2020-06-26 08:17:53 +02:00
|
|
|
/*
|
|
|
|
* 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.net.Uri;
|
|
|
|
import android.os.AsyncTask;
|
|
|
|
import android.os.Build;
|
|
|
|
import android.service.notification.StatusBarNotification;
|
2021-03-05 06:19:53 +01:00
|
|
|
import android.text.TextUtils;
|
|
|
|
|
2020-08-19 02:06:26 +02:00
|
|
|
import androidx.annotation.NonNull;
|
2022-08-10 10:17:48 +02:00
|
|
|
import androidx.annotation.Nullable;
|
2020-08-19 02:06:26 +02:00
|
|
|
import androidx.core.app.NotificationCompat;
|
|
|
|
import androidx.core.app.NotificationManagerCompat;
|
2020-06-26 08:17:53 +02:00
|
|
|
|
2022-09-07 05:41:43 +02:00
|
|
|
import com.annimon.stream.Optional;
|
|
|
|
import com.annimon.stream.Stream;
|
2022-08-10 10:17:48 +02:00
|
|
|
import com.goterl.lazysodium.utils.KeyPair;
|
|
|
|
|
|
|
|
import org.session.libsession.messaging.open_groups.OpenGroup;
|
2021-01-13 07:11:30 +01:00
|
|
|
import org.session.libsession.messaging.sending_receiving.notifications.MessageNotifier;
|
2022-08-10 10:17:48 +02:00
|
|
|
import org.session.libsession.messaging.utilities.SessionId;
|
|
|
|
import org.session.libsession.messaging.utilities.SodiumUtilities;
|
2021-07-30 02:30:04 +02:00
|
|
|
import org.session.libsession.utilities.Address;
|
2021-05-18 08:11:38 +02:00
|
|
|
import org.session.libsession.utilities.Contact;
|
2021-03-05 06:19:53 +01:00
|
|
|
import org.session.libsession.utilities.ServiceUtil;
|
|
|
|
import org.session.libsession.utilities.TextSecurePreferences;
|
2021-07-20 08:06:59 +02:00
|
|
|
import org.session.libsession.utilities.recipients.Recipient;
|
2022-08-10 10:17:48 +02:00
|
|
|
import org.session.libsignal.utilities.IdPrefix;
|
2021-05-18 01:12:33 +02:00
|
|
|
import org.session.libsignal.utilities.Log;
|
2021-07-20 08:06:59 +02:00
|
|
|
import org.session.libsignal.utilities.Util;
|
2021-03-05 06:19:53 +01:00
|
|
|
import org.thoughtcrime.securesms.ApplicationContext;
|
2020-06-26 08:17:53 +02:00
|
|
|
import org.thoughtcrime.securesms.contactshare.ContactUtil;
|
2021-06-30 06:57:53 +02:00
|
|
|
import org.thoughtcrime.securesms.conversation.v2.ConversationActivityV2;
|
2021-07-30 01:54:16 +02:00
|
|
|
import org.thoughtcrime.securesms.conversation.v2.utilities.MentionManagerUtilities;
|
2021-07-20 08:06:59 +02:00
|
|
|
import org.thoughtcrime.securesms.conversation.v2.utilities.MentionUtilities;
|
2022-08-10 10:17:48 +02:00
|
|
|
import org.thoughtcrime.securesms.crypto.KeyPairUtilities;
|
|
|
|
import org.thoughtcrime.securesms.database.LokiThreadDatabase;
|
2020-06-26 08:17:53 +02:00
|
|
|
import org.thoughtcrime.securesms.database.MessagingDatabase.MarkedMessageInfo;
|
|
|
|
import org.thoughtcrime.securesms.database.MmsSmsDatabase;
|
2021-07-20 08:06:59 +02:00
|
|
|
import org.thoughtcrime.securesms.database.RecipientDatabase;
|
2020-06-26 08:17:53 +02:00
|
|
|
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;
|
2021-07-30 02:30:04 +02:00
|
|
|
import org.thoughtcrime.securesms.database.model.Quote;
|
2022-09-04 13:03:32 +02:00
|
|
|
import org.thoughtcrime.securesms.database.model.ReactionRecord;
|
2021-10-04 09:51:19 +02:00
|
|
|
import org.thoughtcrime.securesms.dependencies.DatabaseComponent;
|
2020-06-26 08:17:53 +02:00
|
|
|
import org.thoughtcrime.securesms.mms.SlideDeck;
|
|
|
|
import org.thoughtcrime.securesms.service.KeyCachingService;
|
2021-07-20 08:06:59 +02:00
|
|
|
import org.thoughtcrime.securesms.util.SessionMetaProtocol;
|
2020-06-26 08:17:53 +02:00
|
|
|
import org.thoughtcrime.securesms.util.SpanUtil;
|
|
|
|
|
2022-08-10 10:17:48 +02:00
|
|
|
import java.util.HashMap;
|
2020-06-26 08:17:53 +02:00
|
|
|
import java.util.HashSet;
|
|
|
|
import java.util.List;
|
|
|
|
import java.util.ListIterator;
|
2022-08-10 10:17:48 +02:00
|
|
|
import java.util.Map;
|
2021-07-30 02:30:04 +02:00
|
|
|
import java.util.Objects;
|
2020-06-26 08:17:53 +02:00
|
|
|
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();
|
|
|
|
|
2021-08-16 06:05:49 +02:00
|
|
|
public static final String EXTRA_REMOTE_REPLY = "extra_remote_reply";
|
2021-07-21 05:58:07 +02:00
|
|
|
public static final String LATEST_MESSAGE_ID_TAG = "extra_latest_message_id";
|
2020-06-26 08:17:53 +02:00
|
|
|
|
2021-08-19 05:45:57 +02:00
|
|
|
private static final int FOREGROUND_ID = 313399;
|
|
|
|
private static final int SUMMARY_NOTIFICATION_ID = 1338;
|
2020-06-26 08:17:53 +02:00
|
|
|
private static final int PENDING_MESSAGES_ID = 1111;
|
|
|
|
private static final String NOTIFICATION_GROUP = "messages";
|
2021-09-29 07:29:24 +02:00
|
|
|
private static final long MIN_AUDIBLE_PERIOD_MILLIS = TimeUnit.SECONDS.toMillis(5);
|
2020-06-26 08:17:53 +02:00
|
|
|
private static final long DESKTOP_ACTIVITY_PERIOD = TimeUnit.MINUTES.toMillis(1);
|
|
|
|
|
|
|
|
private volatile static long visibleThread = -1;
|
2021-07-13 08:31:16 +02:00
|
|
|
private volatile static boolean homeScreenVisible = false;
|
2020-06-26 08:17:53 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2021-07-13 08:31:16 +02:00
|
|
|
@Override
|
|
|
|
public void setHomeScreenVisible(boolean isVisible) {
|
|
|
|
homeScreenVisible = isVisible;
|
|
|
|
}
|
|
|
|
|
2020-06-26 08:17:53 +02:00
|
|
|
@Override
|
|
|
|
public void setLastDesktopActivityTimestamp(long timestamp) {
|
|
|
|
lastDesktopActivityTimestamp = timestamp;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void notifyMessageDeliveryFailed(Context context, Recipient recipient, long threadId) {
|
2022-09-07 05:41:43 +02:00
|
|
|
if (visibleThread != threadId) {
|
2021-06-30 06:57:53 +02:00
|
|
|
Intent intent = new Intent(context, ConversationActivityV2.class);
|
2021-07-01 01:31:30 +02:00
|
|
|
intent.putExtra(ConversationActivityV2.ADDRESS, recipient.getAddress());
|
2021-06-30 06:57:53 +02:00
|
|
|
intent.putExtra(ConversationActivityV2.THREAD_ID, threadId);
|
2020-06-26 08:17:53 +02:00
|
|
|
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);
|
|
|
|
|
2022-09-04 13:03:32 +02:00
|
|
|
try {
|
|
|
|
StatusBarNotification[] activeNotifications = notifications.getActiveNotifications();
|
2020-06-26 08:17:53 +02:00
|
|
|
|
2022-09-04 13:03:32 +02:00
|
|
|
for (StatusBarNotification activeNotification : activeNotifications) {
|
|
|
|
notifications.cancel(activeNotification.getId());
|
2020-06-26 08:17:53 +02:00
|
|
|
}
|
2022-09-04 13:03:32 +02:00
|
|
|
} catch (Throwable e) {
|
|
|
|
// XXX Appears to be a ROM bug, see #6043
|
|
|
|
Log.w(TAG, e);
|
|
|
|
notifications.cancelAll();
|
2020-06-26 08:17:53 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void cancelOrphanedNotifications(@NonNull Context context, NotificationState notificationState) {
|
2022-03-04 07:46:39 +01:00
|
|
|
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() != KeyCachingService.SERVICE_RUNNING_ID &&
|
|
|
|
notification.getId() != FOREGROUND_ID &&
|
|
|
|
notification.getId() != PENDING_MESSAGES_ID)
|
|
|
|
{
|
|
|
|
for (NotificationItem item : notificationState.getNotifications()) {
|
|
|
|
if (notification.getId() == (SUMMARY_NOTIFICATION_ID + item.getThreadId())) {
|
|
|
|
validNotification = true;
|
|
|
|
break;
|
2020-06-26 08:17:53 +02:00
|
|
|
}
|
2022-03-04 07:46:39 +01:00
|
|
|
}
|
2020-06-26 08:17:53 +02:00
|
|
|
|
2022-03-04 07:46:39 +01:00
|
|
|
if (!validNotification) {
|
|
|
|
notifications.cancel(notification.getId());
|
2020-06-26 08:17:53 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-03-04 07:46:39 +01:00
|
|
|
} catch (Throwable e) {
|
|
|
|
// XXX Android ROM Bug, see #6043
|
|
|
|
Log.w(TAG, e);
|
2020-06-26 08:17:53 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@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
|
2020-08-12 06:06:18 +02:00
|
|
|
public void updateNotification(@NonNull Context context, long threadId, boolean signal)
|
2020-06-26 08:17:53 +02:00
|
|
|
{
|
|
|
|
boolean isVisible = visibleThread == threadId;
|
|
|
|
|
2021-10-04 09:51:19 +02:00
|
|
|
ThreadDatabase threads = DatabaseComponent.get(context).threadDatabase();
|
2022-03-04 07:46:39 +01:00
|
|
|
Recipient recipient = threads.getRecipientForThreadId(threadId);
|
2020-06-26 08:17:53 +02:00
|
|
|
|
Performance improvements and bug fixes (#869)
* refactor: fail on testSnode instead of recursively using up snode list. add call timeout on http client
* refactor: refactoring batch message receives and pollers
* refactor: reduce thread utils pool count to a 2 thread fixed pool. Do a check against pubkey instead of room names for oxenHostedOpenGroup
* refactor: caching lib with potential loader fixes and no-cache for giphy
* refactor: remove store and instead use ConcurrentHashMap with a backing update coroutine
* refactor: queue trim thread jobs instead of add every message processed
* fix: wrapping auth token and initial sync for open groups in a threadutils queued runnable, getting initial sync times down
* fix: fixing the user contacts cache in ConversationAdapter.kt
* refactor: improve polling and initial sync, move group joins from config messages into a background job fetching image.
* refactor: improving the job queuing for open groups, replacing placeholder avatar generation with a custom glide loader and archiving initial sync of open groups
* feat: add OpenGroupDeleteJob.kt
* feat: add open group delete job to process deletions after batch adding
* feat: add vacuum and fix job queue re-adding jobs forever, only try to set message hash values in DB if they have changed
* refactor: remove redundant inflation for profile image views throughout app
* refactor(wip): reducing layout inflation and starting to refactor the open group deletion issues taking a long time
* refactor(wip): refactoring group deletion to not iterate through and delete messages individually
* refactor(wip): refactoring group deletion to not iterate through and delete messages individually
* fix: group deletion optimisation
* build: bump build number
* build: bump build number and fix batch message receive retry logic
* fix: clear out open group deletes
* fix: update visible ConversationAdapter.kt binding for initial contact fetching and better traces for debugging background jobs
* fix: add in check for / force sync latest encryption key pair from linked devices if we already have that closed group
* Rename .java to .kt
* refactor: change MmsDatabase to kotlin to make list operations easier
* fix: nullable type
* fix: compilation issues and constants in .kt instead of .java
* fix: bug fix expiration timer on closed group recipient
* feat: use the job queue properly across executors
* feat: start on open group dispatcher-specific logic, probably a queue factory based on openGroupId if that is the same across new message and deletion jobs to ensure consistent entry and removal
* refactor: removing redundant code and fixing jobqueue per opengroup
* fix: allow attachments in note to self
* fix: make the minWidth in quote view bind max of text / title and body, wrapped ?
* fix: fixing up layouts and code view layouts
* fix: remove TODO, remove timestamp binding
* feat: fix view logic, avatars and padding, downloading attachments lazily (on bind), fixing potential crash, add WindowDebouncer.kt
* fix: NPE on viewModel recipient from removed thread while tearing down the Recipient observer in ConversationActivityV2.kt
* refactor: replace conversation notification debouncer handler with handlerthread, same as conversation list debouncer
* refactor: UI for groups and poller improvements
* fix: revert some changes in poller
* feat: add header back in for message requests
* refactor: remove Trace calls, add more conditions to the HomeDiffUtil for updating more efficiently
* feat: try update the home adapter if we get a profile picture modified event
* feat: bump build numbers
* fix: try to start with list in homeViewModel if we don't have already, render quotes to be width of attachment slide view instead of fixed
* fix: set channel to be conflated instead of no buffer
* fix: set unreads based off last local user message vs incrementing unreads to be all amount
* feat: add profile update flag, update build number
* fix: link preview thumbnails download on bind
* fix: centercrop placeholder in glide request
* feat: recycle the contact selection list and profile image in unbind
* fix: try to prevent user KP crash at weird times
* fix: remove additional log, improve attachment download success rate, fix share logs dialog issue
2022-06-08 09:12:34 +02:00
|
|
|
if (recipient != null && !recipient.isGroupRecipient() && threads.getMessageCount(threadId) == 1 &&
|
2022-03-04 07:46:39 +01:00
|
|
|
!(recipient.isApproved() || threads.getLastSeenAndHasSent(threadId).second())) {
|
|
|
|
TextSecurePreferences.removeHasHiddenMessageRequests(context);
|
|
|
|
}
|
|
|
|
if (isVisible && recipient != null) {
|
2020-06-26 08:17:53 +02:00
|
|
|
List<MarkedMessageInfo> messageIds = threads.setRead(threadId, false);
|
2022-03-04 07:46:39 +01:00
|
|
|
if (SessionMetaProtocol.shouldSendReadReceipt(recipient)) { MarkReadReceiver.process(context, messageIds); }
|
2020-06-26 08:17:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!TextSecurePreferences.isNotificationsEnabled(context) ||
|
2022-03-04 07:46:39 +01:00
|
|
|
(recipient != null && recipient.isMuted()))
|
2020-06-26 08:17:53 +02:00
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-09-07 05:41:43 +02:00
|
|
|
if (!isVisible && !homeScreenVisible) {
|
2020-06-26 08:17:53 +02:00
|
|
|
updateNotification(context, signal, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void updateNotification(@NonNull Context context, boolean signal, int reminderCount)
|
|
|
|
{
|
|
|
|
Cursor telcoCursor = null;
|
|
|
|
Cursor pushCursor = null;
|
|
|
|
|
|
|
|
try {
|
2022-08-08 07:16:33 +02:00
|
|
|
telcoCursor = DatabaseComponent.get(context).mmsSmsDatabase().getUnread(); // TODO: add a notification specific lighter query here
|
2020-06-26 08:17:53 +02:00
|
|
|
|
Add one on one calls over clearnet (#864)
* feat: adding basic webrtc deps and test activity
* more testing code
* feat: add protos and bump version
* feat: added basic call functionality
* feat: adding UI and flipping cameras
* feat: add stats and starting call bottom sheet
* feat: hanging up and bottom sheet behaviors should work now
* feat: add call stats report on frontend
* feat: add relay toggle for answer and offer
* fix: add keep screen on and more end call message on back pressed / on finish
* refactor: removing and replacing dagger 1 dep with android hilt
* feat: include latest proto
* feat: update to utilise call ID
* feat: add stun and turn
* refactor: playing around with deps and transport types
* feat: adding call service functionality and permissions for calls
* feat: add call manager and more static intent building functions for WebRtcCallService.kt
* feat: adding ringers and more audio boilerplate
* feat: audio manager call service boilerplate
* feat: update kotlin and add in call view model and more management functions
* refactor: moving call code around to service and viewmodel interactions
* feat: plugging CallManager.kt into view model and service, fixing up dependencies
* feat: implementing more WebRtcCallService.kt functions and handlers for actions as well as lifecycle
* feat: adding more lifecycle vm and callmanager / call service functionality
* feat: adding more command handlers in WebRtcCallService.kt
* feat: more commands handled, adding lock manager and bluetooth permissions
* feat: adding remainder of basic functionality to services and CallManager.kt
* feat: hooking up calls and fixing broken dependencies and compile errors
* fix: add timestamp to incoming call
* feat: some connection and service launching / ring lifecycle
* feat: call establishing and displaying
* fix: fixing call connect flows
* feat: ringers and better state handling
* feat: updating call layout
* feat: add fixes to bluetooth and begin the network renegotiation
* feat: add call related permissions and more network handover tests
* fix: don't display call option in conversation and don't show notification if option not enabled
* fix: incoming ringer fix on receiving call, call notification priorities and notification channel update
* build: update build number for testing
* fix: bluetooth auto-connection and re-connection fixes, removing finished todos, allowing self-send call messages for deduping answers
* feat: add pre-offer information and action handling in web rtc call service
* refactor: discard offer messages from non-matching pre-offers we are already expecting
* build: build numbers and version name update
* feat: handle discarding pending calls from linked devices
* feat: add signing props to release config build
* docs: fix comment on time being 300s (5m) instead of 30s
* feat: adding call messages for incoming/outgoing/missed
* refactor: handle in-thread call notifications better and replace deny button intent with denyCallIntent instead of hangup
* feat: add a hangup via data channel message
* feat: process microphone enabled events and remove debuggable from build.gradle
* feat: add first call notification
* refactor: set the buttons to match iOS in terms of enable disable and colours
* refactor: change the call logos in control messages
* refactor: more bluetooth improvements
* refactor: move start ringer and init of audio manager to CallManager.kt and string fix up
* build: remove debuggable for release build
* refactor: replace call icons
* feat: adding a call time display
* refactor: change the call time to update every second
* refactor: testing out the full screen intents
* refactor: wrapper use corrected session description, set title to recipient displayName, indicate session calls
* fix: crash on view with a parent already attached
* refactor: aspect ratio fit preserved
* refactor: add wantsToAnswer ability in pre-init for fullscreenintent
* refactor: prevent calls from non hasSent participants
* build: update gradle code
* refactor: replace timeout schedule with a seconds count
* fix: various bug fixes for calls
* fix: remove end call from busy
* refactor: use answerCall instead of manual intent building again
* build: new version
* feat: add silenced notifications for call notification builder. check pre-offer and connecting state for pending connection
* build: update build number
* fix: text color uses overridden style value
* fix: remove wrap content for renderers and look more at recovering from network switches
* build: update build number
* refactor: remove whitespace
* build: update build number
* refactor: used shared number for BatchMessageReceiveJob.kt parameter across pollers
* fix: glide in update crash
* fix: bug fixes for self-send answer / hangup messages
* build: update build number
* build: update build.gradle number
* refactor: compile errors and refactoring to view binding
* fix: set the content to binding.root view
* build: increase build number
* build: update build numbers
* feat: adding base for rotation and picking random subset of turn servers
* feat: starting the screen rotation processing
* feat: setting up rotation for the remote render view
* refactor: applying rotation and mirroring based on front / rear cameras that wraps nicely, only scale reworking needed
* refactor: calls video stretching but consistent
* refactor: state machine and tests for the transition events
* feat: new call state processing
* refactor: adding reconnecting logic and visuals
* feat: state machine reconnect logic wip
* feat: add reconnecting and merge fixes
* feat: check new session based off current state
* feat: reconnection logic works correctly now
* refactor: reduce TIMEOUT_SECONDS to 30 from 90
* feat: reset peer connection on DC to prevent ICE messages from old connection or stale state in reconnecting
* refactor: add null case
* fix: set approved on new outgoing threads, use approved more deeply and invalidate the options menu on recipient modified. Add approvedMe flag toggles for visible message receive
* fix: add name update in action bar on modified, change where approvedMe is set
* build: increment build number
* build: update build number
* fix: merge compile errors and increment build number
* refactor: remove negotiation based on which party dropped connection
* refactor: call reconnection improvement tested cross platform to re-establish
* refactor: failed and disconnect events only handled if either the reconnect or the timeout runnables are not set
* build: update version number
* fix: reduce timeout
* fix: fixes the incoming hangup logic for linked devices
* refactor: match iOS styling for call activity closer
* chore: upgrade build numbers
* feat: add in call settings dialog for if calls is disabled in conversation
* feat: add a first call missed control message and info popup with link to privacy settings
* fix: looking at crash for specific large transaction in NotificationManager
* refactor: removing the people in case transaction size reduces to fix notif crash
* fix: comment out the entire send multiple to see if it fixes the issue
* refactor: revert to including the full notification process in a try/catch to handle weird responses from NotificationManager
* fix: add in notification settings prompt for calls and try to fall back to dirty full screen intent / start activity if we're allowed
* build: upgrade build number
2022-04-19 06:25:40 +02:00
|
|
|
if ((telcoCursor == null || telcoCursor.isAfterLast()) || !TextSecurePreferences.hasSeenWelcomeScreen(context))
|
2020-06-26 08:17:53 +02:00
|
|
|
{
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
Add one on one calls over clearnet (#864)
* feat: adding basic webrtc deps and test activity
* more testing code
* feat: add protos and bump version
* feat: added basic call functionality
* feat: adding UI and flipping cameras
* feat: add stats and starting call bottom sheet
* feat: hanging up and bottom sheet behaviors should work now
* feat: add call stats report on frontend
* feat: add relay toggle for answer and offer
* fix: add keep screen on and more end call message on back pressed / on finish
* refactor: removing and replacing dagger 1 dep with android hilt
* feat: include latest proto
* feat: update to utilise call ID
* feat: add stun and turn
* refactor: playing around with deps and transport types
* feat: adding call service functionality and permissions for calls
* feat: add call manager and more static intent building functions for WebRtcCallService.kt
* feat: adding ringers and more audio boilerplate
* feat: audio manager call service boilerplate
* feat: update kotlin and add in call view model and more management functions
* refactor: moving call code around to service and viewmodel interactions
* feat: plugging CallManager.kt into view model and service, fixing up dependencies
* feat: implementing more WebRtcCallService.kt functions and handlers for actions as well as lifecycle
* feat: adding more lifecycle vm and callmanager / call service functionality
* feat: adding more command handlers in WebRtcCallService.kt
* feat: more commands handled, adding lock manager and bluetooth permissions
* feat: adding remainder of basic functionality to services and CallManager.kt
* feat: hooking up calls and fixing broken dependencies and compile errors
* fix: add timestamp to incoming call
* feat: some connection and service launching / ring lifecycle
* feat: call establishing and displaying
* fix: fixing call connect flows
* feat: ringers and better state handling
* feat: updating call layout
* feat: add fixes to bluetooth and begin the network renegotiation
* feat: add call related permissions and more network handover tests
* fix: don't display call option in conversation and don't show notification if option not enabled
* fix: incoming ringer fix on receiving call, call notification priorities and notification channel update
* build: update build number for testing
* fix: bluetooth auto-connection and re-connection fixes, removing finished todos, allowing self-send call messages for deduping answers
* feat: add pre-offer information and action handling in web rtc call service
* refactor: discard offer messages from non-matching pre-offers we are already expecting
* build: build numbers and version name update
* feat: handle discarding pending calls from linked devices
* feat: add signing props to release config build
* docs: fix comment on time being 300s (5m) instead of 30s
* feat: adding call messages for incoming/outgoing/missed
* refactor: handle in-thread call notifications better and replace deny button intent with denyCallIntent instead of hangup
* feat: add a hangup via data channel message
* feat: process microphone enabled events and remove debuggable from build.gradle
* feat: add first call notification
* refactor: set the buttons to match iOS in terms of enable disable and colours
* refactor: change the call logos in control messages
* refactor: more bluetooth improvements
* refactor: move start ringer and init of audio manager to CallManager.kt and string fix up
* build: remove debuggable for release build
* refactor: replace call icons
* feat: adding a call time display
* refactor: change the call time to update every second
* refactor: testing out the full screen intents
* refactor: wrapper use corrected session description, set title to recipient displayName, indicate session calls
* fix: crash on view with a parent already attached
* refactor: aspect ratio fit preserved
* refactor: add wantsToAnswer ability in pre-init for fullscreenintent
* refactor: prevent calls from non hasSent participants
* build: update gradle code
* refactor: replace timeout schedule with a seconds count
* fix: various bug fixes for calls
* fix: remove end call from busy
* refactor: use answerCall instead of manual intent building again
* build: new version
* feat: add silenced notifications for call notification builder. check pre-offer and connecting state for pending connection
* build: update build number
* fix: text color uses overridden style value
* fix: remove wrap content for renderers and look more at recovering from network switches
* build: update build number
* refactor: remove whitespace
* build: update build number
* refactor: used shared number for BatchMessageReceiveJob.kt parameter across pollers
* fix: glide in update crash
* fix: bug fixes for self-send answer / hangup messages
* build: update build number
* build: update build.gradle number
* refactor: compile errors and refactoring to view binding
* fix: set the content to binding.root view
* build: increase build number
* build: update build numbers
* feat: adding base for rotation and picking random subset of turn servers
* feat: starting the screen rotation processing
* feat: setting up rotation for the remote render view
* refactor: applying rotation and mirroring based on front / rear cameras that wraps nicely, only scale reworking needed
* refactor: calls video stretching but consistent
* refactor: state machine and tests for the transition events
* feat: new call state processing
* refactor: adding reconnecting logic and visuals
* feat: state machine reconnect logic wip
* feat: add reconnecting and merge fixes
* feat: check new session based off current state
* feat: reconnection logic works correctly now
* refactor: reduce TIMEOUT_SECONDS to 30 from 90
* feat: reset peer connection on DC to prevent ICE messages from old connection or stale state in reconnecting
* refactor: add null case
* fix: set approved on new outgoing threads, use approved more deeply and invalidate the options menu on recipient modified. Add approvedMe flag toggles for visible message receive
* fix: add name update in action bar on modified, change where approvedMe is set
* build: increment build number
* build: update build number
* fix: merge compile errors and increment build number
* refactor: remove negotiation based on which party dropped connection
* refactor: call reconnection improvement tested cross platform to re-establish
* refactor: failed and disconnect events only handled if either the reconnect or the timeout runnables are not set
* build: update version number
* fix: reduce timeout
* fix: fixes the incoming hangup logic for linked devices
* refactor: match iOS styling for call activity closer
* chore: upgrade build numbers
* feat: add in call settings dialog for if calls is disabled in conversation
* feat: add a first call missed control message and info popup with link to privacy settings
* fix: looking at crash for specific large transaction in NotificationManager
* refactor: removing the people in case transaction size reduces to fix notif crash
* fix: comment out the entire send multiple to see if it fixes the issue
* refactor: revert to including the full notification process in a try/catch to handle weird responses from NotificationManager
* fix: add in notification settings prompt for calls and try to fall back to dirty full screen intent / start activity if we're allowed
* build: upgrade build number
2022-04-19 06:25:40 +02:00
|
|
|
try {
|
|
|
|
if (notificationState.hasMultipleThreads()) {
|
|
|
|
for (long threadId : notificationState.getThreads()) {
|
|
|
|
sendSingleThreadNotification(context, new NotificationState(notificationState.getNotificationsForThread(threadId)), false, true);
|
|
|
|
}
|
2022-06-21 08:17:01 +02:00
|
|
|
sendMultipleThreadNotification(context, notificationState, signal);
|
2022-09-04 13:03:32 +02:00
|
|
|
} else if (notificationState.getMessageCount() > 0) {
|
Add one on one calls over clearnet (#864)
* feat: adding basic webrtc deps and test activity
* more testing code
* feat: add protos and bump version
* feat: added basic call functionality
* feat: adding UI and flipping cameras
* feat: add stats and starting call bottom sheet
* feat: hanging up and bottom sheet behaviors should work now
* feat: add call stats report on frontend
* feat: add relay toggle for answer and offer
* fix: add keep screen on and more end call message on back pressed / on finish
* refactor: removing and replacing dagger 1 dep with android hilt
* feat: include latest proto
* feat: update to utilise call ID
* feat: add stun and turn
* refactor: playing around with deps and transport types
* feat: adding call service functionality and permissions for calls
* feat: add call manager and more static intent building functions for WebRtcCallService.kt
* feat: adding ringers and more audio boilerplate
* feat: audio manager call service boilerplate
* feat: update kotlin and add in call view model and more management functions
* refactor: moving call code around to service and viewmodel interactions
* feat: plugging CallManager.kt into view model and service, fixing up dependencies
* feat: implementing more WebRtcCallService.kt functions and handlers for actions as well as lifecycle
* feat: adding more lifecycle vm and callmanager / call service functionality
* feat: adding more command handlers in WebRtcCallService.kt
* feat: more commands handled, adding lock manager and bluetooth permissions
* feat: adding remainder of basic functionality to services and CallManager.kt
* feat: hooking up calls and fixing broken dependencies and compile errors
* fix: add timestamp to incoming call
* feat: some connection and service launching / ring lifecycle
* feat: call establishing and displaying
* fix: fixing call connect flows
* feat: ringers and better state handling
* feat: updating call layout
* feat: add fixes to bluetooth and begin the network renegotiation
* feat: add call related permissions and more network handover tests
* fix: don't display call option in conversation and don't show notification if option not enabled
* fix: incoming ringer fix on receiving call, call notification priorities and notification channel update
* build: update build number for testing
* fix: bluetooth auto-connection and re-connection fixes, removing finished todos, allowing self-send call messages for deduping answers
* feat: add pre-offer information and action handling in web rtc call service
* refactor: discard offer messages from non-matching pre-offers we are already expecting
* build: build numbers and version name update
* feat: handle discarding pending calls from linked devices
* feat: add signing props to release config build
* docs: fix comment on time being 300s (5m) instead of 30s
* feat: adding call messages for incoming/outgoing/missed
* refactor: handle in-thread call notifications better and replace deny button intent with denyCallIntent instead of hangup
* feat: add a hangup via data channel message
* feat: process microphone enabled events and remove debuggable from build.gradle
* feat: add first call notification
* refactor: set the buttons to match iOS in terms of enable disable and colours
* refactor: change the call logos in control messages
* refactor: more bluetooth improvements
* refactor: move start ringer and init of audio manager to CallManager.kt and string fix up
* build: remove debuggable for release build
* refactor: replace call icons
* feat: adding a call time display
* refactor: change the call time to update every second
* refactor: testing out the full screen intents
* refactor: wrapper use corrected session description, set title to recipient displayName, indicate session calls
* fix: crash on view with a parent already attached
* refactor: aspect ratio fit preserved
* refactor: add wantsToAnswer ability in pre-init for fullscreenintent
* refactor: prevent calls from non hasSent participants
* build: update gradle code
* refactor: replace timeout schedule with a seconds count
* fix: various bug fixes for calls
* fix: remove end call from busy
* refactor: use answerCall instead of manual intent building again
* build: new version
* feat: add silenced notifications for call notification builder. check pre-offer and connecting state for pending connection
* build: update build number
* fix: text color uses overridden style value
* fix: remove wrap content for renderers and look more at recovering from network switches
* build: update build number
* refactor: remove whitespace
* build: update build number
* refactor: used shared number for BatchMessageReceiveJob.kt parameter across pollers
* fix: glide in update crash
* fix: bug fixes for self-send answer / hangup messages
* build: update build number
* build: update build.gradle number
* refactor: compile errors and refactoring to view binding
* fix: set the content to binding.root view
* build: increase build number
* build: update build numbers
* feat: adding base for rotation and picking random subset of turn servers
* feat: starting the screen rotation processing
* feat: setting up rotation for the remote render view
* refactor: applying rotation and mirroring based on front / rear cameras that wraps nicely, only scale reworking needed
* refactor: calls video stretching but consistent
* refactor: state machine and tests for the transition events
* feat: new call state processing
* refactor: adding reconnecting logic and visuals
* feat: state machine reconnect logic wip
* feat: add reconnecting and merge fixes
* feat: check new session based off current state
* feat: reconnection logic works correctly now
* refactor: reduce TIMEOUT_SECONDS to 30 from 90
* feat: reset peer connection on DC to prevent ICE messages from old connection or stale state in reconnecting
* refactor: add null case
* fix: set approved on new outgoing threads, use approved more deeply and invalidate the options menu on recipient modified. Add approvedMe flag toggles for visible message receive
* fix: add name update in action bar on modified, change where approvedMe is set
* build: increment build number
* build: update build number
* fix: merge compile errors and increment build number
* refactor: remove negotiation based on which party dropped connection
* refactor: call reconnection improvement tested cross platform to re-establish
* refactor: failed and disconnect events only handled if either the reconnect or the timeout runnables are not set
* build: update version number
* fix: reduce timeout
* fix: fixes the incoming hangup logic for linked devices
* refactor: match iOS styling for call activity closer
* chore: upgrade build numbers
* feat: add in call settings dialog for if calls is disabled in conversation
* feat: add a first call missed control message and info popup with link to privacy settings
* fix: looking at crash for specific large transaction in NotificationManager
* refactor: removing the people in case transaction size reduces to fix notif crash
* fix: comment out the entire send multiple to see if it fixes the issue
* refactor: revert to including the full notification process in a try/catch to handle weird responses from NotificationManager
* fix: add in notification settings prompt for calls and try to fall back to dirty full screen intent / start activity if we're allowed
* build: upgrade build number
2022-04-19 06:25:40 +02:00
|
|
|
sendSingleThreadNotification(context, notificationState, signal, false);
|
|
|
|
} else {
|
|
|
|
cancelActiveNotifications(context);
|
2021-07-30 01:54:16 +02:00
|
|
|
}
|
Add one on one calls over clearnet (#864)
* feat: adding basic webrtc deps and test activity
* more testing code
* feat: add protos and bump version
* feat: added basic call functionality
* feat: adding UI and flipping cameras
* feat: add stats and starting call bottom sheet
* feat: hanging up and bottom sheet behaviors should work now
* feat: add call stats report on frontend
* feat: add relay toggle for answer and offer
* fix: add keep screen on and more end call message on back pressed / on finish
* refactor: removing and replacing dagger 1 dep with android hilt
* feat: include latest proto
* feat: update to utilise call ID
* feat: add stun and turn
* refactor: playing around with deps and transport types
* feat: adding call service functionality and permissions for calls
* feat: add call manager and more static intent building functions for WebRtcCallService.kt
* feat: adding ringers and more audio boilerplate
* feat: audio manager call service boilerplate
* feat: update kotlin and add in call view model and more management functions
* refactor: moving call code around to service and viewmodel interactions
* feat: plugging CallManager.kt into view model and service, fixing up dependencies
* feat: implementing more WebRtcCallService.kt functions and handlers for actions as well as lifecycle
* feat: adding more lifecycle vm and callmanager / call service functionality
* feat: adding more command handlers in WebRtcCallService.kt
* feat: more commands handled, adding lock manager and bluetooth permissions
* feat: adding remainder of basic functionality to services and CallManager.kt
* feat: hooking up calls and fixing broken dependencies and compile errors
* fix: add timestamp to incoming call
* feat: some connection and service launching / ring lifecycle
* feat: call establishing and displaying
* fix: fixing call connect flows
* feat: ringers and better state handling
* feat: updating call layout
* feat: add fixes to bluetooth and begin the network renegotiation
* feat: add call related permissions and more network handover tests
* fix: don't display call option in conversation and don't show notification if option not enabled
* fix: incoming ringer fix on receiving call, call notification priorities and notification channel update
* build: update build number for testing
* fix: bluetooth auto-connection and re-connection fixes, removing finished todos, allowing self-send call messages for deduping answers
* feat: add pre-offer information and action handling in web rtc call service
* refactor: discard offer messages from non-matching pre-offers we are already expecting
* build: build numbers and version name update
* feat: handle discarding pending calls from linked devices
* feat: add signing props to release config build
* docs: fix comment on time being 300s (5m) instead of 30s
* feat: adding call messages for incoming/outgoing/missed
* refactor: handle in-thread call notifications better and replace deny button intent with denyCallIntent instead of hangup
* feat: add a hangup via data channel message
* feat: process microphone enabled events and remove debuggable from build.gradle
* feat: add first call notification
* refactor: set the buttons to match iOS in terms of enable disable and colours
* refactor: change the call logos in control messages
* refactor: more bluetooth improvements
* refactor: move start ringer and init of audio manager to CallManager.kt and string fix up
* build: remove debuggable for release build
* refactor: replace call icons
* feat: adding a call time display
* refactor: change the call time to update every second
* refactor: testing out the full screen intents
* refactor: wrapper use corrected session description, set title to recipient displayName, indicate session calls
* fix: crash on view with a parent already attached
* refactor: aspect ratio fit preserved
* refactor: add wantsToAnswer ability in pre-init for fullscreenintent
* refactor: prevent calls from non hasSent participants
* build: update gradle code
* refactor: replace timeout schedule with a seconds count
* fix: various bug fixes for calls
* fix: remove end call from busy
* refactor: use answerCall instead of manual intent building again
* build: new version
* feat: add silenced notifications for call notification builder. check pre-offer and connecting state for pending connection
* build: update build number
* fix: text color uses overridden style value
* fix: remove wrap content for renderers and look more at recovering from network switches
* build: update build number
* refactor: remove whitespace
* build: update build number
* refactor: used shared number for BatchMessageReceiveJob.kt parameter across pollers
* fix: glide in update crash
* fix: bug fixes for self-send answer / hangup messages
* build: update build number
* build: update build.gradle number
* refactor: compile errors and refactoring to view binding
* fix: set the content to binding.root view
* build: increase build number
* build: update build numbers
* feat: adding base for rotation and picking random subset of turn servers
* feat: starting the screen rotation processing
* feat: setting up rotation for the remote render view
* refactor: applying rotation and mirroring based on front / rear cameras that wraps nicely, only scale reworking needed
* refactor: calls video stretching but consistent
* refactor: state machine and tests for the transition events
* feat: new call state processing
* refactor: adding reconnecting logic and visuals
* feat: state machine reconnect logic wip
* feat: add reconnecting and merge fixes
* feat: check new session based off current state
* feat: reconnection logic works correctly now
* refactor: reduce TIMEOUT_SECONDS to 30 from 90
* feat: reset peer connection on DC to prevent ICE messages from old connection or stale state in reconnecting
* refactor: add null case
* fix: set approved on new outgoing threads, use approved more deeply and invalidate the options menu on recipient modified. Add approvedMe flag toggles for visible message receive
* fix: add name update in action bar on modified, change where approvedMe is set
* build: increment build number
* build: update build number
* fix: merge compile errors and increment build number
* refactor: remove negotiation based on which party dropped connection
* refactor: call reconnection improvement tested cross platform to re-establish
* refactor: failed and disconnect events only handled if either the reconnect or the timeout runnables are not set
* build: update version number
* fix: reduce timeout
* fix: fixes the incoming hangup logic for linked devices
* refactor: match iOS styling for call activity closer
* chore: upgrade build numbers
* feat: add in call settings dialog for if calls is disabled in conversation
* feat: add a first call missed control message and info popup with link to privacy settings
* fix: looking at crash for specific large transaction in NotificationManager
* refactor: removing the people in case transaction size reduces to fix notif crash
* fix: comment out the entire send multiple to see if it fixes the issue
* refactor: revert to including the full notification process in a try/catch to handle weird responses from NotificationManager
* fix: add in notification settings prompt for calls and try to fall back to dirty full screen intent / start activity if we're allowed
* build: upgrade build number
2022-04-19 06:25:40 +02:00
|
|
|
} catch (Exception e) {
|
2022-09-04 13:03:32 +02:00
|
|
|
Log.e(TAG, "Error creating notification", e);
|
2020-06-26 08:17:53 +02:00
|
|
|
}
|
|
|
|
cancelOrphanedNotifications(context, notificationState);
|
|
|
|
updateBadge(context, notificationState.getMessageCount());
|
|
|
|
|
|
|
|
if (signal) {
|
|
|
|
scheduleReminder(context, reminderCount);
|
|
|
|
}
|
|
|
|
} finally {
|
|
|
|
if (telcoCursor != null) telcoCursor.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));
|
2021-08-19 04:14:21 +02:00
|
|
|
String messageIdTag = String.valueOf(notifications.get(0).getTimestamp());
|
2021-07-21 05:58:07 +02:00
|
|
|
|
|
|
|
NotificationManager notificationManager = ServiceUtil.getNotificationManager(context);
|
|
|
|
for (StatusBarNotification notification: notificationManager.getActiveNotifications()) {
|
2021-08-19 04:24:28 +02:00
|
|
|
if ( (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && notification.isAppGroup() == bundled)
|
|
|
|
&& messageIdTag.equals(notification.getNotification().extras.getString(LATEST_MESSAGE_ID_TAG))) {
|
2021-07-21 05:58:07 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
long timestamp = notifications.get(0).getTimestamp();
|
|
|
|
if (timestamp != 0) builder.setWhen(timestamp);
|
2020-06-26 08:17:53 +02:00
|
|
|
|
2021-07-21 05:58:07 +02:00
|
|
|
builder.putStringExtra(LATEST_MESSAGE_ID_TAG, messageIdTag);
|
2020-06-26 08:17:53 +02:00
|
|
|
|
Add one on one calls over clearnet (#864)
* feat: adding basic webrtc deps and test activity
* more testing code
* feat: add protos and bump version
* feat: added basic call functionality
* feat: adding UI and flipping cameras
* feat: add stats and starting call bottom sheet
* feat: hanging up and bottom sheet behaviors should work now
* feat: add call stats report on frontend
* feat: add relay toggle for answer and offer
* fix: add keep screen on and more end call message on back pressed / on finish
* refactor: removing and replacing dagger 1 dep with android hilt
* feat: include latest proto
* feat: update to utilise call ID
* feat: add stun and turn
* refactor: playing around with deps and transport types
* feat: adding call service functionality and permissions for calls
* feat: add call manager and more static intent building functions for WebRtcCallService.kt
* feat: adding ringers and more audio boilerplate
* feat: audio manager call service boilerplate
* feat: update kotlin and add in call view model and more management functions
* refactor: moving call code around to service and viewmodel interactions
* feat: plugging CallManager.kt into view model and service, fixing up dependencies
* feat: implementing more WebRtcCallService.kt functions and handlers for actions as well as lifecycle
* feat: adding more lifecycle vm and callmanager / call service functionality
* feat: adding more command handlers in WebRtcCallService.kt
* feat: more commands handled, adding lock manager and bluetooth permissions
* feat: adding remainder of basic functionality to services and CallManager.kt
* feat: hooking up calls and fixing broken dependencies and compile errors
* fix: add timestamp to incoming call
* feat: some connection and service launching / ring lifecycle
* feat: call establishing and displaying
* fix: fixing call connect flows
* feat: ringers and better state handling
* feat: updating call layout
* feat: add fixes to bluetooth and begin the network renegotiation
* feat: add call related permissions and more network handover tests
* fix: don't display call option in conversation and don't show notification if option not enabled
* fix: incoming ringer fix on receiving call, call notification priorities and notification channel update
* build: update build number for testing
* fix: bluetooth auto-connection and re-connection fixes, removing finished todos, allowing self-send call messages for deduping answers
* feat: add pre-offer information and action handling in web rtc call service
* refactor: discard offer messages from non-matching pre-offers we are already expecting
* build: build numbers and version name update
* feat: handle discarding pending calls from linked devices
* feat: add signing props to release config build
* docs: fix comment on time being 300s (5m) instead of 30s
* feat: adding call messages for incoming/outgoing/missed
* refactor: handle in-thread call notifications better and replace deny button intent with denyCallIntent instead of hangup
* feat: add a hangup via data channel message
* feat: process microphone enabled events and remove debuggable from build.gradle
* feat: add first call notification
* refactor: set the buttons to match iOS in terms of enable disable and colours
* refactor: change the call logos in control messages
* refactor: more bluetooth improvements
* refactor: move start ringer and init of audio manager to CallManager.kt and string fix up
* build: remove debuggable for release build
* refactor: replace call icons
* feat: adding a call time display
* refactor: change the call time to update every second
* refactor: testing out the full screen intents
* refactor: wrapper use corrected session description, set title to recipient displayName, indicate session calls
* fix: crash on view with a parent already attached
* refactor: aspect ratio fit preserved
* refactor: add wantsToAnswer ability in pre-init for fullscreenintent
* refactor: prevent calls from non hasSent participants
* build: update gradle code
* refactor: replace timeout schedule with a seconds count
* fix: various bug fixes for calls
* fix: remove end call from busy
* refactor: use answerCall instead of manual intent building again
* build: new version
* feat: add silenced notifications for call notification builder. check pre-offer and connecting state for pending connection
* build: update build number
* fix: text color uses overridden style value
* fix: remove wrap content for renderers and look more at recovering from network switches
* build: update build number
* refactor: remove whitespace
* build: update build number
* refactor: used shared number for BatchMessageReceiveJob.kt parameter across pollers
* fix: glide in update crash
* fix: bug fixes for self-send answer / hangup messages
* build: update build number
* build: update build.gradle number
* refactor: compile errors and refactoring to view binding
* fix: set the content to binding.root view
* build: increase build number
* build: update build numbers
* feat: adding base for rotation and picking random subset of turn servers
* feat: starting the screen rotation processing
* feat: setting up rotation for the remote render view
* refactor: applying rotation and mirroring based on front / rear cameras that wraps nicely, only scale reworking needed
* refactor: calls video stretching but consistent
* refactor: state machine and tests for the transition events
* feat: new call state processing
* refactor: adding reconnecting logic and visuals
* feat: state machine reconnect logic wip
* feat: add reconnecting and merge fixes
* feat: check new session based off current state
* feat: reconnection logic works correctly now
* refactor: reduce TIMEOUT_SECONDS to 30 from 90
* feat: reset peer connection on DC to prevent ICE messages from old connection or stale state in reconnecting
* refactor: add null case
* fix: set approved on new outgoing threads, use approved more deeply and invalidate the options menu on recipient modified. Add approvedMe flag toggles for visible message receive
* fix: add name update in action bar on modified, change where approvedMe is set
* build: increment build number
* build: update build number
* fix: merge compile errors and increment build number
* refactor: remove negotiation based on which party dropped connection
* refactor: call reconnection improvement tested cross platform to re-establish
* refactor: failed and disconnect events only handled if either the reconnect or the timeout runnables are not set
* build: update version number
* fix: reduce timeout
* fix: fixes the incoming hangup logic for linked devices
* refactor: match iOS styling for call activity closer
* chore: upgrade build numbers
* feat: add in call settings dialog for if calls is disabled in conversation
* feat: add a first call missed control message and info popup with link to privacy settings
* fix: looking at crash for specific large transaction in NotificationManager
* refactor: removing the people in case transaction size reduces to fix notif crash
* fix: comment out the entire send multiple to see if it fixes the issue
* refactor: revert to including the full notification process in a try/catch to handle weird responses from NotificationManager
* fix: add in notification settings prompt for calls and try to fall back to dirty full screen intent / start activity if we're allowed
* build: upgrade build number
2022-04-19 06:25:40 +02:00
|
|
|
CharSequence text = notifications.get(0).getText();
|
|
|
|
|
2020-06-26 08:17:53 +02:00
|
|
|
builder.setThread(notifications.get(0).getRecipient());
|
|
|
|
builder.setMessageCount(notificationState.getMessageCount());
|
2021-07-30 01:54:16 +02:00
|
|
|
MentionManagerUtilities.INSTANCE.populateUserPublicKeyCacheIfNeeded(notifications.get(0).getThreadId(),context);
|
2020-06-26 08:17:53 +02:00
|
|
|
builder.setPrimaryMessageBody(recipient, notifications.get(0).getIndividualRecipient(),
|
2022-07-19 06:31:50 +02:00
|
|
|
MentionUtilities.highlightMentions(text == null ? "" : text,
|
2021-07-30 05:42:39 +02:00
|
|
|
notifications.get(0).getThreadId(),
|
|
|
|
context),
|
2020-08-06 06:42:24 +02:00
|
|
|
notifications.get(0).getSlideDeck());
|
2020-06-26 08:17:53 +02:00
|
|
|
builder.setContentIntent(notifications.get(0).getPendingIntent(context));
|
|
|
|
builder.setDeleteIntent(notificationState.getDeleteIntent(context));
|
|
|
|
builder.setOnlyAlertOnce(!signal);
|
|
|
|
builder.setGroupAlertBehavior(NotificationCompat.GROUP_ALERT_SUMMARY);
|
|
|
|
builder.setAutoCancel(true);
|
|
|
|
|
|
|
|
ReplyMethod replyMethod = ReplyMethod.forRecipient(context, recipient);
|
|
|
|
|
2020-07-15 06:26:20 +02:00
|
|
|
boolean canReply = SessionMetaProtocol.canUserReplyToNotification(recipient);
|
2020-06-26 08:17:53 +02:00
|
|
|
|
|
|
|
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);
|
|
|
|
|
2021-08-19 04:14:21 +02:00
|
|
|
String messageIdTag = String.valueOf(notifications.get(0).getTimestamp());
|
|
|
|
|
|
|
|
NotificationManager notificationManager = ServiceUtil.getNotificationManager(context);
|
|
|
|
for (StatusBarNotification notification: notificationManager.getActiveNotifications()) {
|
|
|
|
if (notification.getId() == SUMMARY_NOTIFICATION_ID
|
|
|
|
&& messageIdTag.equals(notification.getNotification().extras.getString(LATEST_MESSAGE_ID_TAG))) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-26 08:17:53 +02:00
|
|
|
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();
|
2020-08-06 06:42:24 +02:00
|
|
|
builder.addMessageBody(item.getIndividualRecipient(), item.getRecipient(),
|
2021-07-30 05:42:39 +02:00
|
|
|
MentionUtilities.highlightMentions(item.getText(), item.getThreadId(), context));
|
2020-06-26 08:17:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (signal) {
|
|
|
|
builder.setAlarms(notificationState.getRingtone(context), notificationState.getVibrate());
|
|
|
|
builder.setTicker(notifications.get(0).getIndividualRecipient(),
|
2021-07-30 05:42:39 +02:00
|
|
|
MentionUtilities.highlightMentions(notifications.get(0).getText(), notifications.get(0).getThreadId(), context));
|
2020-06-26 08:17:53 +02:00
|
|
|
}
|
|
|
|
|
2021-08-19 04:14:21 +02:00
|
|
|
builder.putStringExtra(LATEST_MESSAGE_ID_TAG, messageIdTag);
|
|
|
|
|
2020-06-26 08:17:53 +02:00
|
|
|
Notification notification = builder.build();
|
Add one on one calls over clearnet (#864)
* feat: adding basic webrtc deps and test activity
* more testing code
* feat: add protos and bump version
* feat: added basic call functionality
* feat: adding UI and flipping cameras
* feat: add stats and starting call bottom sheet
* feat: hanging up and bottom sheet behaviors should work now
* feat: add call stats report on frontend
* feat: add relay toggle for answer and offer
* fix: add keep screen on and more end call message on back pressed / on finish
* refactor: removing and replacing dagger 1 dep with android hilt
* feat: include latest proto
* feat: update to utilise call ID
* feat: add stun and turn
* refactor: playing around with deps and transport types
* feat: adding call service functionality and permissions for calls
* feat: add call manager and more static intent building functions for WebRtcCallService.kt
* feat: adding ringers and more audio boilerplate
* feat: audio manager call service boilerplate
* feat: update kotlin and add in call view model and more management functions
* refactor: moving call code around to service and viewmodel interactions
* feat: plugging CallManager.kt into view model and service, fixing up dependencies
* feat: implementing more WebRtcCallService.kt functions and handlers for actions as well as lifecycle
* feat: adding more lifecycle vm and callmanager / call service functionality
* feat: adding more command handlers in WebRtcCallService.kt
* feat: more commands handled, adding lock manager and bluetooth permissions
* feat: adding remainder of basic functionality to services and CallManager.kt
* feat: hooking up calls and fixing broken dependencies and compile errors
* fix: add timestamp to incoming call
* feat: some connection and service launching / ring lifecycle
* feat: call establishing and displaying
* fix: fixing call connect flows
* feat: ringers and better state handling
* feat: updating call layout
* feat: add fixes to bluetooth and begin the network renegotiation
* feat: add call related permissions and more network handover tests
* fix: don't display call option in conversation and don't show notification if option not enabled
* fix: incoming ringer fix on receiving call, call notification priorities and notification channel update
* build: update build number for testing
* fix: bluetooth auto-connection and re-connection fixes, removing finished todos, allowing self-send call messages for deduping answers
* feat: add pre-offer information and action handling in web rtc call service
* refactor: discard offer messages from non-matching pre-offers we are already expecting
* build: build numbers and version name update
* feat: handle discarding pending calls from linked devices
* feat: add signing props to release config build
* docs: fix comment on time being 300s (5m) instead of 30s
* feat: adding call messages for incoming/outgoing/missed
* refactor: handle in-thread call notifications better and replace deny button intent with denyCallIntent instead of hangup
* feat: add a hangup via data channel message
* feat: process microphone enabled events and remove debuggable from build.gradle
* feat: add first call notification
* refactor: set the buttons to match iOS in terms of enable disable and colours
* refactor: change the call logos in control messages
* refactor: more bluetooth improvements
* refactor: move start ringer and init of audio manager to CallManager.kt and string fix up
* build: remove debuggable for release build
* refactor: replace call icons
* feat: adding a call time display
* refactor: change the call time to update every second
* refactor: testing out the full screen intents
* refactor: wrapper use corrected session description, set title to recipient displayName, indicate session calls
* fix: crash on view with a parent already attached
* refactor: aspect ratio fit preserved
* refactor: add wantsToAnswer ability in pre-init for fullscreenintent
* refactor: prevent calls from non hasSent participants
* build: update gradle code
* refactor: replace timeout schedule with a seconds count
* fix: various bug fixes for calls
* fix: remove end call from busy
* refactor: use answerCall instead of manual intent building again
* build: new version
* feat: add silenced notifications for call notification builder. check pre-offer and connecting state for pending connection
* build: update build number
* fix: text color uses overridden style value
* fix: remove wrap content for renderers and look more at recovering from network switches
* build: update build number
* refactor: remove whitespace
* build: update build number
* refactor: used shared number for BatchMessageReceiveJob.kt parameter across pollers
* fix: glide in update crash
* fix: bug fixes for self-send answer / hangup messages
* build: update build number
* build: update build.gradle number
* refactor: compile errors and refactoring to view binding
* fix: set the content to binding.root view
* build: increase build number
* build: update build numbers
* feat: adding base for rotation and picking random subset of turn servers
* feat: starting the screen rotation processing
* feat: setting up rotation for the remote render view
* refactor: applying rotation and mirroring based on front / rear cameras that wraps nicely, only scale reworking needed
* refactor: calls video stretching but consistent
* refactor: state machine and tests for the transition events
* feat: new call state processing
* refactor: adding reconnecting logic and visuals
* feat: state machine reconnect logic wip
* feat: add reconnecting and merge fixes
* feat: check new session based off current state
* feat: reconnection logic works correctly now
* refactor: reduce TIMEOUT_SECONDS to 30 from 90
* feat: reset peer connection on DC to prevent ICE messages from old connection or stale state in reconnecting
* refactor: add null case
* fix: set approved on new outgoing threads, use approved more deeply and invalidate the options menu on recipient modified. Add approvedMe flag toggles for visible message receive
* fix: add name update in action bar on modified, change where approvedMe is set
* build: increment build number
* build: update build number
* fix: merge compile errors and increment build number
* refactor: remove negotiation based on which party dropped connection
* refactor: call reconnection improvement tested cross platform to re-establish
* refactor: failed and disconnect events only handled if either the reconnect or the timeout runnables are not set
* build: update version number
* fix: reduce timeout
* fix: fixes the incoming hangup logic for linked devices
* refactor: match iOS styling for call activity closer
* chore: upgrade build numbers
* feat: add in call settings dialog for if calls is disabled in conversation
* feat: add a first call missed control message and info popup with link to privacy settings
* fix: looking at crash for specific large transaction in NotificationManager
* refactor: removing the people in case transaction size reduces to fix notif crash
* fix: comment out the entire send multiple to see if it fixes the issue
* refactor: revert to including the full notification process in a try/catch to handle weird responses from NotificationManager
* fix: add in notification settings prompt for calls and try to fall back to dirty full screen intent / start activity if we're allowed
* build: upgrade build number
2022-04-19 06:25:40 +02:00
|
|
|
NotificationManagerCompat.from(context).notify(SUMMARY_NOTIFICATION_ID, notification);
|
|
|
|
Log.i(TAG, "Posted notification. " + notification);
|
2020-06-26 08:17:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
private NotificationState constructNotificationState(@NonNull Context context,
|
|
|
|
@NonNull Cursor cursor)
|
|
|
|
{
|
|
|
|
NotificationState notificationState = new NotificationState();
|
2021-10-04 09:51:19 +02:00
|
|
|
MmsSmsDatabase.Reader reader = DatabaseComponent.get(context).mmsSmsDatabase().readerFor(cursor);
|
2022-03-04 07:46:39 +01:00
|
|
|
ThreadDatabase threadDatabase = DatabaseComponent.get(context).threadDatabase();
|
2022-12-19 01:29:05 +01:00
|
|
|
|
2020-06-26 08:17:53 +02:00
|
|
|
MessageRecord record;
|
2022-08-10 10:17:48 +02:00
|
|
|
Map<Long, String> cache = new HashMap<Long, String>();
|
2020-06-26 08:17:53 +02:00
|
|
|
|
|
|
|
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();
|
2022-03-04 07:46:39 +01:00
|
|
|
boolean messageRequest = false;
|
2020-06-26 08:17:53 +02:00
|
|
|
|
|
|
|
if (threadId != -1) {
|
2022-03-04 07:46:39 +01:00
|
|
|
threadRecipients = threadDatabase.getRecipientForThreadId(threadId);
|
|
|
|
messageRequest = threadRecipients != null && !threadRecipients.isGroupRecipient() &&
|
|
|
|
!threadRecipients.isApproved() && !threadDatabase.getLastSeenAndHasSent(threadId).second();
|
|
|
|
if (messageRequest && (threadDatabase.getMessageCount(threadId) > 1 || !TextSecurePreferences.hasHiddenMessageRequests(context))) {
|
|
|
|
continue;
|
|
|
|
}
|
2020-06-26 08:17:53 +02:00
|
|
|
}
|
2022-03-04 07:46:39 +01:00
|
|
|
if (messageRequest) {
|
|
|
|
body = SpanUtil.italic(context.getString(R.string.message_requests_notification));
|
|
|
|
} else if (KeyCachingService.isLocked(context)) {
|
2020-06-26 08:17:53 +02:00
|
|
|
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()) {
|
|
|
|
slideDeck = ((MediaMmsMessageRecord)record).getSlideDeck();
|
2020-09-03 07:07:59 +02:00
|
|
|
body = SpanUtil.italic(slideDeck.getBody());
|
2020-06-26 08:17:53 +02:00
|
|
|
} else if (record.isMms() && !record.isMmsNotification() && !((MmsMessageRecord) record).getSlideDeck().getSlides().isEmpty()) {
|
2020-09-03 07:07:59 +02:00
|
|
|
slideDeck = ((MediaMmsMessageRecord)record).getSlideDeck();
|
|
|
|
String message = slideDeck.getBody() + ": " + record.getBody();
|
2020-06-26 08:17:53 +02:00
|
|
|
int italicLength = message.length() - body.length();
|
|
|
|
body = SpanUtil.italic(message, italicLength);
|
2021-05-13 07:59:24 +02:00
|
|
|
} else if (record.isOpenGroupInvitation()) {
|
|
|
|
body = SpanUtil.italic(context.getString(R.string.ThreadRecord_open_group_invitation));
|
2020-06-26 08:17:53 +02:00
|
|
|
}
|
2022-09-04 13:03:32 +02:00
|
|
|
String userPublicKey = TextSecurePreferences.getLocalNumber(context);
|
|
|
|
String blindedPublicKey = cache.get(threadId);
|
|
|
|
if (blindedPublicKey == null) {
|
|
|
|
blindedPublicKey = generateBlindedId(threadId, context);
|
|
|
|
cache.put(threadId, blindedPublicKey);
|
|
|
|
}
|
2020-06-26 08:17:53 +02:00
|
|
|
if (threadRecipients == null || !threadRecipients.isMuted()) {
|
2021-07-20 08:06:59 +02:00
|
|
|
if (threadRecipients != null && threadRecipients.notifyType == RecipientDatabase.NOTIFY_TYPE_MENTIONS) {
|
|
|
|
// check if mentioned here
|
2021-07-30 02:30:04 +02:00
|
|
|
boolean isQuoteMentioned = false;
|
|
|
|
if (record instanceof MmsMessageRecord) {
|
|
|
|
Quote quote = ((MmsMessageRecord) record).getQuote();
|
|
|
|
Address quoteAddress = quote != null ? quote.getAuthor() : null;
|
|
|
|
String serializedAddress = quoteAddress != null ? quoteAddress.serialize() : null;
|
2022-08-10 10:17:48 +02:00
|
|
|
isQuoteMentioned = (serializedAddress!= null && Objects.equals(userPublicKey, serializedAddress)) ||
|
|
|
|
(blindedPublicKey != null && Objects.equals(userPublicKey, blindedPublicKey));
|
2021-07-30 02:30:04 +02:00
|
|
|
}
|
2022-08-10 10:17:48 +02:00
|
|
|
if (body.toString().contains("@"+userPublicKey) || body.toString().contains("@"+blindedPublicKey) || isQuoteMentioned) {
|
2021-07-20 08:06:59 +02:00
|
|
|
notificationState.addNotification(new NotificationItem(id, mms, recipient, conversationRecipient, threadRecipients, threadId, body, timestamp, slideDeck));
|
|
|
|
}
|
|
|
|
} else if (threadRecipients != null && threadRecipients.notifyType == RecipientDatabase.NOTIFY_TYPE_NONE) {
|
|
|
|
// do nothing, no notifications
|
|
|
|
} else {
|
|
|
|
notificationState.addNotification(new NotificationItem(id, mms, recipient, conversationRecipient, threadRecipients, threadId, body, timestamp, slideDeck));
|
|
|
|
}
|
2022-09-04 13:03:32 +02:00
|
|
|
|
|
|
|
String userBlindedPublicKey = blindedPublicKey;
|
|
|
|
Optional<ReactionRecord> lastReact = Stream.of(record.getReactions())
|
|
|
|
.filter(r -> !(r.getAuthor().equals(userPublicKey) || r.getAuthor().equals(userBlindedPublicKey)))
|
|
|
|
.findLast();
|
|
|
|
|
|
|
|
if (lastReact.isPresent()) {
|
|
|
|
if (threadRecipients != null && !threadRecipients.isGroupRecipient()) {
|
|
|
|
ReactionRecord reaction = lastReact.get();
|
|
|
|
Recipient reactor = Recipient.from(context, Address.fromSerialized(reaction.getAuthor()), false);
|
|
|
|
String emoji = context.getString(R.string.reaction_notification, reactor.toShortString(), reaction.getEmoji());
|
|
|
|
notificationState.addNotification(new NotificationItem(id, mms, reactor, reactor, threadRecipients, threadId, emoji, reaction.getDateSent(), slideDeck));
|
|
|
|
}
|
|
|
|
}
|
2020-06-26 08:17:53 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
reader.close();
|
|
|
|
return notificationState;
|
|
|
|
}
|
|
|
|
|
2022-08-10 10:17:48 +02:00
|
|
|
private @Nullable String generateBlindedId(long threadId, Context context) {
|
|
|
|
LokiThreadDatabase lokiThreadDatabase = DatabaseComponent.get(context).lokiThreadDatabase();
|
|
|
|
OpenGroup openGroup = lokiThreadDatabase.getOpenGroupChat(threadId);
|
|
|
|
KeyPair edKeyPair = KeyPairUtilities.INSTANCE.getUserED25519KeyPair(context);
|
|
|
|
if (openGroup != null && edKeyPair != null) {
|
2022-09-04 13:03:32 +02:00
|
|
|
KeyPair blindedKeyPair = SodiumUtilities.blindedKeyPair(openGroup.getPublicKey(), edKeyPair);
|
2022-08-10 10:17:48 +02:00
|
|
|
if (blindedKeyPair != null) {
|
|
|
|
return new SessionId(IdPrefix.BLINDED, blindedKeyPair.getPublicKey().getAsBytes()).getHexString();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2020-06-26 08:17:53 +02:00
|
|
|
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);
|
|
|
|
|
2022-12-19 01:29:05 +01:00
|
|
|
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, alarmIntent, PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE);
|
2020-06-26 08:17:53 +02:00
|
|
|
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);
|
2022-12-19 01:29:05 +01:00
|
|
|
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, alarmIntent, PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE);
|
2020-06-26 08:17:53 +02:00
|
|
|
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();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|