mirror of
https://github.com/oxen-io/session-android.git
synced 2025-02-17 15:48:26 +00:00
Merge branch 'fix-notification-spam' into dev
This commit is contained in:
commit
3124a59269
@ -69,8 +69,10 @@ import org.thoughtcrime.securesms.loki.protocol.EphemeralMessage;
|
||||
import org.thoughtcrime.securesms.loki.protocol.LokiSessionResetImplementation;
|
||||
import org.thoughtcrime.securesms.loki.protocol.PushEphemeralMessageSendJob;
|
||||
import org.thoughtcrime.securesms.loki.utilities.Broadcaster;
|
||||
import org.thoughtcrime.securesms.notifications.DefaultMessageNotifier;
|
||||
import org.thoughtcrime.securesms.notifications.MessageNotifier;
|
||||
import org.thoughtcrime.securesms.notifications.NotificationChannels;
|
||||
import org.thoughtcrime.securesms.notifications.OptimizedMessageNotifier;
|
||||
import org.thoughtcrime.securesms.profiles.AvatarHelper;
|
||||
import org.thoughtcrime.securesms.providers.BlobProvider;
|
||||
import org.thoughtcrime.securesms.push.SignalServiceNetworkAccess;
|
||||
@ -148,6 +150,7 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
|
||||
private PersistentLogger persistentLogger;
|
||||
|
||||
// Loki
|
||||
public MessageNotifier messageNotifier = null;
|
||||
public LokiPoller lokiPoller = null;
|
||||
public LokiPublicChatManager lokiPublicChatManager = null;
|
||||
private LokiPublicChatAPI lokiPublicChatAPI = null;
|
||||
@ -173,6 +176,7 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
|
||||
ProcessLifecycleOwner.get().getLifecycle().addObserver(this);
|
||||
// Loki
|
||||
// ========
|
||||
messageNotifier = new OptimizedMessageNotifier(new DefaultMessageNotifier());
|
||||
broadcaster = new Broadcaster(this);
|
||||
LokiAPIDatabase apiDB = DatabaseFactory.getLokiAPIDatabase(this);
|
||||
LokiThreadDatabase threadDB = DatabaseFactory.getLokiThreadDatabase(this);
|
||||
@ -222,7 +226,9 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
|
||||
executePendingContactSync();
|
||||
KeyCachingService.onAppForegrounded(this);
|
||||
// Loki
|
||||
if (lokiPoller != null) { lokiPoller.setCaughtUp(false); }
|
||||
startPollingIfNeeded();
|
||||
lokiPublicChatManager.markAllAsNotCaughtUp();
|
||||
lokiPublicChatManager.startPollersIfNeeded();
|
||||
}
|
||||
|
||||
@ -231,7 +237,7 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
|
||||
isAppVisible = false;
|
||||
Log.i(TAG, "App is no longer visible.");
|
||||
KeyCachingService.onAppBackgrounded(this);
|
||||
MessageNotifier.setVisibleThread(-1);
|
||||
messageNotifier.setVisibleThread(-1);
|
||||
// Loki
|
||||
if (lokiPoller != null) { lokiPoller.stopIfNeeded(); }
|
||||
if (lokiPublicChatManager != null) { lokiPublicChatManager.stopPollers(); }
|
||||
|
@ -298,7 +298,7 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit
|
||||
Context context = ConversationListActivity.this;
|
||||
List<MarkedMessageInfo> messageIds = DatabaseFactory.getThreadDatabase(context).setAllThreadsRead();
|
||||
|
||||
MessageNotifier.updateNotification(context);
|
||||
ApplicationContext.getInstance(context).messageNotifier.updateNotification(context);
|
||||
MarkReadReceiver.process(context, messageIds);
|
||||
|
||||
return null;
|
||||
|
@ -324,8 +324,9 @@ public class ConversationListFragment extends Fragment
|
||||
|
||||
@Override
|
||||
protected Void doInBackground(Void... params) {
|
||||
DatabaseFactory.getThreadDatabase(getActivity()).deleteConversations(selectedConversations);
|
||||
MessageNotifier.updateNotification(getActivity());
|
||||
Context context = getActivity();
|
||||
DatabaseFactory.getThreadDatabase(context).deleteConversations(selectedConversations);
|
||||
ApplicationContext.getInstance(context).messageNotifier.updateNotification(context);
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -542,9 +543,10 @@ public class ConversationListFragment extends Fragment
|
||||
DatabaseFactory.getThreadDatabase(getActivity()).archiveConversation(threadId);
|
||||
|
||||
if (unreadCount > 0) {
|
||||
List<MarkedMessageInfo> messageIds = DatabaseFactory.getThreadDatabase(getActivity()).setRead(threadId, false);
|
||||
MessageNotifier.updateNotification(getActivity());
|
||||
MarkReadReceiver.process(getActivity(), messageIds);
|
||||
Context context = getActivity();
|
||||
List<MarkedMessageInfo> messageIds = DatabaseFactory.getThreadDatabase(context).setRead(threadId, false);
|
||||
ApplicationContext.getInstance(context).messageNotifier.updateNotification(context);
|
||||
MarkReadReceiver.process(context, messageIds);
|
||||
}
|
||||
}
|
||||
|
||||
@ -553,8 +555,9 @@ public class ConversationListFragment extends Fragment
|
||||
DatabaseFactory.getThreadDatabase(getActivity()).unarchiveConversation(threadId);
|
||||
|
||||
if (unreadCount > 0) {
|
||||
DatabaseFactory.getThreadDatabase(getActivity()).incrementUnread(threadId, unreadCount);
|
||||
MessageNotifier.updateNotification(getActivity());
|
||||
Context context = getActivity();
|
||||
DatabaseFactory.getThreadDatabase(context).incrementUnread(threadId, unreadCount);
|
||||
ApplicationContext.getInstance(context).messageNotifier.updateNotification(context);
|
||||
}
|
||||
}
|
||||
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, threadId);
|
||||
|
@ -176,7 +176,7 @@ public class DatabaseUpgradeActivity extends BaseActivity {
|
||||
new AsyncTask<Void, Void, Void>() {
|
||||
@Override
|
||||
protected Void doInBackground(Void... params) {
|
||||
MessageNotifier.updateNotification(context);
|
||||
ApplicationContext.getInstance(context).messageNotifier.updateNotification(context);
|
||||
return null;
|
||||
}
|
||||
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
|
@ -133,13 +133,13 @@ public class MessageDetailsActivity extends PassphraseRequiredActionBarActivity
|
||||
assert getSupportActionBar() != null;
|
||||
getSupportActionBar().setTitle("Message Details");
|
||||
|
||||
MessageNotifier.setVisibleThread(threadId);
|
||||
ApplicationContext.getInstance(this).messageNotifier.setVisibleThread(threadId);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
MessageNotifier.setVisibleThread(-1L);
|
||||
ApplicationContext.getInstance(this).messageNotifier.setVisibleThread(-1L);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -550,7 +550,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
setGroupShareProfileReminder(recipient);
|
||||
calculateCharactersRemaining();
|
||||
|
||||
MessageNotifier.setVisibleThread(threadId);
|
||||
ApplicationContext.getInstance(this).messageNotifier.setVisibleThread(threadId);
|
||||
markThreadAsRead();
|
||||
|
||||
DatabaseFactory.getLokiThreadDatabase(this).setDelegate(this);
|
||||
@ -565,7 +565,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
MessageNotifier.setVisibleThread(-1L);
|
||||
ApplicationContext.getInstance(this).messageNotifier.setVisibleThread(-1L);
|
||||
if (isFinishing()) overridePendingTransition(R.anim.fade_scale_in, R.anim.slide_to_right);
|
||||
inputPanel.onPause();
|
||||
|
||||
@ -2244,7 +2244,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
|
||||
if (refreshFragment) {
|
||||
fragment.reload(recipient, threadId);
|
||||
MessageNotifier.setVisibleThread(threadId);
|
||||
ApplicationContext.getInstance(this).messageNotifier.setVisibleThread(threadId);
|
||||
}
|
||||
|
||||
fragment.scrollToBottom();
|
||||
|
@ -12,6 +12,7 @@ import android.text.TextUtils;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
import org.thoughtcrime.securesms.ApplicationContext;
|
||||
import org.thoughtcrime.securesms.DatabaseUpgradeActivity;
|
||||
import org.thoughtcrime.securesms.crypto.AttachmentSecret;
|
||||
import org.thoughtcrime.securesms.crypto.ClassicDecryptingPartInputStream;
|
||||
@ -423,7 +424,7 @@ public class ClassicOpenHelper extends SQLiteOpenHelper {
|
||||
db.endTransaction();
|
||||
|
||||
// DecryptingQueue.schedulePendingDecrypts(context, masterSecret);
|
||||
MessageNotifier.updateNotification(context);
|
||||
ApplicationContext.getInstance(context).messageNotifier.updateNotification(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -281,7 +281,7 @@ public class GroupMessageProcessor {
|
||||
Optional<InsertResult> insertResult = smsDatabase.insertMessageInbox(groupMessage);
|
||||
|
||||
if (insertResult.isPresent()) {
|
||||
MessageNotifier.updateNotification(context, insertResult.get().getThreadId());
|
||||
ApplicationContext.getInstance(context).messageNotifier.updateNotification(context, insertResult.get().getThreadId());
|
||||
return insertResult.get().getThreadId();
|
||||
} else {
|
||||
return null;
|
||||
|
@ -5,6 +5,7 @@ import android.support.annotation.VisibleForTesting;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
import org.thoughtcrime.securesms.ApplicationContext;
|
||||
import org.thoughtcrime.securesms.attachments.Attachment;
|
||||
import org.thoughtcrime.securesms.attachments.AttachmentId;
|
||||
import org.thoughtcrime.securesms.attachments.DatabaseAttachment;
|
||||
@ -107,7 +108,7 @@ public class AttachmentDownloadJob extends BaseJob implements InjectableType {
|
||||
@Override
|
||||
public void onRun() throws IOException {
|
||||
doWork();
|
||||
MessageNotifier.updateNotification(context, 0);
|
||||
ApplicationContext.getInstance(context).messageNotifier.updateNotification(context, 0);
|
||||
}
|
||||
|
||||
public void doWork() throws IOException {
|
||||
|
@ -10,6 +10,7 @@ import com.google.android.mms.pdu_alt.PduBody;
|
||||
import com.google.android.mms.pdu_alt.PduPart;
|
||||
import com.google.android.mms.pdu_alt.RetrieveConf;
|
||||
|
||||
import org.thoughtcrime.securesms.ApplicationContext;
|
||||
import org.thoughtcrime.securesms.attachments.Attachment;
|
||||
import org.thoughtcrime.securesms.attachments.UriAttachment;
|
||||
import org.thoughtcrime.securesms.database.Address;
|
||||
@ -57,6 +58,7 @@ public class MmsDownloadJob extends BaseJob {
|
||||
private long messageId;
|
||||
private long threadId;
|
||||
private boolean automatic;
|
||||
private MessageNotifier messageNotifier;
|
||||
|
||||
public MmsDownloadJob(long messageId, long threadId, boolean automatic) {
|
||||
this(new Job.Parameters.Builder()
|
||||
@ -75,6 +77,7 @@ public class MmsDownloadJob extends BaseJob {
|
||||
this.messageId = messageId;
|
||||
this.threadId = threadId;
|
||||
this.automatic = automatic;
|
||||
this.messageNotifier = ApplicationContext.getInstance(context).messageNotifier;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -94,7 +97,7 @@ public class MmsDownloadJob extends BaseJob {
|
||||
public void onAdded() {
|
||||
if (automatic && KeyCachingService.isLocked(context)) {
|
||||
DatabaseFactory.getMmsDatabase(context).markIncomingNotificationReceived(threadId);
|
||||
MessageNotifier.updateNotification(context);
|
||||
messageNotifier.updateNotification(context);
|
||||
}
|
||||
}
|
||||
|
||||
@ -177,7 +180,7 @@ public class MmsDownloadJob extends BaseJob {
|
||||
|
||||
if (automatic) {
|
||||
database.markIncomingNotificationReceived(threadId);
|
||||
MessageNotifier.updateNotification(context, threadId);
|
||||
messageNotifier.updateNotification(context, threadId);
|
||||
}
|
||||
}
|
||||
|
||||
@ -252,7 +255,7 @@ public class MmsDownloadJob extends BaseJob {
|
||||
|
||||
if (insertResult.isPresent()) {
|
||||
database.delete(messageId);
|
||||
MessageNotifier.updateNotification(context, insertResult.get().getThreadId());
|
||||
messageNotifier.updateNotification(context, insertResult.get().getThreadId());
|
||||
}
|
||||
}
|
||||
|
||||
@ -264,7 +267,7 @@ public class MmsDownloadJob extends BaseJob {
|
||||
|
||||
if (automatic) {
|
||||
db.markIncomingNotificationReceived(threadId);
|
||||
MessageNotifier.updateNotification(context, threadId);
|
||||
messageNotifier.updateNotification(context, threadId);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -19,6 +19,7 @@ import com.google.android.mms.pdu_alt.SendReq;
|
||||
import com.google.android.mms.smil.SmilHelper;
|
||||
import com.klinker.android.send_message.Utils;
|
||||
|
||||
import org.thoughtcrime.securesms.ApplicationContext;
|
||||
import org.thoughtcrime.securesms.attachments.Attachment;
|
||||
import org.thoughtcrime.securesms.database.Address;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
@ -304,7 +305,7 @@ public class MmsSendJob extends SendJob {
|
||||
Recipient recipient = DatabaseFactory.getThreadDatabase(context).getRecipientForThreadId(threadId);
|
||||
|
||||
if (recipient != null) {
|
||||
MessageNotifier.notifyMessageDeliveryFailed(context, recipient, threadId);
|
||||
ApplicationContext.getInstance(context).messageNotifier.notifyMessageDeliveryFailed(context, recipient, threadId);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -159,6 +159,8 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
||||
private long messageId;
|
||||
private long smsMessageId;
|
||||
|
||||
private MessageNotifier messageNotifier;
|
||||
|
||||
@Inject SignalServiceMessageSender messageSender;
|
||||
private Address author;
|
||||
|
||||
@ -178,6 +180,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
||||
pushMessageId,
|
||||
smsMessageId);
|
||||
setContext(context);
|
||||
this.messageNotifier = ApplicationContext.getInstance(context).messageNotifier;
|
||||
}
|
||||
|
||||
private PushDecryptJob(@NonNull Job.Parameters parameters, long pushMessageId, long smsMessageId) {
|
||||
@ -546,7 +549,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
||||
|
||||
if (threadId != null) {
|
||||
SessionManagementProtocol.handleEndSessionMessageIfNeeded(context, content);
|
||||
MessageNotifier.updateNotification(context, threadId);
|
||||
messageNotifier.updateNotification(context, threadId);
|
||||
}
|
||||
}
|
||||
|
||||
@ -709,10 +712,10 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
||||
|
||||
if (threadId != null) {
|
||||
DatabaseFactory.getThreadDatabase(context).setRead(threadId, true);
|
||||
MessageNotifier.updateNotification(context);
|
||||
messageNotifier.updateNotification(context);
|
||||
}
|
||||
|
||||
MessageNotifier.setLastDesktopActivityTimestamp(message.getTimestamp());
|
||||
messageNotifier.setLastDesktopActivityTimestamp(message.getTimestamp());
|
||||
} catch (MmsException e) {
|
||||
throw new StorageFailedException(e, content.getSender(), content.getSenderDevice());
|
||||
}
|
||||
@ -775,9 +778,9 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
||||
}
|
||||
}
|
||||
|
||||
MessageNotifier.setLastDesktopActivityTimestamp(envelopeTimestamp);
|
||||
MessageNotifier.cancelDelayedNotifications();
|
||||
MessageNotifier.updateNotification(context);
|
||||
messageNotifier.setLastDesktopActivityTimestamp(envelopeTimestamp);
|
||||
messageNotifier.cancelDelayedNotifications();
|
||||
messageNotifier.updateNotification(context);
|
||||
}
|
||||
|
||||
public void handleMediaMessage(@NonNull SignalServiceContent content,
|
||||
@ -843,7 +846,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
||||
}
|
||||
|
||||
if (insertResult.isPresent()) {
|
||||
MessageNotifier.updateNotification(context, insertResult.get().getThreadId());
|
||||
messageNotifier.updateNotification(context, insertResult.get().getThreadId());
|
||||
}
|
||||
|
||||
// Loki - Store message open group server ID if needed
|
||||
@ -1015,7 +1018,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
||||
if (smsMessageId.isPresent()) database.deleteMessage(smsMessageId.get());
|
||||
|
||||
if (threadId != null) {
|
||||
MessageNotifier.updateNotification(context, threadId);
|
||||
messageNotifier.updateNotification(context, threadId);
|
||||
}
|
||||
|
||||
if (insertResult.isPresent()) {
|
||||
@ -1116,7 +1119,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
||||
|
||||
if (insertResult.isPresent()) {
|
||||
smsDatabase.markAsInvalidVersionKeyExchange(insertResult.get().getMessageId());
|
||||
MessageNotifier.updateNotification(context, insertResult.get().getThreadId());
|
||||
messageNotifier.updateNotification(context, insertResult.get().getThreadId());
|
||||
}
|
||||
} else {
|
||||
smsDatabase.markAsInvalidVersionKeyExchange(smsMessageId.get());
|
||||
@ -1133,7 +1136,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
||||
|
||||
if (insertResult.isPresent()) {
|
||||
smsDatabase.markAsDecryptFailed(insertResult.get().getMessageId());
|
||||
MessageNotifier.updateNotification(context, insertResult.get().getThreadId());
|
||||
messageNotifier.updateNotification(context, insertResult.get().getThreadId());
|
||||
}
|
||||
} else {
|
||||
smsDatabase.markAsDecryptFailed(smsMessageId.get());
|
||||
@ -1151,7 +1154,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
||||
|
||||
if (insertResult.isPresent()) {
|
||||
smsDatabase.markAsNoSession(insertResult.get().getMessageId());
|
||||
MessageNotifier.updateNotification(context, insertResult.get().getThreadId());
|
||||
messageNotifier.updateNotification(context, insertResult.get().getThreadId());
|
||||
}
|
||||
} else {
|
||||
smsDatabase.markAsNoSession(smsMessageId.get());
|
||||
@ -1169,7 +1172,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
||||
|
||||
if (insertResult.isPresent()) {
|
||||
smsDatabase.markAsLegacyVersion(insertResult.get().getMessageId());
|
||||
MessageNotifier.updateNotification(context, insertResult.get().getThreadId());
|
||||
messageNotifier.updateNotification(context, insertResult.get().getThreadId());
|
||||
}
|
||||
} else {
|
||||
smsDatabase.markAsLegacyVersion(smsMessageId.get());
|
||||
|
@ -182,7 +182,7 @@ public abstract class PushSendJob extends SendJob {
|
||||
Recipient recipient = DatabaseFactory.getThreadDatabase(context).getRecipientForThreadId(threadId);
|
||||
|
||||
if (threadId != -1 && recipient != null) {
|
||||
MessageNotifier.notifyMessageDeliveryFailed(context, recipient, threadId);
|
||||
ApplicationContext.getInstance(context).messageNotifier.notifyMessageDeliveryFailed(context, recipient, threadId);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -164,7 +164,7 @@ public class PushTextSendJob extends PushSendJob implements InjectableType {
|
||||
warn(TAG, "Couldn't send message due to error: ", e);
|
||||
if (messageId >= 0) {
|
||||
database.markAsPendingInsecureSmsFallback(record.getId());
|
||||
MessageNotifier.notifyMessageDeliveryFailed(context, record.getRecipient(), record.getThreadId());
|
||||
ApplicationContext.getInstance(context).messageNotifier.notifyMessageDeliveryFailed(context, record.getRecipient(), record.getThreadId());
|
||||
}
|
||||
} catch (UntrustedIdentityException e) {
|
||||
warn(TAG, "Couldn't send message due to error: ", e);
|
||||
@ -198,7 +198,7 @@ public class PushTextSendJob extends PushSendJob implements InjectableType {
|
||||
Recipient recipient = DatabaseFactory.getThreadDatabase(context).getRecipientForThreadId(threadId);
|
||||
|
||||
if (threadId != -1 && recipient != null) {
|
||||
MessageNotifier.notifyMessageDeliveryFailed(context, recipient, threadId);
|
||||
ApplicationContext.getInstance(context).messageNotifier.notifyMessageDeliveryFailed(context, recipient, threadId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.telephony.SmsMessage;
|
||||
|
||||
import org.thoughtcrime.securesms.ApplicationContext;
|
||||
import org.thoughtcrime.securesms.jobmanager.Data;
|
||||
import org.thoughtcrime.securesms.jobmanager.Job;
|
||||
import org.thoughtcrime.securesms.jobmanager.impl.SqlCipherMigrationConstraint;
|
||||
@ -79,7 +80,7 @@ public class SmsReceiveJob extends BaseJob {
|
||||
Optional<InsertResult> insertResult = storeMessage(message.get());
|
||||
|
||||
if (insertResult.isPresent()) {
|
||||
MessageNotifier.updateNotification(context, insertResult.get().getThreadId());
|
||||
ApplicationContext.getInstance(context).messageNotifier.updateNotification(context, insertResult.get().getThreadId());
|
||||
}
|
||||
} else if (message.isPresent()) {
|
||||
Log.w(TAG, "*** Received blocked SMS, ignoring...");
|
||||
|
@ -9,6 +9,7 @@ import android.support.annotation.NonNull;
|
||||
import android.telephony.PhoneNumberUtils;
|
||||
import android.telephony.SmsManager;
|
||||
|
||||
import org.thoughtcrime.securesms.ApplicationContext;
|
||||
import org.thoughtcrime.securesms.jobmanager.Data;
|
||||
import org.thoughtcrime.securesms.jobmanager.Job;
|
||||
import org.thoughtcrime.securesms.jobmanager.impl.NetworkOrCellServiceConstraint;
|
||||
@ -88,7 +89,7 @@ public class SmsSendJob extends SendJob {
|
||||
} catch (UndeliverableMessageException ude) {
|
||||
warn(TAG, ude);
|
||||
DatabaseFactory.getSmsDatabase(context).markAsSentFailed(record.getId());
|
||||
MessageNotifier.notifyMessageDeliveryFailed(context, record.getRecipient(), record.getThreadId());
|
||||
ApplicationContext.getInstance(context).messageNotifier.notifyMessageDeliveryFailed(context, record.getRecipient(), record.getThreadId());
|
||||
}
|
||||
}
|
||||
|
||||
@ -106,7 +107,7 @@ public class SmsSendJob extends SendJob {
|
||||
DatabaseFactory.getSmsDatabase(context).markAsSentFailed(messageId);
|
||||
|
||||
if (threadId != -1 && recipient != null) {
|
||||
MessageNotifier.notifyMessageDeliveryFailed(context, recipient, threadId);
|
||||
ApplicationContext.getInstance(context).messageNotifier.notifyMessageDeliveryFailed(context, recipient, threadId);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -108,7 +108,7 @@ public class SmsSentJob extends BaseJob {
|
||||
break;
|
||||
default:
|
||||
database.markAsSentFailed(messageId);
|
||||
MessageNotifier.notifyMessageDeliveryFailed(context, record.getRecipient(), record.getThreadId());
|
||||
ApplicationContext.getInstance(context).messageNotifier.notifyMessageDeliveryFailed(context, record.getRecipient(), record.getThreadId());
|
||||
}
|
||||
} catch (NoSuchMessageException e) {
|
||||
Log.w(TAG, e);
|
||||
|
@ -78,7 +78,7 @@ class HomeActivity : PassphraseRequiredActionBarActivity, ConversationClickListe
|
||||
val threadID = archivedConversations.getLong(archivedConversations.getColumnIndex(ThreadDatabase.ID))
|
||||
AsyncTask.execute {
|
||||
threadDatabase.deleteConversation(threadID)
|
||||
MessageNotifier.updateNotification(this)
|
||||
(applicationContext as ApplicationContext).messageNotifier.updateNotification(this)
|
||||
}
|
||||
}
|
||||
deleteThreadAtCurrentPosition()
|
||||
@ -314,7 +314,7 @@ class HomeActivity : PassphraseRequiredActionBarActivity, ConversationClickListe
|
||||
ApplicationContext.getInstance(activity).lokiPublicChatAPI!!.leave(publicChat.channel, publicChat.server)
|
||||
}
|
||||
threadDatabase.deleteConversation(threadID)
|
||||
MessageNotifier.updateNotification(activity)
|
||||
ApplicationContext.getInstance(activity).messageNotifier.updateNotification(activity)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -20,6 +20,24 @@ class LokiPublicChatManager(private val context: Context) {
|
||||
private val observers = mutableMapOf<Long, ContentObserver>()
|
||||
private var isPolling = false
|
||||
|
||||
public fun areAllCaughtUp():Boolean {
|
||||
var areAllCaughtUp = true
|
||||
refreshChatsAndPollers()
|
||||
for ((threadID, chat) in chats) {
|
||||
val poller = pollers[threadID] ?: LokiPublicChatPoller(context, chat)
|
||||
areAllCaughtUp = areAllCaughtUp && poller.isCaughtUp
|
||||
}
|
||||
return areAllCaughtUp
|
||||
}
|
||||
|
||||
public fun markAllAsNotCaughtUp() {
|
||||
refreshChatsAndPollers()
|
||||
for ((threadID, chat) in chats) {
|
||||
val poller = pollers[threadID] ?: LokiPublicChatPoller(context, chat)
|
||||
poller.isCaughtUp = false
|
||||
}
|
||||
}
|
||||
|
||||
public fun startPollersIfNeeded() {
|
||||
refreshChatsAndPollers()
|
||||
|
||||
|
@ -34,6 +34,7 @@ import java.util.*
|
||||
class LokiPublicChatPoller(private val context: Context, private val group: LokiPublicChat) {
|
||||
private val handler = Handler()
|
||||
private var hasStarted = false
|
||||
public var isCaughtUp = false
|
||||
|
||||
// region Convenience
|
||||
private val userHexEncodedPublicKey = TextSecurePreferences.getLocalNumber(context)
|
||||
@ -249,6 +250,7 @@ class LokiPublicChatPoller(private val context: Context, private val group: Loki
|
||||
processIncomingMessage(message)
|
||||
}
|
||||
}
|
||||
isCaughtUp = true
|
||||
}.fail {
|
||||
Log.d("Loki", "Failed to get messages for group chat with ID: ${group.channel} on server: ${group.server}.")
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ import android.content.Intent;
|
||||
import android.os.AsyncTask;
|
||||
import android.support.v4.app.NotificationManagerCompat;
|
||||
|
||||
import org.thoughtcrime.securesms.ApplicationContext;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.MessagingDatabase.MarkedMessageInfo;
|
||||
import org.whispersystems.libsignal.logging.Log;
|
||||
@ -66,7 +67,7 @@ public class AndroidAutoHeardReceiver extends BroadcastReceiver {
|
||||
messageIdsCollection.addAll(messageIds);
|
||||
}
|
||||
|
||||
MessageNotifier.updateNotification(context);
|
||||
ApplicationContext.getInstance(context).messageNotifier.updateNotification(context);
|
||||
MarkReadReceiver.process(context, messageIdsCollection);
|
||||
|
||||
return null;
|
||||
|
@ -25,6 +25,7 @@ import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.RemoteInput;
|
||||
|
||||
import org.thoughtcrime.securesms.ApplicationContext;
|
||||
import org.thoughtcrime.securesms.database.Address;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.MessagingDatabase.MarkedMessageInfo;
|
||||
@ -86,7 +87,7 @@ public class AndroidAutoReplyReceiver extends BroadcastReceiver {
|
||||
|
||||
List<MarkedMessageInfo> messageIds = DatabaseFactory.getThreadDatabase(context).setRead(replyThreadId, true);
|
||||
|
||||
MessageNotifier.updateNotification(context);
|
||||
ApplicationContext.getInstance(context).messageNotifier.updateNotification(context);
|
||||
MarkReadReceiver.process(context, messageIds);
|
||||
|
||||
return null;
|
||||
|
@ -0,0 +1,621 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Whisper Systems
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.thoughtcrime.securesms.notifications;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.AlarmManager;
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationManager;
|
||||
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;
|
||||
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.v4.app.NotificationCompat;
|
||||
import android.support.v4.app.NotificationManagerCompat;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import org.thoughtcrime.securesms.ApplicationContext;
|
||||
import org.thoughtcrime.securesms.contactshare.Contact;
|
||||
import org.thoughtcrime.securesms.contactshare.ContactUtil;
|
||||
import org.thoughtcrime.securesms.conversation.ConversationActivity;
|
||||
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.logging.Log;
|
||||
import org.thoughtcrime.securesms.loki.protocol.SessionMetaProtocol;
|
||||
import org.thoughtcrime.securesms.mms.SlideDeck;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.service.IncomingMessageObserver;
|
||||
import org.thoughtcrime.securesms.service.KeyCachingService;
|
||||
import org.thoughtcrime.securesms.util.ServiceUtil;
|
||||
import org.thoughtcrime.securesms.util.SpanUtil;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.thoughtcrime.securesms.webrtc.CallNotificationBuilder;
|
||||
import org.whispersystems.signalservice.internal.util.Util;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import me.leolin.shortcutbadger.ShortcutBadger;
|
||||
import network.loki.messenger.R;
|
||||
|
||||
/**
|
||||
* Handles posting system notifications for new messages.
|
||||
*
|
||||
*
|
||||
* @author Moxie Marlinspike
|
||||
*/
|
||||
|
||||
public class DefaultMessageNotifier implements MessageNotifier {
|
||||
|
||||
private static final String TAG = DefaultMessageNotifier.class.getSimpleName();
|
||||
|
||||
public static final String EXTRA_REMOTE_REPLY = "extra_remote_reply";
|
||||
|
||||
private static final int SUMMARY_NOTIFICATION_ID = 1338;
|
||||
private static final int PENDING_MESSAGES_ID = 1111;
|
||||
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);
|
||||
|
||||
private volatile static long visibleThread = -1;
|
||||
private volatile static long lastDesktopActivityTimestamp = -1;
|
||||
private volatile static long lastAudibleNotification = -1;
|
||||
private static final CancelableExecutor executor = new CancelableExecutor();
|
||||
|
||||
@Override
|
||||
public void setVisibleThread(long threadId) {
|
||||
visibleThread = threadId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLastDesktopActivityTimestamp(long timestamp) {
|
||||
lastDesktopActivityTimestamp = timestamp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyMessageDeliveryFailed(Context context, Recipient recipient, long threadId) {
|
||||
if (visibleThread == threadId) {
|
||||
sendInThreadNotification(context, recipient);
|
||||
} else {
|
||||
Intent intent = new Intent(context, ConversationActivity.class);
|
||||
intent.putExtra(ConversationActivity.ADDRESS_EXTRA, recipient.getAddress());
|
||||
intent.putExtra(ConversationActivity.THREAD_ID_EXTRA, threadId);
|
||||
intent.setData((Uri.parse("custom://" + System.currentTimeMillis())));
|
||||
|
||||
FailedNotificationBuilder builder = new FailedNotificationBuilder(context, TextSecurePreferences.getNotificationPrivacy(context), intent);
|
||||
((NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE))
|
||||
.notify((int)threadId, builder.build());
|
||||
}
|
||||
}
|
||||
|
||||
public void notifyMessagesPending(Context context) {
|
||||
if (!TextSecurePreferences.isNotificationsEnabled(context)) {
|
||||
return;
|
||||
}
|
||||
|
||||
PendingMessageNotificationBuilder builder = new PendingMessageNotificationBuilder(context, TextSecurePreferences.getNotificationPrivacy(context));
|
||||
ServiceUtil.getNotificationManager(context).notify(PENDING_MESSAGES_ID, builder.build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancelDelayedNotifications() {
|
||||
executor.cancel();
|
||||
}
|
||||
|
||||
private void cancelActiveNotifications(@NonNull Context context) {
|
||||
NotificationManager notifications = ServiceUtil.getNotificationManager(context);
|
||||
notifications.cancel(SUMMARY_NOTIFICATION_ID);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= 23) {
|
||||
try {
|
||||
StatusBarNotification[] activeNotifications = notifications.getActiveNotifications();
|
||||
|
||||
for (StatusBarNotification activeNotification : activeNotifications) {
|
||||
if (activeNotification.getId() != CallNotificationBuilder.WEBRTC_NOTIFICATION) {
|
||||
notifications.cancel(activeNotification.getId());
|
||||
}
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
// XXX Appears to be a ROM bug, see #6043
|
||||
Log.w(TAG, e);
|
||||
notifications.cancelAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void cancelOrphanedNotifications(@NonNull Context context, NotificationState notificationState) {
|
||||
if (Build.VERSION.SDK_INT >= 23) {
|
||||
try {
|
||||
NotificationManager notifications = ServiceUtil.getNotificationManager(context);
|
||||
StatusBarNotification[] activeNotifications = notifications.getActiveNotifications();
|
||||
|
||||
for (StatusBarNotification notification : activeNotifications) {
|
||||
boolean validNotification = false;
|
||||
|
||||
if (notification.getId() != SUMMARY_NOTIFICATION_ID &&
|
||||
notification.getId() != CallNotificationBuilder.WEBRTC_NOTIFICATION &&
|
||||
notification.getId() != KeyCachingService.SERVICE_RUNNING_ID &&
|
||||
notification.getId() != IncomingMessageObserver.FOREGROUND_ID &&
|
||||
notification.getId() != PENDING_MESSAGES_ID)
|
||||
{
|
||||
for (NotificationItem item : notificationState.getNotifications()) {
|
||||
if (notification.getId() == (SUMMARY_NOTIFICATION_ID + item.getThreadId())) {
|
||||
validNotification = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!validNotification) {
|
||||
notifications.cancel(notification.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
// XXX Android ROM Bug, see #6043
|
||||
Log.w(TAG, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateNotification(@NonNull Context context) {
|
||||
if (!TextSecurePreferences.isNotificationsEnabled(context)) {
|
||||
return;
|
||||
}
|
||||
|
||||
updateNotification(context, false, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateNotification(@NonNull Context context, long threadId)
|
||||
{
|
||||
if (System.currentTimeMillis() - lastDesktopActivityTimestamp < DESKTOP_ACTIVITY_PERIOD) {
|
||||
Log.i(TAG, "Scheduling delayed notification...");
|
||||
executor.execute(new DelayedNotification(context, threadId));
|
||||
} else {
|
||||
updateNotification(context, threadId, true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateNotification(@NonNull Context context, long threadId, boolean signal)
|
||||
{
|
||||
boolean isVisible = visibleThread == threadId;
|
||||
|
||||
ThreadDatabase threads = DatabaseFactory.getThreadDatabase(context);
|
||||
Recipient recipients = DatabaseFactory.getThreadDatabase(context)
|
||||
.getRecipientForThreadId(threadId);
|
||||
|
||||
if (isVisible) {
|
||||
List<MarkedMessageInfo> messageIds = threads.setRead(threadId, false);
|
||||
MarkReadReceiver.process(context, messageIds);
|
||||
}
|
||||
|
||||
if (!TextSecurePreferences.isNotificationsEnabled(context) ||
|
||||
(recipients != null && recipients.isMuted()))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (isVisible) {
|
||||
sendInThreadNotification(context, threads.getRecipientForThreadId(threadId));
|
||||
} else {
|
||||
updateNotification(context, signal, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateNotification(@NonNull Context context, boolean signal, int reminderCount)
|
||||
{
|
||||
Cursor telcoCursor = null;
|
||||
Cursor pushCursor = null;
|
||||
|
||||
try {
|
||||
telcoCursor = DatabaseFactory.getMmsSmsDatabase(context).getUnread();
|
||||
pushCursor = DatabaseFactory.getPushDatabase(context).getPending();
|
||||
|
||||
if ((telcoCursor == null || telcoCursor.isAfterLast()) &&
|
||||
(pushCursor == null || pushCursor.isAfterLast()))
|
||||
{
|
||||
cancelActiveNotifications(context);
|
||||
updateBadge(context, 0);
|
||||
clearReminder(context);
|
||||
return;
|
||||
}
|
||||
|
||||
NotificationState notificationState = constructNotificationState(context, telcoCursor);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
sendMultipleThreadNotification(context, notificationState, signal);
|
||||
} else {
|
||||
sendSingleThreadNotification(context, notificationState, signal, false);
|
||||
}
|
||||
|
||||
cancelOrphanedNotifications(context, notificationState);
|
||||
updateBadge(context, notificationState.getMessageCount());
|
||||
|
||||
if (signal) {
|
||||
scheduleReminder(context, reminderCount);
|
||||
}
|
||||
} finally {
|
||||
if (telcoCursor != null) telcoCursor.close();
|
||||
if (pushCursor != null) pushCursor.close();
|
||||
}
|
||||
}
|
||||
|
||||
private void sendSingleThreadNotification(@NonNull Context context,
|
||||
@NonNull NotificationState notificationState,
|
||||
boolean signal, boolean bundled)
|
||||
{
|
||||
Log.i(TAG, "sendSingleThreadNotification() signal: " + signal + " bundled: " + bundled);
|
||||
|
||||
if (notificationState.getNotifications().isEmpty()) {
|
||||
if (!bundled) cancelActiveNotifications(context);
|
||||
Log.i(TAG, "Empty notification state. Skipping.");
|
||||
return;
|
||||
}
|
||||
|
||||
SingleRecipientNotificationBuilder builder = new SingleRecipientNotificationBuilder(context, TextSecurePreferences.getNotificationPrivacy(context));
|
||||
List<NotificationItem> notifications = notificationState.getNotifications();
|
||||
Recipient recipient = notifications.get(0).getRecipient();
|
||||
int notificationId = (int) (SUMMARY_NOTIFICATION_ID + (bundled ? notifications.get(0).getThreadId() : 0));
|
||||
|
||||
|
||||
builder.setThread(notifications.get(0).getRecipient());
|
||||
builder.setMessageCount(notificationState.getMessageCount());
|
||||
builder.setPrimaryMessageBody(recipient, notifications.get(0).getIndividualRecipient(),
|
||||
notifications.get(0).getText(), notifications.get(0).getSlideDeck());
|
||||
builder.setContentIntent(notifications.get(0).getPendingIntent(context));
|
||||
builder.setDeleteIntent(notificationState.getDeleteIntent(context));
|
||||
builder.setOnlyAlertOnce(!signal);
|
||||
builder.setGroupAlertBehavior(NotificationCompat.GROUP_ALERT_SUMMARY);
|
||||
builder.setAutoCancel(true);
|
||||
|
||||
long timestamp = notifications.get(0).getTimestamp();
|
||||
if (timestamp != 0) builder.setWhen(timestamp);
|
||||
|
||||
long threadID = notifications.get(0).getThreadId();
|
||||
|
||||
ReplyMethod replyMethod = ReplyMethod.forRecipient(context, recipient);
|
||||
|
||||
boolean canReply = SessionMetaProtocol.canUserReplyToNotification(recipient, context);
|
||||
|
||||
PendingIntent quickReplyIntent = canReply ? notificationState.getQuickReplyIntent(context, recipient) : null;
|
||||
PendingIntent remoteReplyIntent = canReply ? notificationState.getRemoteReplyIntent(context, recipient, replyMethod) : null;
|
||||
|
||||
builder.addActions(notificationState.getMarkAsReadIntent(context, notificationId),
|
||||
quickReplyIntent,
|
||||
remoteReplyIntent,
|
||||
replyMethod);
|
||||
|
||||
if (canReply) {
|
||||
builder.addAndroidAutoAction(notificationState.getAndroidAutoReplyIntent(context, recipient),
|
||||
notificationState.getAndroidAutoHeardIntent(context, notificationId),
|
||||
notifications.get(0).getTimestamp());
|
||||
}
|
||||
|
||||
ListIterator<NotificationItem> iterator = notifications.listIterator(notifications.size());
|
||||
|
||||
while(iterator.hasPrevious()) {
|
||||
NotificationItem item = iterator.previous();
|
||||
builder.addMessageBody(item.getRecipient(), item.getIndividualRecipient(), item.getText());
|
||||
}
|
||||
|
||||
if (signal) {
|
||||
builder.setAlarms(notificationState.getRingtone(context), notificationState.getVibrate());
|
||||
builder.setTicker(notifications.get(0).getIndividualRecipient(),
|
||||
notifications.get(0).getText());
|
||||
}
|
||||
|
||||
if (bundled) {
|
||||
builder.setGroup(NOTIFICATION_GROUP);
|
||||
builder.setGroupAlertBehavior(NotificationCompat.GROUP_ALERT_SUMMARY);
|
||||
}
|
||||
|
||||
Notification notification = builder.build();
|
||||
NotificationManagerCompat.from(context).notify(notificationId, notification);
|
||||
Log.i(TAG, "Posted notification. " + notification.toString());
|
||||
}
|
||||
|
||||
private void sendMultipleThreadNotification(@NonNull Context context,
|
||||
@NonNull NotificationState notificationState,
|
||||
boolean signal)
|
||||
{
|
||||
Log.i(TAG, "sendMultiThreadNotification() signal: " + signal);
|
||||
|
||||
MultipleRecipientNotificationBuilder builder = new MultipleRecipientNotificationBuilder(context, TextSecurePreferences.getNotificationPrivacy(context));
|
||||
List<NotificationItem> notifications = notificationState.getNotifications();
|
||||
|
||||
builder.setMessageCount(notificationState.getMessageCount(), notificationState.getThreadCount());
|
||||
builder.setMostRecentSender(notifications.get(0).getIndividualRecipient(), notifications.get(0).getRecipient());
|
||||
builder.setGroup(NOTIFICATION_GROUP);
|
||||
builder.setDeleteIntent(notificationState.getDeleteIntent(context));
|
||||
builder.setOnlyAlertOnce(!signal);
|
||||
builder.setGroupAlertBehavior(NotificationCompat.GROUP_ALERT_SUMMARY);
|
||||
builder.setAutoCancel(true);
|
||||
|
||||
long timestamp = notifications.get(0).getTimestamp();
|
||||
if (timestamp != 0) builder.setWhen(timestamp);
|
||||
|
||||
builder.addActions(notificationState.getMarkAsReadIntent(context, SUMMARY_NOTIFICATION_ID));
|
||||
|
||||
ListIterator<NotificationItem> iterator = notifications.listIterator(notifications.size());
|
||||
|
||||
while(iterator.hasPrevious()) {
|
||||
NotificationItem item = iterator.previous();
|
||||
builder.addMessageBody(item.getIndividualRecipient(), item.getRecipient(), item.getText());
|
||||
}
|
||||
|
||||
if (signal) {
|
||||
builder.setAlarms(notificationState.getRingtone(context), notificationState.getVibrate());
|
||||
builder.setTicker(notifications.get(0).getIndividualRecipient(),
|
||||
notifications.get(0).getText());
|
||||
}
|
||||
|
||||
Notification notification = builder.build();
|
||||
NotificationManagerCompat.from(context).notify(SUMMARY_NOTIFICATION_ID, builder.build());
|
||||
Log.i(TAG, "Posted notification. " + notification.toString());
|
||||
}
|
||||
|
||||
private void sendInThreadNotification(Context context, Recipient recipient) {
|
||||
if (!TextSecurePreferences.isInThreadNotifications(context) ||
|
||||
ServiceUtil.getAudioManager(context).getRingerMode() != AudioManager.RINGER_MODE_NORMAL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Uri uri = null;
|
||||
if (recipient != null) {
|
||||
uri = NotificationChannels.supported() ? NotificationChannels.getMessageRingtone(context, recipient) : recipient.getMessageRingtone();
|
||||
}
|
||||
|
||||
if (uri == null) {
|
||||
uri = NotificationChannels.supported() ? NotificationChannels.getMessageRingtone(context) : TextSecurePreferences.getNotificationRingtone(context);
|
||||
}
|
||||
|
||||
if (uri.toString().isEmpty()) {
|
||||
Log.d(TAG, "ringtone uri is empty");
|
||||
return;
|
||||
}
|
||||
|
||||
Ringtone ringtone = RingtoneManager.getRingtone(context, uri);
|
||||
|
||||
if (ringtone == null) {
|
||||
Log.w(TAG, "ringtone is null");
|
||||
return;
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT >= 21) {
|
||||
ringtone.setAudioAttributes(new AudioAttributes.Builder().setContentType(AudioAttributes.CONTENT_TYPE_UNKNOWN)
|
||||
.setUsage(AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_INSTANT)
|
||||
.build());
|
||||
} else {
|
||||
ringtone.setStreamType(AudioManager.STREAM_NOTIFICATION);
|
||||
}
|
||||
|
||||
ringtone.play();
|
||||
}
|
||||
|
||||
private NotificationState constructNotificationState(@NonNull Context context,
|
||||
@NonNull Cursor cursor)
|
||||
{
|
||||
NotificationState notificationState = new NotificationState();
|
||||
MmsSmsDatabase.Reader reader = DatabaseFactory.getMmsSmsDatabase(context).readerFor(cursor);
|
||||
|
||||
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();
|
||||
CharSequence body = record.getDisplayBody(context);
|
||||
Recipient threadRecipients = null;
|
||||
SlideDeck slideDeck = null;
|
||||
long timestamp = record.getTimestamp();
|
||||
|
||||
|
||||
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() && ((MmsMessageRecord) record).getSlideDeck().getStickerSlide() != null) {
|
||||
body = SpanUtil.italic(context.getString(R.string.MessageNotifier_sticker));
|
||||
slideDeck = ((MmsMessageRecord) record).getSlideDeck();
|
||||
} else if (record.isMms() && TextUtils.isEmpty(body) && !((MmsMessageRecord) record).getSlideDeck().getSlides().isEmpty()) {
|
||||
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()) {
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
reader.close();
|
||||
return notificationState;
|
||||
}
|
||||
|
||||
private void updateBadge(Context context, int count) {
|
||||
try {
|
||||
if (count == 0) ShortcutBadger.removeCount(context);
|
||||
else ShortcutBadger.applyCount(context, count);
|
||||
} catch (Throwable t) {
|
||||
// NOTE :: I don't totally trust this thing, so I'm catching
|
||||
// everything.
|
||||
Log.w("MessageNotifier", t);
|
||||
}
|
||||
}
|
||||
|
||||
private void scheduleReminder(Context context, int count) {
|
||||
if (count >= TextSecurePreferences.getRepeatAlertsCount(context)) {
|
||||
return;
|
||||
}
|
||||
|
||||
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
|
||||
Intent alarmIntent = new Intent(ReminderReceiver.REMINDER_ACTION);
|
||||
alarmIntent.putExtra("reminder_count", count);
|
||||
|
||||
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, alarmIntent, PendingIntent.FLAG_CANCEL_CURRENT);
|
||||
long timeout = TimeUnit.MINUTES.toMillis(2);
|
||||
|
||||
alarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + timeout, pendingIntent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearReminder(Context context) {
|
||||
Intent alarmIntent = new Intent(ReminderReceiver.REMINDER_ACTION);
|
||||
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, alarmIntent, PendingIntent.FLAG_CANCEL_CURRENT);
|
||||
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
|
||||
alarmManager.cancel(pendingIntent);
|
||||
}
|
||||
|
||||
public static class ReminderReceiver extends BroadcastReceiver {
|
||||
|
||||
public static final String REMINDER_ACTION = "network.loki.securesms.MessageNotifier.REMINDER_ACTION";
|
||||
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
@Override
|
||||
public void onReceive(final Context context, final Intent intent) {
|
||||
new AsyncTask<Void, Void, Void>() {
|
||||
@Override
|
||||
protected Void doInBackground(Void... params) {
|
||||
int reminderCount = intent.getIntExtra("reminder_count", 0);
|
||||
ApplicationContext.getInstance(context).messageNotifier.updateNotification(context, true, reminderCount + 1);
|
||||
|
||||
return null;
|
||||
}
|
||||
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
}
|
||||
}
|
||||
|
||||
private static class DelayedNotification implements Runnable {
|
||||
|
||||
private static final long DELAY = TimeUnit.SECONDS.toMillis(5);
|
||||
|
||||
private final AtomicBoolean canceled = new AtomicBoolean(false);
|
||||
|
||||
private final Context context;
|
||||
private final long threadId;
|
||||
private final long delayUntil;
|
||||
|
||||
private DelayedNotification(Context context, long threadId) {
|
||||
this.context = context;
|
||||
this.threadId = threadId;
|
||||
this.delayUntil = System.currentTimeMillis() + DELAY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
long delayMillis = delayUntil - System.currentTimeMillis();
|
||||
Log.i(TAG, "Waiting to notify: " + delayMillis);
|
||||
|
||||
if (delayMillis > 0) {
|
||||
Util.sleep(delayMillis);
|
||||
}
|
||||
|
||||
if (!canceled.get()) {
|
||||
Log.i(TAG, "Not canceled, notifying...");
|
||||
ApplicationContext.getInstance(context).messageNotifier.updateNotification(context, threadId, true);
|
||||
ApplicationContext.getInstance(context).messageNotifier.cancelDelayedNotifications();
|
||||
} else {
|
||||
Log.w(TAG, "Canceled, not notifying...");
|
||||
}
|
||||
}
|
||||
|
||||
public void cancel() {
|
||||
canceled.set(true);
|
||||
}
|
||||
}
|
||||
|
||||
private static class CancelableExecutor {
|
||||
|
||||
private final Executor executor = Executors.newSingleThreadExecutor();
|
||||
private final Set<DelayedNotification> tasks = new HashSet<>();
|
||||
|
||||
public void execute(final DelayedNotification runnable) {
|
||||
synchronized (tasks) {
|
||||
tasks.add(runnable);
|
||||
}
|
||||
|
||||
Runnable wrapper = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
runnable.run();
|
||||
|
||||
synchronized (tasks) {
|
||||
tasks.remove(runnable);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
executor.execute(wrapper);
|
||||
}
|
||||
|
||||
public void cancel() {
|
||||
synchronized (tasks) {
|
||||
for (DelayedNotification task : tasks) {
|
||||
task.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -6,6 +6,7 @@ import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.AsyncTask;
|
||||
|
||||
import org.thoughtcrime.securesms.ApplicationContext;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
|
||||
public class DeleteNotificationReceiver extends BroadcastReceiver {
|
||||
@ -18,7 +19,7 @@ public class DeleteNotificationReceiver extends BroadcastReceiver {
|
||||
@Override
|
||||
public void onReceive(final Context context, Intent intent) {
|
||||
if (DELETE_NOTIFICATION_ACTION.equals(intent.getAction())) {
|
||||
MessageNotifier.clearReminder(context);
|
||||
ApplicationContext.getInstance(context).messageNotifier.clearReminder(context);
|
||||
|
||||
final long[] ids = intent.getLongArrayExtra(EXTRA_IDS);
|
||||
final boolean[] mms = intent.getBooleanArrayExtra(EXTRA_MMS);
|
||||
|
@ -61,7 +61,7 @@ public class MarkReadReceiver extends BroadcastReceiver {
|
||||
|
||||
process(context, messageIdsCollection);
|
||||
|
||||
MessageNotifier.updateNotification(context);
|
||||
ApplicationContext.getInstance(context).messageNotifier.updateNotification(context);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
@ -1,615 +1,19 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Whisper Systems
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.thoughtcrime.securesms.notifications;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.AlarmManager;
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationManager;
|
||||
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;
|
||||
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.v4.app.NotificationCompat;
|
||||
import android.support.v4.app.NotificationManagerCompat;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import org.thoughtcrime.securesms.contactshare.Contact;
|
||||
import org.thoughtcrime.securesms.contactshare.ContactUtil;
|
||||
import org.thoughtcrime.securesms.conversation.ConversationActivity;
|
||||
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.logging.Log;
|
||||
import org.thoughtcrime.securesms.loki.protocol.SessionMetaProtocol;
|
||||
import org.thoughtcrime.securesms.mms.SlideDeck;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.service.IncomingMessageObserver;
|
||||
import org.thoughtcrime.securesms.service.KeyCachingService;
|
||||
import org.thoughtcrime.securesms.util.ServiceUtil;
|
||||
import org.thoughtcrime.securesms.util.SpanUtil;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.thoughtcrime.securesms.webrtc.CallNotificationBuilder;
|
||||
import org.whispersystems.signalservice.internal.util.Util;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import me.leolin.shortcutbadger.ShortcutBadger;
|
||||
import network.loki.messenger.R;
|
||||
|
||||
/**
|
||||
* Handles posting system notifications for new messages.
|
||||
*
|
||||
*
|
||||
* @author Moxie Marlinspike
|
||||
*/
|
||||
|
||||
public class MessageNotifier {
|
||||
|
||||
private static final String TAG = MessageNotifier.class.getSimpleName();
|
||||
|
||||
public static final String EXTRA_REMOTE_REPLY = "extra_remote_reply";
|
||||
|
||||
private static final int SUMMARY_NOTIFICATION_ID = 1338;
|
||||
private static final int PENDING_MESSAGES_ID = 1111;
|
||||
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);
|
||||
|
||||
private volatile static long visibleThread = -1;
|
||||
private volatile static long lastDesktopActivityTimestamp = -1;
|
||||
private volatile static long lastAudibleNotification = -1;
|
||||
private static final CancelableExecutor executor = new CancelableExecutor();
|
||||
|
||||
public static void setVisibleThread(long threadId) {
|
||||
visibleThread = threadId;
|
||||
}
|
||||
|
||||
public static void setLastDesktopActivityTimestamp(long timestamp) {
|
||||
lastDesktopActivityTimestamp = timestamp;
|
||||
}
|
||||
|
||||
public static void notifyMessageDeliveryFailed(Context context, Recipient recipient, long threadId) {
|
||||
if (visibleThread == threadId) {
|
||||
sendInThreadNotification(context, recipient);
|
||||
} else {
|
||||
Intent intent = new Intent(context, ConversationActivity.class);
|
||||
intent.putExtra(ConversationActivity.ADDRESS_EXTRA, recipient.getAddress());
|
||||
intent.putExtra(ConversationActivity.THREAD_ID_EXTRA, threadId);
|
||||
intent.setData((Uri.parse("custom://" + System.currentTimeMillis())));
|
||||
|
||||
FailedNotificationBuilder builder = new FailedNotificationBuilder(context, TextSecurePreferences.getNotificationPrivacy(context), intent);
|
||||
((NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE))
|
||||
.notify((int)threadId, builder.build());
|
||||
}
|
||||
}
|
||||
|
||||
public static void notifyMessagesPending(Context context) {
|
||||
if (!TextSecurePreferences.isNotificationsEnabled(context)) {
|
||||
return;
|
||||
}
|
||||
|
||||
PendingMessageNotificationBuilder builder = new PendingMessageNotificationBuilder(context, TextSecurePreferences.getNotificationPrivacy(context));
|
||||
ServiceUtil.getNotificationManager(context).notify(PENDING_MESSAGES_ID, builder.build());
|
||||
}
|
||||
|
||||
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) {
|
||||
try {
|
||||
StatusBarNotification[] activeNotifications = notifications.getActiveNotifications();
|
||||
|
||||
for (StatusBarNotification activeNotification : activeNotifications) {
|
||||
if (activeNotification.getId() != CallNotificationBuilder.WEBRTC_NOTIFICATION) {
|
||||
notifications.cancel(activeNotification.getId());
|
||||
}
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
// XXX Appears to be a ROM bug, see #6043
|
||||
Log.w(TAG, e);
|
||||
notifications.cancelAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void cancelOrphanedNotifications(@NonNull Context context, NotificationState notificationState) {
|
||||
if (Build.VERSION.SDK_INT >= 23) {
|
||||
try {
|
||||
NotificationManager notifications = ServiceUtil.getNotificationManager(context);
|
||||
StatusBarNotification[] activeNotifications = notifications.getActiveNotifications();
|
||||
|
||||
for (StatusBarNotification notification : activeNotifications) {
|
||||
boolean validNotification = false;
|
||||
|
||||
if (notification.getId() != SUMMARY_NOTIFICATION_ID &&
|
||||
notification.getId() != CallNotificationBuilder.WEBRTC_NOTIFICATION &&
|
||||
notification.getId() != KeyCachingService.SERVICE_RUNNING_ID &&
|
||||
notification.getId() != IncomingMessageObserver.FOREGROUND_ID &&
|
||||
notification.getId() != PENDING_MESSAGES_ID)
|
||||
{
|
||||
for (NotificationItem item : notificationState.getNotifications()) {
|
||||
if (notification.getId() == (SUMMARY_NOTIFICATION_ID + item.getThreadId())) {
|
||||
validNotification = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!validNotification) {
|
||||
notifications.cancel(notification.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
// XXX Android ROM Bug, see #6043
|
||||
Log.w(TAG, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void updateNotification(@NonNull Context context) {
|
||||
if (!TextSecurePreferences.isNotificationsEnabled(context)) {
|
||||
return;
|
||||
}
|
||||
|
||||
updateNotification(context, false, 0);
|
||||
}
|
||||
|
||||
public static void updateNotification(@NonNull Context context, long threadId)
|
||||
{
|
||||
if (System.currentTimeMillis() - lastDesktopActivityTimestamp < DESKTOP_ACTIVITY_PERIOD) {
|
||||
Log.i(TAG, "Scheduling delayed notification...");
|
||||
executor.execute(new DelayedNotification(context, threadId));
|
||||
} else {
|
||||
updateNotification(context, threadId, true);
|
||||
}
|
||||
}
|
||||
|
||||
public static void updateNotification(@NonNull Context context,
|
||||
long threadId,
|
||||
boolean signal)
|
||||
{
|
||||
boolean isVisible = visibleThread == threadId;
|
||||
|
||||
ThreadDatabase threads = DatabaseFactory.getThreadDatabase(context);
|
||||
Recipient recipients = DatabaseFactory.getThreadDatabase(context)
|
||||
.getRecipientForThreadId(threadId);
|
||||
|
||||
if (isVisible) {
|
||||
List<MarkedMessageInfo> messageIds = threads.setRead(threadId, false);
|
||||
MarkReadReceiver.process(context, messageIds);
|
||||
}
|
||||
|
||||
if (!TextSecurePreferences.isNotificationsEnabled(context) ||
|
||||
(recipients != null && recipients.isMuted()))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (isVisible) {
|
||||
sendInThreadNotification(context, threads.getRecipientForThreadId(threadId));
|
||||
} else {
|
||||
updateNotification(context, signal, 0);
|
||||
}
|
||||
}
|
||||
|
||||
private static void updateNotification(@NonNull Context context,
|
||||
boolean signal,
|
||||
int reminderCount)
|
||||
{
|
||||
Cursor telcoCursor = null;
|
||||
Cursor pushCursor = null;
|
||||
|
||||
try {
|
||||
telcoCursor = DatabaseFactory.getMmsSmsDatabase(context).getUnread();
|
||||
pushCursor = DatabaseFactory.getPushDatabase(context).getPending();
|
||||
|
||||
if ((telcoCursor == null || telcoCursor.isAfterLast()) &&
|
||||
(pushCursor == null || pushCursor.isAfterLast()))
|
||||
{
|
||||
cancelActiveNotifications(context);
|
||||
updateBadge(context, 0);
|
||||
clearReminder(context);
|
||||
return;
|
||||
}
|
||||
|
||||
NotificationState notificationState = constructNotificationState(context, telcoCursor);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
sendMultipleThreadNotification(context, notificationState, signal);
|
||||
} else {
|
||||
sendSingleThreadNotification(context, notificationState, signal, false);
|
||||
}
|
||||
|
||||
cancelOrphanedNotifications(context, notificationState);
|
||||
updateBadge(context, notificationState.getMessageCount());
|
||||
|
||||
if (signal) {
|
||||
scheduleReminder(context, reminderCount);
|
||||
}
|
||||
} finally {
|
||||
if (telcoCursor != null) telcoCursor.close();
|
||||
if (pushCursor != null) pushCursor.close();
|
||||
}
|
||||
}
|
||||
|
||||
private static void sendSingleThreadNotification(@NonNull Context context,
|
||||
@NonNull NotificationState notificationState,
|
||||
boolean signal, boolean bundled)
|
||||
{
|
||||
Log.i(TAG, "sendSingleThreadNotification() signal: " + signal + " bundled: " + bundled);
|
||||
|
||||
if (notificationState.getNotifications().isEmpty()) {
|
||||
if (!bundled) cancelActiveNotifications(context);
|
||||
Log.i(TAG, "Empty notification state. Skipping.");
|
||||
return;
|
||||
}
|
||||
|
||||
SingleRecipientNotificationBuilder builder = new SingleRecipientNotificationBuilder(context, TextSecurePreferences.getNotificationPrivacy(context));
|
||||
List<NotificationItem> notifications = notificationState.getNotifications();
|
||||
Recipient recipient = notifications.get(0).getRecipient();
|
||||
int notificationId = (int) (SUMMARY_NOTIFICATION_ID + (bundled ? notifications.get(0).getThreadId() : 0));
|
||||
|
||||
|
||||
builder.setThread(notifications.get(0).getRecipient());
|
||||
builder.setMessageCount(notificationState.getMessageCount());
|
||||
builder.setPrimaryMessageBody(recipient, notifications.get(0).getIndividualRecipient(),
|
||||
notifications.get(0).getText(), notifications.get(0).getSlideDeck());
|
||||
builder.setContentIntent(notifications.get(0).getPendingIntent(context));
|
||||
builder.setDeleteIntent(notificationState.getDeleteIntent(context));
|
||||
builder.setOnlyAlertOnce(!signal);
|
||||
builder.setGroupAlertBehavior(NotificationCompat.GROUP_ALERT_SUMMARY);
|
||||
builder.setAutoCancel(true);
|
||||
|
||||
long timestamp = notifications.get(0).getTimestamp();
|
||||
if (timestamp != 0) builder.setWhen(timestamp);
|
||||
|
||||
long threadID = notifications.get(0).getThreadId();
|
||||
|
||||
ReplyMethod replyMethod = ReplyMethod.forRecipient(context, recipient);
|
||||
|
||||
boolean canReply = SessionMetaProtocol.canUserReplyToNotification(recipient, context);
|
||||
|
||||
PendingIntent quickReplyIntent = canReply ? notificationState.getQuickReplyIntent(context, recipient) : null;
|
||||
PendingIntent remoteReplyIntent = canReply ? notificationState.getRemoteReplyIntent(context, recipient, replyMethod) : null;
|
||||
|
||||
builder.addActions(notificationState.getMarkAsReadIntent(context, notificationId),
|
||||
quickReplyIntent,
|
||||
remoteReplyIntent,
|
||||
replyMethod);
|
||||
|
||||
if (canReply) {
|
||||
builder.addAndroidAutoAction(notificationState.getAndroidAutoReplyIntent(context, recipient),
|
||||
notificationState.getAndroidAutoHeardIntent(context, notificationId),
|
||||
notifications.get(0).getTimestamp());
|
||||
}
|
||||
|
||||
ListIterator<NotificationItem> iterator = notifications.listIterator(notifications.size());
|
||||
|
||||
while(iterator.hasPrevious()) {
|
||||
NotificationItem item = iterator.previous();
|
||||
builder.addMessageBody(item.getRecipient(), item.getIndividualRecipient(), item.getText());
|
||||
}
|
||||
|
||||
if (signal) {
|
||||
builder.setAlarms(notificationState.getRingtone(context), notificationState.getVibrate());
|
||||
builder.setTicker(notifications.get(0).getIndividualRecipient(),
|
||||
notifications.get(0).getText());
|
||||
}
|
||||
|
||||
if (bundled) {
|
||||
builder.setGroup(NOTIFICATION_GROUP);
|
||||
builder.setGroupAlertBehavior(NotificationCompat.GROUP_ALERT_SUMMARY);
|
||||
}
|
||||
|
||||
Notification notification = builder.build();
|
||||
NotificationManagerCompat.from(context).notify(notificationId, notification);
|
||||
Log.i(TAG, "Posted notification. " + notification.toString());
|
||||
}
|
||||
|
||||
private static void sendMultipleThreadNotification(@NonNull Context context,
|
||||
@NonNull NotificationState notificationState,
|
||||
boolean signal)
|
||||
{
|
||||
Log.i(TAG, "sendMultiThreadNotification() signal: " + signal);
|
||||
|
||||
MultipleRecipientNotificationBuilder builder = new MultipleRecipientNotificationBuilder(context, TextSecurePreferences.getNotificationPrivacy(context));
|
||||
List<NotificationItem> notifications = notificationState.getNotifications();
|
||||
|
||||
builder.setMessageCount(notificationState.getMessageCount(), notificationState.getThreadCount());
|
||||
builder.setMostRecentSender(notifications.get(0).getIndividualRecipient(), notifications.get(0).getRecipient());
|
||||
builder.setGroup(NOTIFICATION_GROUP);
|
||||
builder.setDeleteIntent(notificationState.getDeleteIntent(context));
|
||||
builder.setOnlyAlertOnce(!signal);
|
||||
builder.setGroupAlertBehavior(NotificationCompat.GROUP_ALERT_SUMMARY);
|
||||
builder.setAutoCancel(true);
|
||||
|
||||
long timestamp = notifications.get(0).getTimestamp();
|
||||
if (timestamp != 0) builder.setWhen(timestamp);
|
||||
|
||||
builder.addActions(notificationState.getMarkAsReadIntent(context, SUMMARY_NOTIFICATION_ID));
|
||||
|
||||
ListIterator<NotificationItem> iterator = notifications.listIterator(notifications.size());
|
||||
|
||||
while(iterator.hasPrevious()) {
|
||||
NotificationItem item = iterator.previous();
|
||||
builder.addMessageBody(item.getIndividualRecipient(), item.getRecipient(), item.getText());
|
||||
}
|
||||
|
||||
if (signal) {
|
||||
builder.setAlarms(notificationState.getRingtone(context), notificationState.getVibrate());
|
||||
builder.setTicker(notifications.get(0).getIndividualRecipient(),
|
||||
notifications.get(0).getText());
|
||||
}
|
||||
|
||||
Notification notification = builder.build();
|
||||
NotificationManagerCompat.from(context).notify(SUMMARY_NOTIFICATION_ID, builder.build());
|
||||
Log.i(TAG, "Posted notification. " + notification.toString());
|
||||
}
|
||||
|
||||
private static void sendInThreadNotification(Context context, Recipient recipient) {
|
||||
if (!TextSecurePreferences.isInThreadNotifications(context) ||
|
||||
ServiceUtil.getAudioManager(context).getRingerMode() != AudioManager.RINGER_MODE_NORMAL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Uri uri = null;
|
||||
if (recipient != null) {
|
||||
uri = NotificationChannels.supported() ? NotificationChannels.getMessageRingtone(context, recipient) : recipient.getMessageRingtone();
|
||||
}
|
||||
|
||||
if (uri == null) {
|
||||
uri = NotificationChannels.supported() ? NotificationChannels.getMessageRingtone(context) : TextSecurePreferences.getNotificationRingtone(context);
|
||||
}
|
||||
|
||||
if (uri.toString().isEmpty()) {
|
||||
Log.d(TAG, "ringtone uri is empty");
|
||||
return;
|
||||
}
|
||||
|
||||
Ringtone ringtone = RingtoneManager.getRingtone(context, uri);
|
||||
|
||||
if (ringtone == null) {
|
||||
Log.w(TAG, "ringtone is null");
|
||||
return;
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT >= 21) {
|
||||
ringtone.setAudioAttributes(new AudioAttributes.Builder().setContentType(AudioAttributes.CONTENT_TYPE_UNKNOWN)
|
||||
.setUsage(AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_INSTANT)
|
||||
.build());
|
||||
} else {
|
||||
ringtone.setStreamType(AudioManager.STREAM_NOTIFICATION);
|
||||
}
|
||||
|
||||
ringtone.play();
|
||||
}
|
||||
|
||||
private static NotificationState constructNotificationState(@NonNull Context context,
|
||||
@NonNull Cursor cursor)
|
||||
{
|
||||
NotificationState notificationState = new NotificationState();
|
||||
MmsSmsDatabase.Reader reader = DatabaseFactory.getMmsSmsDatabase(context).readerFor(cursor);
|
||||
|
||||
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();
|
||||
CharSequence body = record.getDisplayBody(context);
|
||||
Recipient threadRecipients = null;
|
||||
SlideDeck slideDeck = null;
|
||||
long timestamp = record.getTimestamp();
|
||||
|
||||
|
||||
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() && ((MmsMessageRecord) record).getSlideDeck().getStickerSlide() != null) {
|
||||
body = SpanUtil.italic(context.getString(R.string.MessageNotifier_sticker));
|
||||
slideDeck = ((MmsMessageRecord) record).getSlideDeck();
|
||||
} else if (record.isMms() && TextUtils.isEmpty(body) && !((MmsMessageRecord) record).getSlideDeck().getSlides().isEmpty()) {
|
||||
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()) {
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
reader.close();
|
||||
return notificationState;
|
||||
}
|
||||
|
||||
private static void updateBadge(Context context, int count) {
|
||||
try {
|
||||
if (count == 0) ShortcutBadger.removeCount(context);
|
||||
else ShortcutBadger.applyCount(context, count);
|
||||
} catch (Throwable t) {
|
||||
// NOTE :: I don't totally trust this thing, so I'm catching
|
||||
// everything.
|
||||
Log.w("MessageNotifier", t);
|
||||
}
|
||||
}
|
||||
|
||||
private static void scheduleReminder(Context context, int count) {
|
||||
if (count >= TextSecurePreferences.getRepeatAlertsCount(context)) {
|
||||
return;
|
||||
}
|
||||
|
||||
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
|
||||
Intent alarmIntent = new Intent(ReminderReceiver.REMINDER_ACTION);
|
||||
alarmIntent.putExtra("reminder_count", count);
|
||||
|
||||
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, alarmIntent, PendingIntent.FLAG_CANCEL_CURRENT);
|
||||
long timeout = TimeUnit.MINUTES.toMillis(2);
|
||||
|
||||
alarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + timeout, pendingIntent);
|
||||
}
|
||||
|
||||
public static void clearReminder(Context context) {
|
||||
Intent alarmIntent = new Intent(ReminderReceiver.REMINDER_ACTION);
|
||||
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, alarmIntent, PendingIntent.FLAG_CANCEL_CURRENT);
|
||||
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
|
||||
alarmManager.cancel(pendingIntent);
|
||||
}
|
||||
|
||||
public static class ReminderReceiver extends BroadcastReceiver {
|
||||
|
||||
public static final String REMINDER_ACTION = "network.loki.securesms.MessageNotifier.REMINDER_ACTION";
|
||||
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
@Override
|
||||
public void onReceive(final Context context, final Intent intent) {
|
||||
new AsyncTask<Void, Void, Void>() {
|
||||
@Override
|
||||
protected Void doInBackground(Void... params) {
|
||||
int reminderCount = intent.getIntExtra("reminder_count", 0);
|
||||
MessageNotifier.updateNotification(context, true, reminderCount + 1);
|
||||
|
||||
return null;
|
||||
}
|
||||
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
}
|
||||
}
|
||||
|
||||
private static class DelayedNotification implements Runnable {
|
||||
|
||||
private static final long DELAY = TimeUnit.SECONDS.toMillis(5);
|
||||
|
||||
private final AtomicBoolean canceled = new AtomicBoolean(false);
|
||||
|
||||
private final Context context;
|
||||
private final long threadId;
|
||||
private final long delayUntil;
|
||||
|
||||
private DelayedNotification(Context context, long threadId) {
|
||||
this.context = context;
|
||||
this.threadId = threadId;
|
||||
this.delayUntil = System.currentTimeMillis() + DELAY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
long delayMillis = delayUntil - System.currentTimeMillis();
|
||||
Log.i(TAG, "Waiting to notify: " + delayMillis);
|
||||
|
||||
if (delayMillis > 0) {
|
||||
Util.sleep(delayMillis);
|
||||
}
|
||||
|
||||
if (!canceled.get()) {
|
||||
Log.i(TAG, "Not canceled, notifying...");
|
||||
MessageNotifier.updateNotification(context, threadId, true);
|
||||
MessageNotifier.cancelDelayedNotifications();
|
||||
} else {
|
||||
Log.w(TAG, "Canceled, not notifying...");
|
||||
}
|
||||
}
|
||||
|
||||
public void cancel() {
|
||||
canceled.set(true);
|
||||
}
|
||||
}
|
||||
|
||||
private static class CancelableExecutor {
|
||||
|
||||
private final Executor executor = Executors.newSingleThreadExecutor();
|
||||
private final Set<DelayedNotification> tasks = new HashSet<>();
|
||||
|
||||
public void execute(final DelayedNotification runnable) {
|
||||
synchronized (tasks) {
|
||||
tasks.add(runnable);
|
||||
}
|
||||
|
||||
Runnable wrapper = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
runnable.run();
|
||||
|
||||
synchronized (tasks) {
|
||||
tasks.remove(runnable);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
executor.execute(wrapper);
|
||||
}
|
||||
|
||||
public void cancel() {
|
||||
synchronized (tasks) {
|
||||
for (DelayedNotification task : tasks) {
|
||||
task.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
public interface MessageNotifier {
|
||||
void setVisibleThread(long threadId);
|
||||
void setLastDesktopActivityTimestamp(long timestamp);
|
||||
void notifyMessageDeliveryFailed(Context context, Recipient recipient, long threadId);
|
||||
void cancelDelayedNotifications();
|
||||
void updateNotification(@NonNull Context context);
|
||||
void updateNotification(@NonNull Context context, long threadId);
|
||||
void updateNotification(@NonNull Context context, long threadId, boolean signal);
|
||||
void updateNotification(@android.support.annotation.NonNull Context context, boolean signal, int reminderCount);
|
||||
void clearReminder(@NonNull Context context);
|
||||
}
|
||||
|
@ -0,0 +1,106 @@
|
||||
package org.thoughtcrime.securesms.notifications;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.MainThread;
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import org.thoughtcrime.securesms.ApplicationContext;
|
||||
import org.thoughtcrime.securesms.loki.api.LokiPublicChatManager;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.util.Debouncer;
|
||||
import org.whispersystems.signalservice.loki.api.LokiPoller;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class OptimizedMessageNotifier implements MessageNotifier {
|
||||
private final MessageNotifier wrapped;
|
||||
private final Debouncer debouncer;
|
||||
|
||||
@MainThread
|
||||
public OptimizedMessageNotifier(@NonNull MessageNotifier wrapped) {
|
||||
this.wrapped = wrapped;
|
||||
this.debouncer = new Debouncer(TimeUnit.SECONDS.toMillis(1));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVisibleThread(long threadId) { wrapped.setVisibleThread(threadId); }
|
||||
|
||||
@Override
|
||||
public void setLastDesktopActivityTimestamp(long timestamp) { wrapped.setLastDesktopActivityTimestamp(timestamp);}
|
||||
|
||||
@Override
|
||||
public void notifyMessageDeliveryFailed(Context context, Recipient recipient, long threadId) {
|
||||
wrapped.notifyMessageDeliveryFailed(context, recipient, threadId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancelDelayedNotifications() { wrapped.cancelDelayedNotifications(); }
|
||||
|
||||
@Override
|
||||
public void updateNotification(@NonNull Context context) {
|
||||
LokiPoller lokiPoller = ApplicationContext.getInstance(context).lokiPoller;
|
||||
LokiPublicChatManager lokiPublicChatManager = ApplicationContext.getInstance(context).lokiPublicChatManager;
|
||||
Boolean isCaughtUp = false;
|
||||
if (lokiPoller != null && lokiPublicChatManager != null) {
|
||||
isCaughtUp = lokiPoller.isCaughtUp() && lokiPublicChatManager.areAllCaughtUp();
|
||||
}
|
||||
|
||||
if (isCaughtUp) {
|
||||
wrapped.updateNotification(context);
|
||||
} else {
|
||||
debouncer.publish(() -> wrapped.updateNotification(context));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateNotification(@NonNull Context context, long threadId) {
|
||||
LokiPoller lokiPoller = ApplicationContext.getInstance(context).lokiPoller;
|
||||
LokiPublicChatManager lokiPublicChatManager = ApplicationContext.getInstance(context).lokiPublicChatManager;
|
||||
Boolean isCaughtUp = false;
|
||||
if (lokiPoller != null && lokiPublicChatManager != null) {
|
||||
isCaughtUp = lokiPoller.isCaughtUp() && lokiPublicChatManager.areAllCaughtUp();
|
||||
}
|
||||
|
||||
if (isCaughtUp) {
|
||||
wrapped.updateNotification(context, threadId);
|
||||
} else {
|
||||
debouncer.publish(() -> wrapped.updateNotification(context, threadId));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateNotification(@NonNull Context context, long threadId, boolean signal) {
|
||||
LokiPoller lokiPoller = ApplicationContext.getInstance(context).lokiPoller;
|
||||
LokiPublicChatManager lokiPublicChatManager = ApplicationContext.getInstance(context).lokiPublicChatManager;
|
||||
Boolean isCaughtUp = false;
|
||||
if (lokiPoller != null && lokiPublicChatManager != null) {
|
||||
isCaughtUp = lokiPoller.isCaughtUp() && lokiPublicChatManager.areAllCaughtUp();
|
||||
}
|
||||
|
||||
if (isCaughtUp) {
|
||||
wrapped.updateNotification(context, threadId, signal);
|
||||
} else {
|
||||
debouncer.publish(() -> wrapped.updateNotification(context, threadId, signal));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateNotification(@android.support.annotation.NonNull Context context, boolean signal, int reminderCount) {
|
||||
LokiPoller lokiPoller = ApplicationContext.getInstance(context).lokiPoller;
|
||||
LokiPublicChatManager lokiPublicChatManager = ApplicationContext.getInstance(context).lokiPublicChatManager;
|
||||
Boolean isCaughtUp = false;
|
||||
if (lokiPoller != null && lokiPublicChatManager != null) {
|
||||
isCaughtUp = lokiPoller.isCaughtUp() && lokiPublicChatManager.areAllCaughtUp();
|
||||
}
|
||||
|
||||
if (isCaughtUp) {
|
||||
wrapped.updateNotification(context, signal, reminderCount);
|
||||
} else {
|
||||
debouncer.publish(() -> wrapped.updateNotification(context, signal, reminderCount));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearReminder(@NonNull Context context) { wrapped.clearReminder(context); }
|
||||
}
|
@ -25,6 +25,7 @@ import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.RemoteInput;
|
||||
|
||||
import org.thoughtcrime.securesms.ApplicationContext;
|
||||
import org.thoughtcrime.securesms.database.Address;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.MessagingDatabase.MarkedMessageInfo;
|
||||
@ -59,7 +60,7 @@ public class RemoteReplyReceiver extends BroadcastReceiver {
|
||||
|
||||
final Address address = intent.getParcelableExtra(ADDRESS_EXTRA);
|
||||
final ReplyMethod replyMethod = (ReplyMethod) intent.getSerializableExtra(REPLY_METHOD);
|
||||
final CharSequence responseText = remoteInput.getCharSequence(MessageNotifier.EXTRA_REMOTE_REPLY);
|
||||
final CharSequence responseText = remoteInput.getCharSequence(DefaultMessageNotifier.EXTRA_REMOTE_REPLY);
|
||||
|
||||
if (address == null) throw new AssertionError("No address specified");
|
||||
if (replyMethod == null) throw new AssertionError("No reply method specified");
|
||||
@ -91,7 +92,7 @@ public class RemoteReplyReceiver extends BroadcastReceiver {
|
||||
|
||||
List<MarkedMessageInfo> messageIds = DatabaseFactory.getThreadDatabase(context).setRead(threadId, true);
|
||||
|
||||
MessageNotifier.updateNotification(context);
|
||||
ApplicationContext.getInstance(context).messageNotifier.updateNotification(context);
|
||||
MarkReadReceiver.process(context, messageIds);
|
||||
|
||||
return null;
|
||||
|
@ -177,14 +177,14 @@ public class SingleRecipientNotificationBuilder extends AbstractNotificationBuil
|
||||
replyAction = new Action.Builder(R.drawable.ic_reply_white_36dp,
|
||||
actionName,
|
||||
wearableReplyIntent)
|
||||
.addRemoteInput(new RemoteInput.Builder(MessageNotifier.EXTRA_REMOTE_REPLY).setLabel(label).build())
|
||||
.addRemoteInput(new RemoteInput.Builder(DefaultMessageNotifier.EXTRA_REMOTE_REPLY).setLabel(label).build())
|
||||
.build();
|
||||
}
|
||||
|
||||
Action wearableReplyAction = new Action.Builder(R.drawable.ic_reply,
|
||||
actionName,
|
||||
wearableReplyIntent)
|
||||
.addRemoteInput(new RemoteInput.Builder(MessageNotifier.EXTRA_REMOTE_REPLY).setLabel(label).build())
|
||||
.addRemoteInput(new RemoteInput.Builder(DefaultMessageNotifier.EXTRA_REMOTE_REPLY).setLabel(label).build())
|
||||
.build();
|
||||
|
||||
|
||||
|
@ -220,7 +220,7 @@ public class NotificationsPreferenceFragment extends ListSummaryPreferenceFragme
|
||||
new AsyncTask<Void, Void, Void>() {
|
||||
@Override
|
||||
protected Void doInBackground(Void... params) {
|
||||
MessageNotifier.updateNotification(getActivity());
|
||||
ApplicationContext.getInstance(getActivity()).messageNotifier.updateNotification(getActivity());
|
||||
return null;
|
||||
}
|
||||
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
|
@ -115,7 +115,7 @@ public class KeyCachingService extends Service {
|
||||
@Override
|
||||
protected Void doInBackground(Void... params) {
|
||||
if (!DatabaseUpgradeActivity.isUpdate(KeyCachingService.this)) {
|
||||
MessageNotifier.updateNotification(KeyCachingService.this);
|
||||
ApplicationContext.getInstance(KeyCachingService.this).messageNotifier.updateNotification(KeyCachingService.this);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@ -188,7 +188,7 @@ public class KeyCachingService extends Service {
|
||||
new AsyncTask<Void, Void, Void>() {
|
||||
@Override
|
||||
protected Void doInBackground(Void... params) {
|
||||
MessageNotifier.updateNotification(KeyCachingService.this);
|
||||
ApplicationContext.getInstance(KeyCachingService.this).messageNotifier.updateNotification(KeyCachingService.this);
|
||||
return null;
|
||||
}
|
||||
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
|
@ -721,7 +721,7 @@ public class WebRtcCallService extends Service implements InjectableType,
|
||||
|
||||
private void insertMissedCall(@NonNull Recipient recipient, boolean signal) {
|
||||
Pair<Long, Long> messageAndThreadId = DatabaseFactory.getSmsDatabase(this).insertMissedCall(recipient.getAddress());
|
||||
MessageNotifier.updateNotification(this, messageAndThreadId.second, signal);
|
||||
ApplicationContext.getInstance(this).messageNotifier.updateNotification(this, messageAndThreadId.second, signal);
|
||||
}
|
||||
|
||||
private void handleAnswerCall(Intent intent) {
|
||||
|
@ -6,6 +6,7 @@ import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.annotation.StringRes;
|
||||
|
||||
import org.thoughtcrime.securesms.ApplicationContext;
|
||||
import org.thoughtcrime.securesms.crypto.storage.TextSecureIdentityKeyStore;
|
||||
import org.thoughtcrime.securesms.crypto.storage.TextSecureSessionStore;
|
||||
import org.thoughtcrime.securesms.database.Address;
|
||||
@ -143,7 +144,7 @@ public class IdentityUtil {
|
||||
Optional<InsertResult> insertResult = smsDatabase.insertMessageInbox(individualUpdate);
|
||||
|
||||
if (insertResult.isPresent()) {
|
||||
MessageNotifier.updateNotification(context, insertResult.get().getThreadId());
|
||||
ApplicationContext.getInstance(context).messageNotifier.updateNotification(context, insertResult.get().getThreadId());
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user