mirror of
https://github.com/ArcaneChat/android.git
synced 2026-07-03 14:05:24 +02:00
Merge pull request #2464 from deltachat/adb/multi-account-notifications
allow notifications for all accounts
This commit is contained in:
@@ -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);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user