Merge pull request #2464 from deltachat/adb/multi-account-notifications

allow notifications for all accounts
This commit is contained in:
Asiel Díaz Benítez
2023-03-13 15:00:24 -04:00
committed by GitHub
10 changed files with 216 additions and 126 deletions
@@ -85,6 +85,7 @@ import org.thoughtcrime.securesms.components.camera.QuickAttachmentDrawer.Attach
import org.thoughtcrime.securesms.components.camera.QuickAttachmentDrawer.DrawerState;
import org.thoughtcrime.securesms.components.emoji.EmojiKeyboardProvider;
import org.thoughtcrime.securesms.components.emoji.MediaKeyboard;
import org.thoughtcrime.securesms.connect.AccountManager;
import org.thoughtcrime.securesms.connect.DcEventCenter;
import org.thoughtcrime.securesms.connect.DcHelper;
import org.thoughtcrime.securesms.connect.DirectShareUtil;
@@ -157,10 +158,11 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
{
private static final String TAG = ConversationActivity.class.getSimpleName();
public static final String CHAT_ID_EXTRA = "chat_id";
public static final String FROM_ARCHIVED_CHATS_EXTRA = "from_archived";
public static final String TEXT_EXTRA = "draft_text";
public static final String STARTING_POSITION_EXTRA = "starting_position";
public static final String ACCOUNT_ID_EXTRA = TAG + ".account_id";
public static final String CHAT_ID_EXTRA = TAG + ".chat_id";
public static final String FROM_ARCHIVED_CHATS_EXTRA = TAG + ".from_archived";
public static final String TEXT_EXTRA = TAG + ".draft_text";
public static final String STARTING_POSITION_EXTRA = TAG + ".starting_position";
private static final int PICK_GALLERY = 1;
private static final int PICK_DOCUMENT = 2;
@@ -203,6 +205,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
private QuickAttachmentDrawer quickAttachmentDrawer;
private InputPanel inputPanel;
private ApplicationContext context;
private Recipient recipient;
private DcContext dcContext;
private DcChat dcChat = new DcChat(0);
@@ -226,7 +229,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
@Override
protected void onCreate(Bundle state, boolean ready) {
final Context context = getApplicationContext();
this.context = ApplicationContext.getInstance(getApplicationContext());
this.dcContext = DcHelper.getContext(context);
supportRequestWindowFeature(WindowCompat.FEATURE_ACTION_BAR_OVERLAY);
@@ -327,7 +330,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
titleView.setTitle(glideRequests, dcChat);
DcHelper.getNotificationCenter(this).updateVisibleChat(chatId);
DcHelper.getNotificationCenter(this).updateVisibleChat(dcContext.getAccountId(), chatId);
if (doReinitializeDraft) {
initializeDraft();
@@ -347,7 +350,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
doReinitializeDraft = true;
}
DcHelper.getNotificationCenter(this).updateVisibleChat(0);
DcHelper.getNotificationCenter(this).clearVisibleChat();
if (isFinishing()) overridePendingTransition(R.anim.fade_scale_in, R.anim.slide_to_right);
quickAttachmentDrawer.onPause();
inputPanel.onPause();
@@ -962,6 +965,12 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
}
private void initializeResources() {
int accountId = getIntent().getIntExtra(ACCOUNT_ID_EXTRA, dcContext.getAccountId());
if (accountId != dcContext.getAccountId()) {
AccountManager.getInstance().switchAccount(context, accountId);
dcContext = context.dcContext;
fragment.dcContext = context.dcContext;
}
chatId = getIntent().getIntExtra(CHAT_ID_EXTRA, -1);
if(chatId == DcChat.DC_CHAT_NO_CHAT)
throw new IllegalStateException("can't display a conversation for no chat.");
@@ -1211,7 +1220,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
if (refreshFragment) {
fragment.reload(recipient, chatId);
DcHelper.getNotificationCenter(this).updateVisibleChat(chatId);
DcHelper.getNotificationCenter(this).updateVisibleChat(dcContext.getAccountId(), chatId);
}
fragment.scrollToBottom();
@@ -76,6 +76,7 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit
private static final String OPENPGP4FPR = "openpgp4fpr";
private static final String NDK_ARCH_WARNED = "ndk_arch_warned";
public static final String CLEAR_NOTIFICATIONS = "clear_notifications";
public static final String ACCOUNT_ID_EXTRA = TAG + ".account_id";
private final DynamicTheme dynamicTheme = new DynamicNoActionBarTheme();
private final DynamicLanguage dynamicLanguage = new DynamicLanguage();
@@ -201,6 +202,15 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit
}
private void refresh() {
DcContext dcContext = DcHelper.getContext(this);
int accountId = getIntent().getIntExtra(ACCOUNT_ID_EXTRA, dcContext.getAccountId());
if (getIntent().getBooleanExtra(CLEAR_NOTIFICATIONS, false)) {
DcHelper.getNotificationCenter(this).removeAllNotifiations(accountId);
}
if (accountId != dcContext.getAccountId()) {
AccountManager.getInstance().switchAccountAndStartActivity(this, accountId, null);
}
refreshAvatar();
refreshTitle();
handleOpenpgp4fpr();
@@ -211,10 +221,6 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit
if (isDirectSharing(this)) {
openConversation(getDirectSharingChatId(this), -1);
}
if (getIntent().getBooleanExtra(CLEAR_NOTIFICATIONS, false)) {
DcHelper.getNotificationCenter(this).removeAllNotifiations();
}
}
public void refreshTitle() {
@@ -350,8 +350,9 @@ public class ConversationListFragment extends Fragment
@Override
protected Void doInBackground(Void... params) {
int accountId = dcContext.getAccountId();
for (long chatId : selectedConversations) {
DcHelper.getNotificationCenter(getContext()).removeNotifications((int) chatId);
DcHelper.getNotificationCenter(getContext()).removeNotifications(accountId, (int) chatId);
dcContext.deleteChat((int) chatId);
DirectShareUtil.clearShortcut(getContext(), (int) chatId);
}
@@ -455,7 +455,7 @@ public class ProfileActivity extends PassphraseRequiredActionBarActivity
}
private void onSoundSettings() {
Uri current = Prefs.getChatRingtone(this, chatId);
Uri current = Prefs.getChatRingtone(this, dcContext.getAccountId(), chatId);
Uri defaultUri = Prefs.getNotificationRingtone(this);
if (current == null) current = Settings.System.DEFAULT_NOTIFICATION_URI;
@@ -472,14 +472,14 @@ public class ProfileActivity extends PassphraseRequiredActionBarActivity
}
private void onVibrateSettings() {
int checkedItem = Prefs.getChatVibrate(this, chatId).getId();
int checkedItem = Prefs.getChatVibrate(this, dcContext.getAccountId(), chatId).getId();
int[] selectedChoice = new int[]{checkedItem};
new AlertDialog.Builder(this)
.setTitle(R.string.pref_vibrate)
.setSingleChoiceItems(R.array.recipient_vibrate_entries, checkedItem,
(dialog, which) -> selectedChoice[0] = which)
.setPositiveButton(R.string.ok,
(dialog, which) -> Prefs.setChatVibrate(this, chatId, Prefs.VibrateState.fromId(selectedChoice[0])))
(dialog, which) -> Prefs.setChatVibrate(this, dcContext.getAccountId(), chatId, Prefs.VibrateState.fromId(selectedChoice[0])))
.setNegativeButton(R.string.cancel, null)
.show();
}
@@ -588,7 +588,7 @@ public class ProfileActivity extends PassphraseRequiredActionBarActivity
if (defaultValue.equals(value)) value = null;
else if (value == null) value = Uri.EMPTY;
Prefs.setChatRingtone(this, chatId, value);
Prefs.setChatRingtone(this, dcContext.getAccountId(), chatId, value);
}
}
@@ -30,10 +30,7 @@ public class AccountManager {
private void resetDcContext(Context context) {
ApplicationContext appContext = (ApplicationContext)context.getApplicationContext();
DcHelper.getNotificationCenter(context).removeAllNotifiations();
appContext.dcContext = appContext.dcAccounts.getSelectedAccount();
appContext.notificationCenter = new NotificationCenter(context);
appContext.eventCenter = new DcEventCenter(context);
DcHelper.setStockTranslations(context);
DirectShareUtil.resetAllShortcuts(appContext);
}
@@ -137,11 +137,22 @@ public class DcEventCenter {
public long handleEvent(@NonNull DcEvent event) {
int accountId = event.getAccountId();
int id = event.getId();
switch (id) {
case DcContext.DC_EVENT_INCOMING_MSG:
DcHelper.getNotificationCenter(context).addNotification(accountId, event.getData1Int(), event.getData2Int());
break;
case DcContext.DC_EVENT_MSGS_NOTICED:
DcHelper.getNotificationCenter(context).removeNotifications(accountId, event.getData1Int());
break;
}
if (accountId != context.dcContext.getAccountId()) {
return 0;
}
int id = event.getId();
switch (id) {
case DcContext.DC_EVENT_INFO:
Log.i("DeltaChat", event.getData2Str());
@@ -160,12 +171,10 @@ public class DcEventCenter {
break;
case DcContext.DC_EVENT_INCOMING_MSG:
DcHelper.getNotificationCenter(context).addNotification(event.getData1Int(), event.getData2Int());
sendToObservers(event);
break;
case DcContext.DC_EVENT_MSGS_NOTICED:
DcHelper.getNotificationCenter(context).removeNotifications(event.getData1Int());
sendToObservers(event);
break;
@@ -10,9 +10,11 @@ import org.thoughtcrime.securesms.connect.DcHelper;
import org.thoughtcrime.securesms.util.Util;
public class MarkReadReceiver extends BroadcastReceiver {
private static final String TAG = MarkReadReceiver.class.getSimpleName();
public static final String MARK_NOTICED_ACTION = "org.thoughtcrime.securesms.notifications.MARK_NOTICED";
public static final String CANCEL_ACTION = "org.thoughtcrime.securesms.notifications.CANCEL";
public static final String CHAT_ID_EXTRA = "chat_id";
public static final String ACCOUNT_ID_EXTRA = TAG + ".account_id";
public static final String CHAT_ID_EXTRA = TAG + ".chat_id";
@Override
public void onReceive(final Context context, Intent intent) {
@@ -21,15 +23,16 @@ public class MarkReadReceiver extends BroadcastReceiver {
return;
}
final int accountId = intent.getIntExtra(ACCOUNT_ID_EXTRA, 0);
final int chatId = intent.getIntExtra(CHAT_ID_EXTRA, 0);
if (chatId==0) {
if (accountId == 0 || chatId == 0) {
return;
}
Util.runOnAnyBackgroundThread(() -> {
DcHelper.getNotificationCenter(context).removeNotifications(chatId);
DcHelper.getNotificationCenter(context).removeNotifications(accountId, chatId);
if (markNoticed) {
DcHelper.getContext(context).marknoticedChat(chatId);
DcHelper.getAccounts(context).getAccount(accountId).marknoticedChat(chatId);
}
});
}
@@ -28,10 +28,10 @@ import com.b44t.messenger.DcContext;
import com.b44t.messenger.DcMsg;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import org.thoughtcrime.securesms.ApplicationContext;
import org.thoughtcrime.securesms.ConversationActivity;
import org.thoughtcrime.securesms.ConversationListActivity;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.connect.DcHelper;
import org.thoughtcrime.securesms.contacts.avatars.ContactPhoto;
import org.thoughtcrime.securesms.mms.GlideApp;
import org.thoughtcrime.securesms.preferences.widgets.NotificationPrivacyPreference;
@@ -50,20 +50,23 @@ import java.util.concurrent.TimeUnit;
public class NotificationCenter {
private static final String TAG = NotificationCenter.class.getSimpleName();
@NonNull private DcContext dcContext;
@NonNull private Context context;
private volatile int visibleChatId = 0;
@NonNull private final ApplicationContext context;
private volatile ChatData visibleChat = null;
private volatile long lastAudibleNotification = 0;
private static final long MIN_AUDIBLE_PERIOD_MILLIS = TimeUnit.SECONDS.toMillis(2);
private final HashMap<Integer, ArrayList<String>> inboxes = new HashMap<>(); // contains the last lines of each chat
// Map<accountId, Map<chatId, lines>, contains the last lines of each chat for each account
private final HashMap<Integer, HashMap<Integer, ArrayList<String>>> inboxes = new HashMap<>();
public NotificationCenter(Context context) {
this.context = context.getApplicationContext();
this.dcContext = DcHelper.getContext(context);
this.context = ApplicationContext.getInstance(context);
}
private @Nullable Uri effectiveSound(int chatId) { // chatId=0: return app-global setting
@Nullable Uri chatRingtone = Prefs.getChatRingtone(context, chatId);
private @Nullable Uri effectiveSound(ChatData chatData) { // chatData=null: return app-global setting
if (chatData == null) {
chatData = new ChatData(0, 0);
}
@Nullable Uri chatRingtone = Prefs.getChatRingtone(context, chatData.accountId, chatData.chatId);
if (chatRingtone!=null) {
return chatRingtone;
} else {
@@ -75,8 +78,11 @@ public class NotificationCenter {
return null;
}
private boolean effectiveVibrate(int chatId) { // chatId=0: return app-global setting
Prefs.VibrateState vibrate = Prefs.getChatVibrate(context, chatId);
private boolean effectiveVibrate(ChatData chatData) { // chatData=null: return app-global setting
if (chatData == null) {
chatData = new ChatData(0, 0);
}
Prefs.VibrateState vibrate = Prefs.getChatVibrate(context, chatData.accountId, chatData.chatId);
if (vibrate == Prefs.VibrateState.ENABLED) {
return true;
} else if (vibrate == Prefs.VibrateState.DISABLED) {
@@ -85,9 +91,12 @@ public class NotificationCenter {
return Prefs.isNotificationVibrateEnabled(context);
}
private boolean requiresIndependentChannel(int chatId) {
return Prefs.getChatRingtone(context, chatId) != null
|| Prefs.getChatVibrate(context, chatId) != Prefs.VibrateState.DEFAULT;
private boolean requiresIndependentChannel(ChatData chatData) {
if (chatData == null) {
chatData = new ChatData(0, 0);
}
return Prefs.getChatRingtone(context, chatData.accountId, chatData.chatId) != null
|| Prefs.getChatVibrate(context, chatData.accountId, chatData.chatId) != Prefs.VibrateState.DEFAULT;
}
private int getLedArgb(String ledColor) {
@@ -101,35 +110,40 @@ public class NotificationCenter {
return argb;
}
private PendingIntent getOpenChatlistIntent() {
private PendingIntent getOpenChatlistIntent(int accountId) {
Intent intent = new Intent(context, ConversationListActivity.class);
intent.putExtra(ConversationListActivity.ACCOUNT_ID_EXTRA, accountId);
intent.putExtra(ConversationListActivity.CLEAR_NOTIFICATIONS, true);
intent.setData(Uri.parse("custom://"+accountId));
return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT | IntentUtils.FLAG_MUTABLE());
}
private PendingIntent getOpenChatIntent(int chatId) {
private PendingIntent getOpenChatIntent(ChatData chatData) {
Intent intent = new Intent(context, ConversationActivity.class);
intent.putExtra(ConversationActivity.CHAT_ID_EXTRA, chatId);
intent.setData((Uri.parse("custom://"+System.currentTimeMillis())));
intent.putExtra(ConversationActivity.ACCOUNT_ID_EXTRA, chatData.accountId);
intent.putExtra(ConversationActivity.CHAT_ID_EXTRA, chatData.chatId);
intent.setData(Uri.parse("custom://"+chatData.accountId+"."+chatData.chatId));
return TaskStackBuilder.create(context)
.addNextIntentWithParentStack(intent)
.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT | IntentUtils.FLAG_MUTABLE());
}
private PendingIntent getRemoteReplyIntent(int chatId) {
private PendingIntent getRemoteReplyIntent(ChatData chatData) {
Intent intent = new Intent(RemoteReplyReceiver.REPLY_ACTION);
intent.setClass(context, RemoteReplyReceiver.class);
intent.setData((Uri.parse("custom://"+System.currentTimeMillis())));
intent.putExtra(RemoteReplyReceiver.CHAT_ID_EXTRA, chatId);
intent.setData(Uri.parse("custom://"+chatData.accountId+"."+chatData.chatId));
intent.putExtra(RemoteReplyReceiver.ACCOUNT_ID_EXTRA, chatData.accountId);
intent.putExtra(RemoteReplyReceiver.CHAT_ID_EXTRA, chatData.chatId);
intent.setPackage(context.getPackageName());
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT | IntentUtils.FLAG_MUTABLE());
}
private PendingIntent getMarkAsReadIntent(int chatId, boolean markNoticed) {
private PendingIntent getMarkAsReadIntent(ChatData chatData, boolean markNoticed) {
Intent intent = new Intent(markNoticed? MarkReadReceiver.MARK_NOTICED_ACTION : MarkReadReceiver.CANCEL_ACTION);
intent.setClass(context, MarkReadReceiver.class);
intent.setData((Uri.parse("custom://"+System.currentTimeMillis())));
intent.putExtra(MarkReadReceiver.CHAT_ID_EXTRA, chatId);
intent.setData(Uri.parse("custom://"+chatData.accountId+"."+chatData.chatId));
intent.putExtra(MarkReadReceiver.ACCOUNT_ID_EXTRA, chatData.accountId);
intent.putExtra(MarkReadReceiver.CHAT_ID_EXTRA, chatData.chatId);
intent.setPackage(context.getPackageName());
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT | IntentUtils.FLAG_MUTABLE());
}
@@ -182,23 +196,19 @@ public class NotificationCenter {
return Build.VERSION.SDK_INT >= 26;
}
// full name is "ch_msgV_HASH" or "ch_msgV_HASH.CHATID"
private String computeChannelId(String ledColor, boolean vibrate, @Nullable Uri ringtone, int chatId) {
// full name is "ch_msgV_HASH" or "ch_msgV_HASH.ACCOUNTID.CHATID"
private String computeChannelId(String ledColor, boolean vibrate, @Nullable Uri ringtone, ChatData chatData) {
String channelId = CH_MSG_PREFIX;
try {
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(ledColor.getBytes());
md.update(vibrate ? (byte) 1 : (byte) 0);
md.update((ringtone != null ? ringtone.toString() : "").getBytes());
if (chatId!=0) {
// for multi-account, force different channelIds for maybe the same chatIds in multiple accounts
md.update(dcContext.getConfig("addr").getBytes());
}
String hash = String.format("%X", new BigInteger(1, md.digest())).substring(0, 16);
channelId = CH_MSG_PREFIX + CH_MSG_VERSION + "_" + hash;
if (chatId!=0) {
channelId += String.format(".%d", chatId);
if (chatData != null) {
channelId += String.format(".%d.%d", chatData.accountId, chatData.chatId);
}
} catch(Exception e) {
@@ -207,15 +217,21 @@ public class NotificationCenter {
return channelId;
}
// return chatId from "ch_msgV_HASH.CHATID" or 0
private int parseNotificationChannelChatId(String channelId) {
// return ChatData(ACCOUNTID, CHATID) from "ch_msgV_HASH.ACCOUNTID.CHATID" or null
private ChatData parseNotificationChannelChat(String channelId) {
try {
int point = channelId.lastIndexOf(".");
if (point>0) {
return Integer.parseInt(channelId.substring(point + 1));
int chatId = Integer.parseInt(channelId.substring(point + 1));
channelId = channelId.substring(0, point);
point = channelId.lastIndexOf(".");
if (point>0) {
int accountId = Integer.parseInt(channelId.substring(point + 1));
return new ChatData(accountId, chatId);
}
}
} catch(Exception e) { }
return 0;
return null;
}
private String getNotificationChannelGroup(NotificationManagerCompat notificationManager) {
@@ -226,20 +242,19 @@ public class NotificationCenter {
return CH_GRP_MSG;
}
private String getNotificationChannel(NotificationManagerCompat notificationManager, DcChat dcChat) {
int chatId = dcChat.getId();
private String getNotificationChannel(NotificationManagerCompat notificationManager, ChatData chatData, DcChat dcChat) {
String channelId = CH_MSG_PREFIX;
if (notificationChannelsSupported()) {
try {
// get all values we'll use as settings for the NotificationChannel
String ledColor = Prefs.getNotificationLedColor(context);
boolean defaultVibrate = effectiveVibrate(chatId);
@Nullable Uri ringtone = effectiveSound(chatId);
boolean isIndependent = requiresIndependentChannel(chatId);
boolean defaultVibrate = effectiveVibrate(chatData);
@Nullable Uri ringtone = effectiveSound(chatData);
boolean isIndependent = requiresIndependentChannel(chatData);
// get channel id from these settings
channelId = computeChannelId(ledColor, defaultVibrate, ringtone, isIndependent? chatId : 0);
channelId = computeChannelId(ledColor, defaultVibrate, ringtone, isIndependent? chatData : null);
// user-visible name of the channel -
// we just use the name of the chat or "Default"
@@ -263,8 +278,8 @@ public class NotificationCenter {
channels.get(i).setName(name);
} else {
// ... another message channel, delete if it is not in use.
int currChatId = parseNotificationChannelChatId(currChannelId);
if (!currChannelId.equals(computeChannelId(ledColor, effectiveVibrate(currChatId), effectiveSound(currChatId), currChatId))) {
ChatData currChat = parseNotificationChannelChat(currChannelId);
if (!currChannelId.equals(computeChannelId(ledColor, effectiveVibrate(currChat), effectiveSound(currChat), currChat))) {
notificationManager.deleteNotificationChannel(currChannelId);
}
}
@@ -311,16 +326,18 @@ public class NotificationCenter {
// add notifications & co.
// --------------------------------------------------------------------------------------------
public void addNotification(int chatId, int msgId) {
public void addNotification(int accountId, int chatId, int msgId) {
Util.runOnAnyBackgroundThread(() -> {
DcContext dcContext = context.dcAccounts.getAccount(accountId);
DcChat dcChat = dcContext.getChat(chatId);
ChatData chatData = new ChatData(accountId, chatId);
if (!Prefs.isNotificationsEnabled(context) || dcChat.isMuted()) {
return;
}
if (chatId == visibleChatId) {
if (Util.equals(visibleChat, chatData)) {
if (Prefs.isInChatNotifications(context)) {
InChatSounds.getInstance(context).playIncomingSound();
}
@@ -349,7 +366,7 @@ public class NotificationCenter {
// even without a name or message displayed,
// it makes sense to use separate notification channels and to open the respective chat directly -
// the user may eg. have chosen a different sound
String notificationChannel = getNotificationChannel(notificationManager, dcChat);
String notificationChannel = getNotificationChannel(notificationManager, chatData, dcChat);
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, notificationChannel)
.setSmallIcon(R.drawable.icon_notification)
.setColor(context.getResources().getColor(R.color.delta_primary))
@@ -357,15 +374,17 @@ public class NotificationCenter {
.setCategory(NotificationCompat.CATEGORY_MESSAGE)
.setOnlyAlertOnce(!signal)
.setContentText(line)
.setDeleteIntent(getMarkAsReadIntent(chatId, false))
.setContentIntent(getOpenChatIntent(chatId));
.setDeleteIntent(getMarkAsReadIntent(chatData, false))
.setContentIntent(getOpenChatIntent(chatData));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
builder.setGroup(GRP_MSG);
builder.setGroup(GRP_MSG + "." + accountId);
}
String accountAddr = dcContext.getConfig("addr");
if (privacy.isDisplayContact()) {
builder.setContentTitle(dcChat.getName());
builder.setSubText(accountAddr);
}
// if privacy allows, for better accessibility,
@@ -379,11 +398,11 @@ public class NotificationCenter {
// set sound, vibrate, led for systems that do not have notification channels
if (!notificationChannelsSupported()) {
if (signal) {
Uri sound = effectiveSound(chatId);
Uri sound = effectiveSound(chatData);
if (sound != null && !TextUtils.isEmpty(sound.toString())) {
builder.setSound(sound);
}
boolean vibrate = effectiveVibrate(chatId);
boolean vibrate = effectiveVibrate(chatData);
if (vibrate) {
builder.setDefaults(Notification.DEFAULT_VIBRATE);
}
@@ -427,8 +446,8 @@ public class NotificationCenter {
if (privacy.isDisplayContact() && privacy.isDisplayMessage()
&& !Prefs.isScreenLockEnabled(context)) {
try {
PendingIntent inNotificationReplyIntent = getRemoteReplyIntent(chatId);
PendingIntent markReadIntent = getMarkAsReadIntent(chatId, true);
PendingIntent inNotificationReplyIntent = getRemoteReplyIntent(chatData);
PendingIntent markReadIntent = getMarkAsReadIntent(chatData, true);
NotificationCompat.Action markAsReadAction = new NotificationCompat.Action(R.drawable.check,
context.getString(R.string.notify_dismiss),
@@ -460,10 +479,15 @@ public class NotificationCenter {
try {
NotificationCompat.InboxStyle inboxStyle = new NotificationCompat.InboxStyle();
synchronized (inboxes) {
ArrayList<String> lines = inboxes.get(chatId);
HashMap<Integer, ArrayList<String>> accountInbox = inboxes.get(accountId);
if (accountInbox == null) {
accountInbox = new HashMap<>();
inboxes.put(accountId, accountInbox);
}
ArrayList<String> lines = accountInbox.get(chatId);
if (lines == null) {
lines = new ArrayList<>();
inboxes.put(chatId, lines);
accountInbox.put(chatId, lines);
}
lines.add(line);
@@ -486,7 +510,7 @@ public class NotificationCenter {
// add notification, we use one notification per chat,
// esp. older android are not that great at grouping
try {
notificationManager.notify(ID_MSG_OFFSET + chatId, builder.build());
notificationManager.notify(String.valueOf(accountId), ID_MSG_OFFSET + chatId, builder.build());
} catch (Exception e) {
Log.e(TAG, "cannot add notification", e);
}
@@ -497,15 +521,18 @@ public class NotificationCenter {
if (Build.VERSION.SDK_INT >= 24) {
try {
NotificationCompat.Builder summary = new NotificationCompat.Builder(context, notificationChannel)
.setGroup(GRP_MSG)
.setGroup(GRP_MSG + "." + accountId)
.setGroupSummary(true)
.setSmallIcon(R.drawable.icon_notification)
.setColor(context.getResources().getColor(R.color.delta_primary))
.setCategory(NotificationCompat.CATEGORY_MESSAGE)
.setContentTitle("Delta Chat") // content title would only be used on SDK <24
.setContentText("New messages") // content text would only be used on SDK <24
.setContentIntent(getOpenChatlistIntent());
notificationManager.notify(ID_MSG_SUMMARY, summary.build());
.setContentIntent(getOpenChatlistIntent(accountId));
if (privacy.isDisplayContact()) {
summary.setSubText(accountAddr);
}
notificationManager.notify(String.valueOf(accountId), ID_MSG_SUMMARY, summary.build());
} catch (Exception e) {
Log.e(TAG, "cannot add notification summary", e);
}
@@ -513,46 +540,83 @@ public class NotificationCenter {
});
}
public void removeNotifications(int chatId) {
public void removeNotifications(int accountId, int chatId) {
boolean removeSummary;
synchronized (inboxes) {
inboxes.remove(chatId);
removeSummary = inboxes.isEmpty();
HashMap<Integer, ArrayList<String>> accountInbox = inboxes.get(accountId);
if (accountInbox == null) {
accountInbox = new HashMap<>();
}
accountInbox.remove(chatId);
removeSummary = accountInbox.isEmpty();
}
// cancel notification independently of inboxes array,
// due to restarts, the app may have notification even when inboxes is empty.
try {
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);
notificationManager.cancel(ID_MSG_OFFSET + chatId);
String tag = String.valueOf(accountId);
notificationManager.cancel(tag, ID_MSG_OFFSET + chatId);
if (removeSummary) {
notificationManager.cancel(ID_MSG_SUMMARY);
notificationManager.cancel(tag, ID_MSG_SUMMARY);
}
} catch (Exception e) { Log.w(TAG, e); }
}
public void removeAllNotifiations() {
synchronized (inboxes) {
inboxes.clear();
}
public void removeAllNotifiations(int accountId) {
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);
notificationManager.cancelAll();
String tag = String.valueOf(accountId);
synchronized (inboxes) {
HashMap<Integer, ArrayList<String>> accountInbox = inboxes.get(accountId);
notificationManager.cancel(tag, ID_MSG_SUMMARY);
if (accountInbox != null) {
for (Integer chatId : accountInbox.keySet()) {
notificationManager.cancel(tag, chatId);
}
accountInbox.clear();
}
}
}
public void updateVisibleChat(int chatId) {
public void updateVisibleChat(int accountId, int chatId) {
Util.runOnAnyBackgroundThread(() -> {
visibleChatId = chatId;
if (chatId!=0) {
removeNotifications(chatId);
if (accountId != 0 && chatId != 0) {
visibleChat = new ChatData(accountId, chatId);
removeNotifications(accountId, chatId);
} else {
visibleChat = null;
}
});
}
public void clearVisibleChat() {
visibleChat = null;
}
public void maybePlaySendSound(DcChat dcChat) {
if (Prefs.isInChatNotifications(context) && Prefs.isNotificationsEnabled(context) && !dcChat.isMuted()) {
InChatSounds.getInstance(context).playSendSound();
}
}
private class ChatData {
public int accountId;
public int chatId;
public ChatData(int accountId, int chatId) {
this.accountId = accountId;
this.chatId = chatId;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ChatData chatData = (ChatData) o;
return accountId == chatData.accountId && chatId == chatData.chatId;
}
}
}
@@ -21,13 +21,13 @@ import android.annotation.SuppressLint;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import androidx.core.app.RemoteInput;
import com.b44t.messenger.DcContext;
import org.thoughtcrime.securesms.connect.DcHelper;
import org.thoughtcrime.securesms.util.Util;
/**
@@ -37,7 +37,8 @@ public class RemoteReplyReceiver extends BroadcastReceiver {
public static final String TAG = RemoteReplyReceiver.class.getSimpleName();
public static final String REPLY_ACTION = "org.thoughtcrime.securesms.notifications.WEAR_REPLY";
public static final String CHAT_ID_EXTRA = "chat_id";
public static final String ACCOUNT_ID_EXTRA = TAG + ".account_id";
public static final String CHAT_ID_EXTRA = TAG + ".chat_id";
public static final String EXTRA_REMOTE_REPLY = "extra_remote_reply";
@SuppressLint("StaticFieldLeak")
@@ -45,26 +46,22 @@ public class RemoteReplyReceiver extends BroadcastReceiver {
public void onReceive(final Context context, Intent intent) {
if (!REPLY_ACTION.equals(intent.getAction())) return;
Bundle remoteInput = RemoteInput.getResultsFromIntent(intent);
final int accountId = intent.getIntExtra(ACCOUNT_ID_EXTRA, 0);
final int chatId = intent.getIntExtra(CHAT_ID_EXTRA, 0);
if (remoteInput == null || chatId == 0) return;
if (remoteInput == null || chatId == 0 || accountId == 0) return;
final CharSequence responseText = remoteInput.getCharSequence(EXTRA_REMOTE_REPLY);
if (responseText != null) {
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
DcContext dcContext = DcHelper.getContext(context);
if (dcContext.getChat(chatId).isContactRequest()) {
dcContext.acceptChat(chatId);
}
dcContext.sendTextMsg(chatId, responseText.toString());
DcHelper.getNotificationCenter(context).removeNotifications(chatId);
return null;
Util.runOnAnyBackgroundThread(() -> {
DcContext dcContext = DcHelper.getAccounts(context).getAccount(accountId);
if (dcContext.getChat(chatId).isContactRequest()) {
dcContext.acceptChat(chatId);
}
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
dcContext.sendTextMsg(chatId, responseText.toString());
DcHelper.getNotificationCenter(context).removeNotifications(accountId, chatId);
});
}
}
}
+14 -10
View File
@@ -225,17 +225,19 @@ public class Prefs {
setStringPreference(context, RINGTONE_PREF, ringtone.toString());
}
public static void setChatRingtone(Context context, int chatId, Uri ringtone) {
public static void setChatRingtone(Context context, int accountId, int chatId, Uri ringtone) {
final String KEY = (accountId != 0 && chatId != 0)? CHAT_RINGTONE+accountId+"."+chatId : CHAT_RINGTONE;
if(ringtone!=null) {
setStringPreference(context, CHAT_RINGTONE+chatId, ringtone.toString());
setStringPreference(context, KEY, ringtone.toString());
}
else {
removePreference(context, CHAT_RINGTONE+chatId);
removePreference(context, KEY);
}
}
public static @Nullable Uri getChatRingtone(Context context, int chatId) {
String result = getStringPreference(context, CHAT_RINGTONE+chatId, null);
public static @Nullable Uri getChatRingtone(Context context, int accountId, int chatId) {
final String KEY = (accountId != 0 && chatId != 0)? CHAT_RINGTONE+accountId+"."+chatId : CHAT_RINGTONE;
String result = getStringPreference(context, KEY, null);
return result==null? null : Uri.parse(result);
}
@@ -254,17 +256,19 @@ public class Prefs {
return getBooleanPreference(context, VIBRATE_PREF, true);
}
public static void setChatVibrate(Context context, int chatId, VibrateState vibrateState) {
public static void setChatVibrate(Context context, int accountId, int chatId, VibrateState vibrateState) {
final String KEY = (accountId != 0 && chatId != 0)? CHAT_VIBRATE+accountId+"."+chatId : CHAT_VIBRATE;
if(vibrateState!=VibrateState.DEFAULT) {
setIntegerPrefrence(context, CHAT_VIBRATE+chatId, vibrateState.getId());
setIntegerPrefrence(context, KEY, vibrateState.getId());
}
else {
removePreference(context, CHAT_VIBRATE+chatId);
removePreference(context, KEY);
}
}
public static VibrateState getChatVibrate(Context context, int chatId) {
return VibrateState.fromId(getIntegerPreference(context, CHAT_VIBRATE+chatId, VibrateState.DEFAULT.getId()));
public static VibrateState getChatVibrate(Context context, int accountId, int chatId) {
final String KEY = (accountId != 0 && chatId != 0)? CHAT_VIBRATE+accountId+"."+chatId : CHAT_VIBRATE;
return VibrateState.fromId(getIntegerPreference(context, KEY, VibrateState.DEFAULT.getId()));
}
// led