diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index ae3b610029..12f1b2c122 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -455,6 +455,9 @@
+
+
{
+ handlePositiveAction(dialog);
+ })
+ .setNegativeButton(android.R.string.cancel, ((dialog, which) -> {
+ dialog.dismiss();
+ finish();
+ }))
+ .show();
+ }
+
+ private void handlePositiveAction(@NonNull DialogInterface dialog) {
+ SimpleTask.run(getLifecycle(), () -> {
+ ThreadDatabase threadDatabase = DatabaseFactory.getThreadDatabase(this);
+
+ List marked = threadDatabase.setRead(getIntent().getLongExtra(EXTRA_THREAD_ID, -1), false);
+ MarkReadReceiver.process(this, marked);
+
+ TextSecurePreferences.setNewContactsNotificationEnabled(this, false);
+ ApplicationDependencies.getMessageNotifier().updateNotification(this);
+
+ return null;
+ }, unused -> {
+ dialog.dismiss();
+ finish();
+ });
+ }
+}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/contacts/sync/DirectoryHelper.java b/app/src/main/java/org/thoughtcrime/securesms/contacts/sync/DirectoryHelper.java
index 116127be86..910a36d304 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/contacts/sync/DirectoryHelper.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/contacts/sync/DirectoryHelper.java
@@ -37,9 +37,9 @@ import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.notifications.NotificationChannels;
import org.thoughtcrime.securesms.permissions.Permissions;
import org.thoughtcrime.securesms.phonenumbers.PhoneNumberFormatter;
-import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.registration.RegistrationUtil;
import org.thoughtcrime.securesms.storage.StorageSyncHelper;
+import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.sms.IncomingJoinedMessage;
import org.thoughtcrime.securesms.util.FeatureFlags;
diff --git a/app/src/main/java/org/thoughtcrime/securesms/notifications/DefaultMessageNotifier.java b/app/src/main/java/org/thoughtcrime/securesms/notifications/DefaultMessageNotifier.java
index 5ae4afac32..7b06e1442f 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/notifications/DefaultMessageNotifier.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/notifications/DefaultMessageNotifier.java
@@ -364,18 +364,25 @@ public class DefaultMessageNotifier implements MessageNotifier {
long timestamp = notifications.get(0).getTimestamp();
if (timestamp != 0) builder.setWhen(timestamp);
+ boolean isSingleNotificationContactJoined = notifications.size() == 1 && notifications.get(0).isJoin();
+
if (!KeyCachingService.isLocked(context) && RecipientUtil.isMessageRequestAccepted(context, recipient.resolve())) {
ReplyMethod replyMethod = ReplyMethod.forRecipient(context, recipient);
builder.addActions(notificationState.getMarkAsReadIntent(context, notificationId),
notificationState.getQuickReplyIntent(context, notifications.get(0).getRecipient()),
notificationState.getRemoteReplyIntent(context, notifications.get(0).getRecipient(), replyMethod),
- replyMethod);
+ replyMethod,
+ !isSingleNotificationContactJoined);
builder.addAndroidAutoAction(notificationState.getAndroidAutoReplyIntent(context, notifications.get(0).getRecipient()),
notificationState.getAndroidAutoHeardIntent(context, notificationId), notifications.get(0).getTimestamp());
}
+ if (!KeyCachingService.isLocked(context) && isSingleNotificationContactJoined) {
+ builder.addTurnOffTheseNotificationsAction(notificationState.getTurnOffTheseNotificationsIntent(context));
+ }
+
ListIterator iterator = notifications.listIterator(notifications.size());
while(iterator.hasPrevious()) {
@@ -538,7 +545,7 @@ public class DefaultMessageNotifier implements MessageNotifier {
}
if (threadRecipients == null || includeMessage) {
- notificationState.addNotification(new NotificationItem(id, mms, recipient, conversationRecipient, threadRecipients, threadId, body, timestamp, receivedTimestamp, slideDeck, false));
+ notificationState.addNotification(new NotificationItem(id, mms, recipient, conversationRecipient, threadRecipients, threadId, body, timestamp, receivedTimestamp, slideDeck, false, record.isJoined()));
}
}
@@ -572,7 +579,7 @@ public class DefaultMessageNotifier implements MessageNotifier {
}
if (threadRecipients == null || !threadRecipients.isMuted()) {
- notificationState.addNotification(new NotificationItem(id, mms, reactionSender, conversationRecipient, threadRecipients, threadId, body, reaction.getDateReceived(), receivedTimestamp, null, true));
+ notificationState.addNotification(new NotificationItem(id, mms, reactionSender, conversationRecipient, threadRecipients, threadId, body, reaction.getDateReceived(), receivedTimestamp, null, true, record.isJoined()));
}
}
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/notifications/NotificationItem.java b/app/src/main/java/org/thoughtcrime/securesms/notifications/NotificationItem.java
index 96d26067d4..e8e417c604 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/notifications/NotificationItem.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/notifications/NotificationItem.java
@@ -27,6 +27,7 @@ public class NotificationItem {
private final long messageReceivedTimestamp;
@Nullable private final SlideDeck slideDeck;
private final boolean jumpToMessage;
+ private final boolean isJoin;
public NotificationItem(long id,
boolean mms,
@@ -38,7 +39,8 @@ public class NotificationItem {
long notificationTimestamp,
long messageReceivedTimestamp,
@Nullable SlideDeck slideDeck,
- boolean jumpToMessage)
+ boolean jumpToMessage,
+ boolean isJoin)
{
this.id = id;
this.mms = mms;
@@ -51,6 +53,7 @@ public class NotificationItem {
this.messageReceivedTimestamp = messageReceivedTimestamp;
this.slideDeck = slideDeck;
this.jumpToMessage = jumpToMessage;
+ this.isJoin = isJoin;
}
public @NonNull Recipient getRecipient() {
@@ -98,6 +101,10 @@ public class NotificationItem {
return mms;
}
+ public boolean isJoin() {
+ return isJoin;
+ }
+
private static int getStartingPosition(@NonNull Context context, long threadId, long receivedTimestampMs) {
return DatabaseFactory.getMmsSmsDatabase(context).getMessagePositionInConversation(threadId, receivedTimestampMs);
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/notifications/NotificationState.java b/app/src/main/java/org/thoughtcrime/securesms/notifications/NotificationState.java
index a060db9f9d..df20bfc631 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/notifications/NotificationState.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/notifications/NotificationState.java
@@ -8,6 +8,7 @@ import android.net.Uri;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import org.thoughtcrime.securesms.contacts.TurnOffContactJoinedNotificationsActivity;
import org.thoughtcrime.securesms.conversation.ConversationActivity;
import org.thoughtcrime.securesms.conversation.ConversationPopupActivity;
import org.thoughtcrime.securesms.database.RecipientDatabase.VibrateState;
@@ -101,6 +102,15 @@ public class NotificationState {
return list;
}
+ public PendingIntent getTurnOffTheseNotificationsIntent(Context context) {
+ long threadId = threads.iterator().next();
+
+ return PendingIntent.getActivity(context,
+ 0,
+ TurnOffContactJoinedNotificationsActivity.newIntent(context, threadId),
+ PendingIntent.FLAG_UPDATE_CURRENT);
+ }
+
public PendingIntent getMarkAsReadIntent(Context context, int notificationId) {
long[] threadArray = new long[threads.size()];
int index = 0;
diff --git a/app/src/main/java/org/thoughtcrime/securesms/notifications/SingleRecipientNotificationBuilder.java b/app/src/main/java/org/thoughtcrime/securesms/notifications/SingleRecipientNotificationBuilder.java
index 35009941d2..765103ee56 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/notifications/SingleRecipientNotificationBuilder.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/notifications/SingleRecipientNotificationBuilder.java
@@ -7,6 +7,8 @@ import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Build;
+import android.text.SpannableStringBuilder;
+
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
@@ -17,8 +19,6 @@ import androidx.core.app.Person;
import androidx.core.app.RemoteInput;
import androidx.core.graphics.drawable.IconCompat;
-import android.text.SpannableStringBuilder;
-
import com.annimon.stream.Stream;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
@@ -156,43 +156,57 @@ public class SingleRecipientNotificationBuilder extends AbstractNotificationBuil
extend(new NotificationCompat.CarExtender().setUnreadConversation(unreadConversationBuilder.build()));
}
+ public void addTurnOffTheseNotificationsAction(@NonNull PendingIntent turnOffTheseNotificationsIntent) {
+ Action turnOffTheseNotifications = new Action(R.drawable.check,
+ context.getString(R.string.MessageNotifier_turn_off_these_notifications),
+ turnOffTheseNotificationsIntent);
+
+ addAction(turnOffTheseNotifications);
+ }
+
public void addActions(@NonNull PendingIntent markReadIntent,
@NonNull PendingIntent quickReplyIntent,
@NonNull PendingIntent wearableReplyIntent,
- @NonNull ReplyMethod replyMethod)
+ @NonNull ReplyMethod replyMethod,
+ boolean replyEnabled)
{
- Action markAsReadAction = new Action(R.drawable.check,
- context.getString(R.string.MessageNotifier_mark_read),
- markReadIntent);
-
- String actionName = context.getString(R.string.MessageNotifier_reply);
- String label = context.getString(replyMethodLongDescription(replyMethod));
-
- Action replyAction = new Action(R.drawable.ic_reply_white_36dp,
- actionName,
- quickReplyIntent);
-
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
- replyAction = new Action.Builder(R.drawable.ic_reply_white_36dp,
- actionName,
- wearableReplyIntent)
- .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(DefaultMessageNotifier.EXTRA_REMOTE_REPLY)
- .setLabel(label).build())
- .build();
+ NotificationCompat.WearableExtender extender = new NotificationCompat.WearableExtender();
+ Action markAsReadAction = new Action(R.drawable.check,
+ context.getString(R.string.MessageNotifier_mark_read),
+ markReadIntent);
addAction(markAsReadAction);
- addAction(replyAction);
+ extender.addAction(markAsReadAction);
- extend(new NotificationCompat.WearableExtender().addAction(markAsReadAction)
- .addAction(wearableReplyAction));
+ if (replyEnabled) {
+ String actionName = context.getString(R.string.MessageNotifier_reply);
+ String label = context.getString(replyMethodLongDescription(replyMethod));
+
+ Action replyAction = new Action(R.drawable.ic_reply_white_36dp,
+ actionName,
+ quickReplyIntent);
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+ replyAction = new Action.Builder(R.drawable.ic_reply_white_36dp,
+ actionName,
+ wearableReplyIntent)
+ .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(DefaultMessageNotifier.EXTRA_REMOTE_REPLY)
+ .setLabel(label)
+ .build())
+ .build();
+
+ addAction(replyAction);
+ extend(extender.addAction(wearableReplyAction));
+ }
}
@StringRes
diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/TextSecurePreferences.java b/app/src/main/java/org/thoughtcrime/securesms/util/TextSecurePreferences.java
index 969f146b6a..73fd549b89 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/util/TextSecurePreferences.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/util/TextSecurePreferences.java
@@ -492,6 +492,10 @@ public class TextSecurePreferences {
return new NotificationPrivacyPreference(getStringPreference(context, NOTIFICATION_PRIVACY_PREF, "all"));
}
+ public static void setNewContactsNotificationEnabled(Context context, boolean isEnabled) {
+ setBooleanPreference(context, NEW_CONTACTS_NOTIFICATIONS, isEnabled);
+ }
+
public static boolean isNewContactsNotificationEnabled(Context context) {
return getBooleanPreference(context, NEW_CONTACTS_NOTIFICATIONS, true);
}
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 7060828d3d..8f82851a63 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -1340,6 +1340,7 @@
Error delivering message.
Mark all as read
Mark read
+ Turn off these notifications
Media message
Sticker
View-once photo
@@ -1361,6 +1362,8 @@
Reacted %1$s to your sticker.
This message was deleted.
+ Turn off contact joined Signal notifications? You can enable them again in Signal > Settings > Notifications.
+
Default
Calls