mirror of
https://github.com/ArcaneChat/android.git
synced 2026-07-03 14:05:24 +02:00
remove dead code
This commit is contained in:
@@ -1,214 +0,0 @@
|
||||
package org.thoughtcrime.securesms.notifications;
|
||||
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationManager;
|
||||
import android.content.Context;
|
||||
import android.graphics.Color;
|
||||
import android.media.AudioManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.app.NotificationCompat;
|
||||
import android.text.SpannableStringBuilder;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.preferences.widgets.NotificationPrivacyPreference;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.util.Prefs;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.security.MessageDigest;
|
||||
import java.util.List;
|
||||
|
||||
abstract class AbstractNotificationBuilder extends NotificationCompat.Builder {
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static final String TAG = AbstractNotificationBuilder.class.getSimpleName();
|
||||
|
||||
protected Context context;
|
||||
protected NotificationPrivacyPreference privacy;
|
||||
private int notificationId;
|
||||
private Uri ringtone;
|
||||
private boolean vibrate;
|
||||
|
||||
AbstractNotificationBuilder(Context context, NotificationPrivacyPreference privacy) {
|
||||
super(context, createMsgNotificationChannel(context));
|
||||
|
||||
this.context = context;
|
||||
this.privacy = privacy;
|
||||
|
||||
setLed();
|
||||
}
|
||||
|
||||
CharSequence getStyledMessage(@NonNull Recipient recipient, @Nullable CharSequence message) {
|
||||
SpannableStringBuilder builder = new SpannableStringBuilder();
|
||||
builder.append(Util.getBoldedString(recipient.toShortString()));
|
||||
builder.append(": ");
|
||||
builder.append(message == null ? "" : message);
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
// Alarms are not set in the notification or the notification channel but handled separately
|
||||
// by the MessageNotifier. It allows us to dynamically turn on and off the sounds and as well as
|
||||
// to change vibration and sounds during runtime
|
||||
void setAlarms(int systemRingerMode, @Nullable Uri ringtone, Prefs.VibrateState vibrate) {
|
||||
Uri appDefaultRingtone = Prefs.getNotificationRingtone(context);
|
||||
boolean appDefaultVibrate = Prefs.isNotificationVibrateEnabled(context);
|
||||
if (systemRingerMode == AudioManager.RINGER_MODE_NORMAL) {
|
||||
if (ringtone == null && !TextUtils.isEmpty(appDefaultRingtone.toString())) {
|
||||
this.ringtone = appDefaultRingtone;
|
||||
} else if (ringtone != null && !ringtone.toString().isEmpty()) {
|
||||
this.ringtone = ringtone;
|
||||
}
|
||||
}
|
||||
|
||||
this.vibrate = (systemRingerMode != AudioManager.RINGER_MODE_SILENT) &&
|
||||
(vibrate == Prefs.VibrateState.ENABLED ||
|
||||
(vibrate == Prefs.VibrateState.DEFAULT && appDefaultVibrate));
|
||||
}
|
||||
|
||||
private void setLed() {
|
||||
/*
|
||||
String ledColor = Prefs.getNotificationLedColor(context);
|
||||
String ledBlinkPattern = Prefs.getNotificationLedPattern(context);
|
||||
String ledBlinkPatternCustom = Prefs.getNotificationLedPatternCustom(context);
|
||||
|
||||
if (!ledColor.equals("none")) {
|
||||
String[] blinkPatternArray = parseBlinkPattern(ledBlinkPattern, ledBlinkPatternCustom);
|
||||
int argb;
|
||||
try {
|
||||
argb = Color.parseColor(ledColor);
|
||||
}
|
||||
catch (Exception e) {
|
||||
argb = Color.rgb(0xFF, 0xFF, 0xFF);
|
||||
}
|
||||
setLights(argb,
|
||||
Integer.parseInt(blinkPatternArray[0]),
|
||||
Integer.parseInt(blinkPatternArray[1]));
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
void setTicker(@NonNull Recipient recipient, @Nullable CharSequence message) {
|
||||
if (privacy.isDisplayMessage()) {
|
||||
setTicker(getStyledMessage(recipient, message));
|
||||
} else if (privacy.isDisplayContact()) {
|
||||
setTicker(getStyledMessage(recipient, context.getString(R.string.notify_new_message)));
|
||||
} else {
|
||||
setTicker(context.getString(R.string.notify_new_message));
|
||||
}
|
||||
}
|
||||
|
||||
private String[] parseBlinkPattern(String blinkPattern, String blinkPatternCustom) {
|
||||
if (blinkPattern.equals("custom"))
|
||||
blinkPattern = blinkPatternCustom;
|
||||
|
||||
return blinkPattern.split(",");
|
||||
}
|
||||
|
||||
// handle NotificationChannels:
|
||||
// - since oreo, a NotificationChannel is a MUST
|
||||
// - NotificationChannels have default values that have a higher precedence as the Notification.Builder setting
|
||||
// - once created, NotificationChannels cannot be modified programmatically
|
||||
// - NotificationChannels can be deleted, however, on re-creation it becomes un-deleted with the old settings
|
||||
// - the idea is that sound and vibrate are handled outside of the scope of the notification channel
|
||||
|
||||
private static String createMsgNotificationChannel(Context context) {
|
||||
String chBase = "ch_msg3_";
|
||||
String chId = chBase + "unsupported";
|
||||
|
||||
if(notificationChannelsSupported()) {
|
||||
try {
|
||||
NotificationManager notificationManager = context.getSystemService(NotificationManager.class);
|
||||
|
||||
// get all values we'll use as settings for the NotificationChannel
|
||||
String ledColor = Prefs.getNotificationLedColor(context);
|
||||
|
||||
// compute hash from these settings
|
||||
String hash = "";
|
||||
MessageDigest md = MessageDigest.getInstance("SHA-256");
|
||||
md.update(ledColor.getBytes());
|
||||
hash = String.format("%X", new BigInteger(1, md.digest())).substring(0, 16);
|
||||
|
||||
// get channel name
|
||||
chId = chBase + hash;
|
||||
String oldChId = Prefs.getStringPreference(context, "ch_curr_" + chBase, "");
|
||||
if (!oldChId.equals(chId)) {
|
||||
try {
|
||||
notificationManager.deleteNotificationChannel(oldChId);
|
||||
}
|
||||
catch (Exception e) {
|
||||
// channel not created before
|
||||
}
|
||||
Prefs.setStringPreference(context, "ch_curr_" + chBase, chId);
|
||||
}
|
||||
|
||||
// check if there is already a channel with the given name
|
||||
List<NotificationChannel> channels = notificationManager.getNotificationChannels();
|
||||
boolean channelExists = false;
|
||||
for (int i = 0; i < channels.size(); i++) {
|
||||
if (chId.equals(channels.get(i).getId())) {
|
||||
channelExists = true;
|
||||
}
|
||||
}
|
||||
|
||||
// create a channel with the given settings;
|
||||
// we cannot change the settings, however, this is handled by using different values for chId
|
||||
if(!channelExists) {
|
||||
NotificationChannel channel = new NotificationChannel(chId,
|
||||
"New messages", NotificationManager.IMPORTANCE_HIGH);
|
||||
channel.setDescription("Informs about new messages.");
|
||||
|
||||
if (!ledColor.equals("none")) {
|
||||
channel.enableLights(true);
|
||||
int argb;
|
||||
try {
|
||||
argb = Color.parseColor(ledColor);
|
||||
}
|
||||
catch (Exception e) {
|
||||
argb = Color.rgb(0xFF, 0xFF, 0xFF);
|
||||
}
|
||||
channel.setLightColor(argb);
|
||||
} else {
|
||||
channel.enableLights(false);
|
||||
}
|
||||
|
||||
channel.setSound(null, null);
|
||||
channel.enableVibration(false);
|
||||
|
||||
notificationManager.createNotificationChannel(channel);
|
||||
}
|
||||
}
|
||||
catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
return chId;
|
||||
}
|
||||
|
||||
private static boolean notificationChannelsSupported() {
|
||||
return Build.VERSION.SDK_INT >= 26;
|
||||
}
|
||||
|
||||
|
||||
public void setNotificationId(int notificationId) {
|
||||
this.notificationId = notificationId;
|
||||
}
|
||||
|
||||
public int getNotificationId() {
|
||||
return this.notificationId;
|
||||
}
|
||||
|
||||
public Uri getRingtone() {
|
||||
return this.ringtone;
|
||||
}
|
||||
|
||||
public boolean getVibrate() {
|
||||
return this.vibrate;
|
||||
}
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
package org.thoughtcrime.securesms.notifications;
|
||||
|
||||
import android.os.AsyncTask;
|
||||
|
||||
import org.thoughtcrime.securesms.connect.ApplicationDcContext;
|
||||
|
||||
/**
|
||||
* This marks the messages the user has acknowledged as noticed.
|
||||
* @author Angelo Fuchs
|
||||
*/
|
||||
public class MarkAsNoticedAsyncTask extends AsyncTask<Void, Void, Void> {
|
||||
private final int[] ids;
|
||||
private final ApplicationDcContext dcContext;
|
||||
private final boolean isChat;
|
||||
|
||||
/**
|
||||
* goes through the given messages or chats and marks them as notified.
|
||||
* @param ids chat or messages ids to be marked.
|
||||
* @param dcContext the applications context
|
||||
* @param isChat true if the ids are chat ids, false to signify message ids.
|
||||
*/
|
||||
MarkAsNoticedAsyncTask(int[] ids, ApplicationDcContext dcContext, boolean isChat) {
|
||||
this.ids = ids;
|
||||
this.dcContext = dcContext;
|
||||
this.isChat = isChat;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Void doInBackground(Void... params) {
|
||||
for (int id : ids) {
|
||||
if (isChat)
|
||||
dcContext.marknoticedChat(id);
|
||||
else
|
||||
dcContext.marknoticedChat(dcContext.getMsg(id).getChatId());
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,412 +0,0 @@
|
||||
package org.thoughtcrime.securesms.notifications;
|
||||
|
||||
import android.app.NotificationManager;
|
||||
import android.content.Context;
|
||||
import android.media.AudioManager;
|
||||
import android.media.Ringtone;
|
||||
import android.media.RingtoneManager;
|
||||
import android.media.SoundPool;
|
||||
import android.net.Uri;
|
||||
import android.os.Vibrator;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.app.NotificationManagerCompat;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import com.b44t.messenger.DcChat;
|
||||
import com.b44t.messenger.DcContext;
|
||||
import com.b44t.messenger.DcMsg;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.connect.ApplicationDcContext;
|
||||
import org.thoughtcrime.securesms.connect.DcHelper;
|
||||
import org.thoughtcrime.securesms.mms.SlideDeck;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.util.Prefs;
|
||||
import org.thoughtcrime.securesms.util.ServiceUtil;
|
||||
import org.thoughtcrime.securesms.util.SpanUtil;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static org.thoughtcrime.securesms.notifications.MessageNotifierCompat.NO_VISIBLE_CHAT_ID;
|
||||
import static org.thoughtcrime.securesms.notifications.MessageNotifierCompat.SUMMARY_NOTIFICATION_ID;
|
||||
|
||||
abstract class MessageNotifier {
|
||||
|
||||
static final String TAG = org.thoughtcrime.securesms.notifications.MessageNotifierApi23.class.getSimpleName();
|
||||
|
||||
private static final String NOTIFICATION_GROUP = "messages";
|
||||
private static final long MIN_AUDIBLE_PERIOD_MILLIS = TimeUnit.SECONDS.toMillis(20);
|
||||
private static final long STARTUP_SILENCE_DELTA = TimeUnit.MINUTES.toMillis(1);
|
||||
private static final long INITIAL_STARTUP = System.currentTimeMillis();
|
||||
|
||||
static volatile int visibleChatId = NO_VISIBLE_CHAT_ID;
|
||||
static volatile long lastAudibleNotification = -1;
|
||||
final NotificationState notificationState;
|
||||
final Context appContext;
|
||||
final Object lock;
|
||||
private final SoundPool soundPool;
|
||||
private final AudioManager audioManager;
|
||||
private final int soundIn;
|
||||
private final int soundOut;
|
||||
private boolean soundInLoaded;
|
||||
private boolean soundOutLoaded;
|
||||
|
||||
MessageNotifier(Context context) {
|
||||
appContext = context.getApplicationContext();
|
||||
soundPool = new SoundPool(3, AudioManager.STREAM_SYSTEM, 0);
|
||||
audioManager = ServiceUtil.getAudioManager(appContext);
|
||||
soundIn = soundPool.load(context, R.raw.sound_in, 1);
|
||||
soundOut = soundPool.load(context, R.raw.sound_out, 1);
|
||||
notificationState = new NotificationState();
|
||||
lock = new Object();
|
||||
|
||||
soundPool.setOnLoadCompleteListener((soundPool, sampleId, status) -> {
|
||||
if (status == 0) {
|
||||
if (sampleId == soundIn) {
|
||||
soundInLoaded = true;
|
||||
} else if (sampleId == soundOut) {
|
||||
soundOutLoaded = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void playSendSound() {
|
||||
if (Prefs.isInChatNotifications(appContext) && soundOutLoaded) {
|
||||
soundPool.play(soundOut, 1.0f, 1.0f, 1, 0, 1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
public void updateVisibleChat(int chatId) {
|
||||
visibleChatId = chatId;
|
||||
if (visibleChatId != NO_VISIBLE_CHAT_ID) {
|
||||
removeNotifications(visibleChatId);
|
||||
}
|
||||
}
|
||||
|
||||
void updateNotification(int chatId, int messageId) {
|
||||
updateNotification(DcHelper.getContext(appContext).getChat(chatId), messageId);
|
||||
}
|
||||
|
||||
private void updateNotification(DcChat chat, int messageId) {
|
||||
boolean isVisible = visibleChatId == chat.getId();
|
||||
|
||||
if (!Prefs.isNotificationsEnabled(appContext) ||
|
||||
Prefs.isChatMuted(chat))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (isVisible) {
|
||||
sendInChatNotification(chat);
|
||||
} else if (visibleChatId != NO_VISIBLE_CHAT_ID) {
|
||||
//different chat is on top
|
||||
sendNotifications(chat, messageId, false);
|
||||
} else {
|
||||
//app is in background or different Activity is on top
|
||||
sendNotifications(chat, messageId, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* On notification privacy preference changed,
|
||||
* the notification state needs to be updated.
|
||||
*/
|
||||
public void onNotificationPrivacyChanged() {
|
||||
if (!Prefs.isNotificationsEnabled(appContext)) {
|
||||
return;
|
||||
}
|
||||
|
||||
clearNotifications();
|
||||
ApplicationDcContext dcContext = DcHelper.getContext(appContext);
|
||||
int[] freshMessages = dcContext.getFreshMsgs();
|
||||
for (int message : freshMessages) {
|
||||
DcMsg record = dcContext.getMsg(message);
|
||||
updateNotification(dcContext.getChat(record.getChatId()), record.getId());
|
||||
}
|
||||
}
|
||||
|
||||
public void removeNotifications(int[] chatIds) {
|
||||
List<NotificationItem> removedItems = new LinkedList<>();
|
||||
synchronized (lock) {
|
||||
for (int id : chatIds) {
|
||||
removedItems.addAll(notificationState.removeNotificationsForChat(id));
|
||||
}
|
||||
}
|
||||
cancelNotifications(removedItems);
|
||||
recreateSummaryNotification();
|
||||
}
|
||||
|
||||
public void removeNotifications(int chatId) {
|
||||
List<NotificationItem> removedItems;
|
||||
synchronized (lock) {
|
||||
removedItems = notificationState.removeNotificationsForChat(chatId);
|
||||
}
|
||||
cancelNotifications(removedItems);
|
||||
recreateSummaryNotification();
|
||||
}
|
||||
|
||||
void cancelNotifications(List<NotificationItem> removedItems) {
|
||||
NotificationManager notifications = ServiceUtil.getNotificationManager(appContext);
|
||||
for (NotificationItem item : removedItems) {
|
||||
notifications.cancel(item.getId());
|
||||
}
|
||||
}
|
||||
|
||||
private void recreateSummaryNotification() {
|
||||
NotificationManager notifications = ServiceUtil.getNotificationManager(appContext);
|
||||
notifications.cancel(SUMMARY_NOTIFICATION_ID);
|
||||
|
||||
synchronized (lock) {
|
||||
if (notificationState.hasMultipleChats()) {
|
||||
for (Integer id : notificationState.getChats()) {
|
||||
sendSingleChatNotification(appContext, new NotificationState(notificationState.getNotificationsForChat(id)), false, true);
|
||||
}
|
||||
sendMultipleChatNotification(appContext, notificationState, false);
|
||||
} else {
|
||||
sendSingleChatNotification(appContext, notificationState, false, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cancelActiveNotifications() {
|
||||
NotificationManager notifications = ServiceUtil.getNotificationManager(appContext);
|
||||
notifications.cancel(SUMMARY_NOTIFICATION_ID);
|
||||
}
|
||||
|
||||
void sendNotifications(DcChat chat, int messageId, boolean signal) {
|
||||
ApplicationDcContext dcContext = DcHelper.getContext(appContext);
|
||||
if (signal = isSignalAllowed(signal)) {
|
||||
lastAudibleNotification = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
if (chat.isDeviceTalk()) {
|
||||
// currently, we just never notify on device chat.
|
||||
// esp. on first start, this is annoying.
|
||||
return;
|
||||
}
|
||||
|
||||
synchronized (lock) {
|
||||
addMessageToNotificationState(dcContext, chat, messageId);
|
||||
if (notificationState.hasMultipleChats()) {
|
||||
for (int id : notificationState.getChats()) {
|
||||
sendSingleChatNotification(appContext, new NotificationState(notificationState.getNotificationsForChat(id)), false, true);
|
||||
}
|
||||
sendMultipleChatNotification(appContext, notificationState, signal);
|
||||
} else {
|
||||
sendSingleChatNotification(appContext, notificationState, signal, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boolean isSignalAllowed(boolean signalRequested) {
|
||||
long now = System.currentTimeMillis();
|
||||
return signalRequested &&
|
||||
(now - INITIAL_STARTUP) > STARTUP_SILENCE_DELTA &&
|
||||
(now - lastAudibleNotification) > MIN_AUDIBLE_PERIOD_MILLIS;
|
||||
}
|
||||
|
||||
private void clearNotifications() {
|
||||
synchronized (lock) {
|
||||
notificationState.reset();
|
||||
}
|
||||
cancelActiveNotifications();
|
||||
}
|
||||
|
||||
void sendSingleChatNotification(@NonNull Context context,
|
||||
@NonNull NotificationState notificationState,
|
||||
boolean signal,
|
||||
boolean bundled)
|
||||
{
|
||||
AbstractNotificationBuilder notificationBuilder = createSingleChatNotification(context, notificationState, signal, bundled);
|
||||
if (notificationBuilder != null)
|
||||
notify(context, notificationBuilder.getNotificationId(), notificationBuilder, signal);
|
||||
}
|
||||
|
||||
void sendMultipleChatNotification(@NonNull Context context,
|
||||
@NonNull NotificationState notificationState,
|
||||
boolean signal)
|
||||
{
|
||||
AbstractNotificationBuilder notificationBuilder = createMultipleChatNotification(context, notificationState, signal);
|
||||
if (notificationBuilder != null)
|
||||
notify(context, SUMMARY_NOTIFICATION_ID, notificationBuilder, signal);
|
||||
}
|
||||
|
||||
protected AbstractNotificationBuilder createSingleChatNotification(@NonNull Context context,
|
||||
@NonNull NotificationState notificationState,
|
||||
boolean signal,
|
||||
boolean bundled) {
|
||||
if (notificationState.getNotifications().isEmpty()) {
|
||||
if (!bundled) cancelActiveNotifications();
|
||||
return null;
|
||||
}
|
||||
|
||||
SingleRecipientNotificationBuilder builder = new SingleRecipientNotificationBuilder(context, Prefs.getNotificationPrivacy(context));
|
||||
List<NotificationItem> notifications = notificationState.getNotifications();
|
||||
NotificationItem firstItem = notifications.get(0);
|
||||
Recipient recipient = firstItem.getRecipient();
|
||||
int chatId = firstItem.getChatId();
|
||||
int notificationId = (SUMMARY_NOTIFICATION_ID + (bundled ? chatId : 0));
|
||||
|
||||
builder.setNotificationId(notificationId);
|
||||
builder.setChat(firstItem.getRecipient());
|
||||
builder.setMessageCount(notificationState.getMessageCount());
|
||||
builder.setPrimaryMessageBody(recipient, firstItem.getIndividualRecipient(),
|
||||
firstItem.getText(""), firstItem.getSlideDeck());
|
||||
builder.setContentIntent(firstItem.getPendingIntent(context));
|
||||
builder.setGroup(NOTIFICATION_GROUP);
|
||||
builder.setDeleteIntent(notificationState.getMarkAsReadIntent(context, chatId, notificationId));
|
||||
|
||||
long timestamp = firstItem.getTimestamp();
|
||||
if (timestamp != 0) builder.setWhen(timestamp);
|
||||
|
||||
//builder.addActions(notificationState.getMarkAsReadIntent(context, chatId, notificationId),
|
||||
// notificationState.getRemoteReplyIntent(context, recipient));
|
||||
|
||||
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(audioManager.getRingerMode(),
|
||||
notificationState.getRingtone(context),
|
||||
notificationState.getVibrate(context));
|
||||
builder.setTicker(firstItem.getIndividualRecipient(),
|
||||
firstItem.getText());
|
||||
}
|
||||
|
||||
if (!bundled) {
|
||||
builder.setGroupSummary(true);
|
||||
}
|
||||
|
||||
return builder;
|
||||
|
||||
|
||||
}
|
||||
|
||||
private void playNotificationSound(Uri uri, boolean vibrate) {
|
||||
if(uri != null) {
|
||||
Ringtone ringtone = RingtoneManager.getRingtone(appContext, uri);
|
||||
|
||||
if (ringtone != null) {
|
||||
ringtone.play();
|
||||
}
|
||||
} // else we selected "no sound"
|
||||
|
||||
if (vibrate) {
|
||||
Vibrator v = (Vibrator) appContext.getSystemService(Context.VIBRATOR_SERVICE);
|
||||
if (v!=null) {
|
||||
v.vibrate(100);
|
||||
v.vibrate(200);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected AbstractNotificationBuilder createMultipleChatNotification(@NonNull Context context,
|
||||
@NonNull NotificationState notificationState,
|
||||
boolean signal) {
|
||||
MultipleRecipientNotificationBuilder builder = new MultipleRecipientNotificationBuilder(context, Prefs.getNotificationPrivacy(context));
|
||||
List<NotificationItem> notifications = notificationState.getNotifications();
|
||||
NotificationItem firstItem = notifications.get(0);
|
||||
|
||||
builder.setMessageCount(notificationState.getMessageCount(), notificationState.getChatCount());
|
||||
builder.setMostRecentSender(firstItem.getIndividualRecipient());
|
||||
builder.setGroup(NOTIFICATION_GROUP);
|
||||
builder.setDeleteIntent(notificationState.getMarkAsReadIntent(context, 0, SUMMARY_NOTIFICATION_ID));
|
||||
|
||||
long timestamp = firstItem.getTimestamp();
|
||||
if (timestamp != 0) builder.setWhen(timestamp);
|
||||
|
||||
builder.addActions(notificationState.getMarkAsReadIntent(context, 0, SUMMARY_NOTIFICATION_ID));
|
||||
|
||||
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(audioManager.getRingerMode(),
|
||||
notificationState.getRingtone(context),
|
||||
notificationState.getVibrate(context));
|
||||
builder.setTicker(firstItem.getIndividualRecipient(),
|
||||
firstItem.getText());
|
||||
}
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
private void notify(Context context, int notificationId, AbstractNotificationBuilder notificationBuilder, boolean signal) {
|
||||
if (signal) {
|
||||
playNotificationSound(notificationBuilder.getRingtone(), notificationBuilder.getVibrate());
|
||||
}
|
||||
NotificationManagerCompat.from(context).notify(notificationId, notificationBuilder.build());
|
||||
}
|
||||
|
||||
private void sendInChatNotification(DcChat chat) {
|
||||
if (!Prefs.isInChatNotifications(appContext) ||
|
||||
audioManager.getRingerMode() != AudioManager.RINGER_MODE_NORMAL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if(Prefs.isChatMuted(chat)) {
|
||||
Log.d(TAG, "chat muted");
|
||||
return;
|
||||
}
|
||||
|
||||
if (soundInLoaded) {
|
||||
soundPool.play(soundIn, 1.0f, 1.0f, 1, 0, 1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
void addMessageToNotificationState(ApplicationDcContext dcContext, DcChat chat, int msgId) {
|
||||
if (Prefs.isChatMuted(chat)) {
|
||||
return;
|
||||
}
|
||||
|
||||
DcMsg record = dcContext.getMsg(msgId);
|
||||
if (record.isInfo()) {
|
||||
return;
|
||||
}
|
||||
|
||||
int id = record.getId();
|
||||
CharSequence body = record.getDisplayBody();
|
||||
DcMsg dcMsg = dcContext.getMsg(msgId);
|
||||
Recipient chatRecipient = new Recipient(appContext, dcContext.getChat(dcMsg.getChatId()), null);
|
||||
Recipient individualRecipient = new Recipient(appContext, null, dcContext.getContact(dcMsg.getFromId()));
|
||||
SlideDeck slideDeck = new SlideDeck(dcContext.context, record);
|
||||
long timestamp = record.getTimestamp();
|
||||
|
||||
|
||||
if(slideDeck.getSlides().isEmpty())
|
||||
slideDeck = null;
|
||||
|
||||
// TODO: if message content should be hidden on screen lock, do it here.
|
||||
if (record.hasFile() && TextUtils.isEmpty(body)) {
|
||||
String summaryText = record.getSummarytext(100);
|
||||
if (summaryText.isEmpty()) {
|
||||
body = SpanUtil.italic(appContext.getString(R.string.notify_media_message));
|
||||
} else {
|
||||
body = SpanUtil.italic(summaryText);
|
||||
}
|
||||
} else if (record.hasFile() && !record.isMediaPending()) {
|
||||
String message = appContext.getString(R.string.notify_media_message_with_text, body);
|
||||
int italicLength = message.length() - body.length();
|
||||
body = SpanUtil.italic(message, italicLength);
|
||||
}
|
||||
|
||||
synchronized (lock) {
|
||||
notificationState.addNotification(new NotificationItem(id, chatRecipient, individualRecipient, chat.getId(), body, timestamp, slideDeck));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
/*
|
||||
* 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.TargetApi;
|
||||
import android.app.NotificationManager;
|
||||
import android.content.Context;
|
||||
import android.service.notification.StatusBarNotification;
|
||||
import android.util.Log;
|
||||
|
||||
import org.thoughtcrime.securesms.util.ServiceUtil;
|
||||
|
||||
|
||||
/**
|
||||
* Handles posting system notifications for new messages.
|
||||
*
|
||||
*/
|
||||
|
||||
@TargetApi(23)
|
||||
class MessageNotifierApi23 extends MessageNotifier {
|
||||
|
||||
MessageNotifierApi23(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
void cancelActiveNotifications() {
|
||||
super.cancelActiveNotifications();
|
||||
NotificationManager notifications = ServiceUtil.getNotificationManager(appContext);
|
||||
try {
|
||||
|
||||
StatusBarNotification[] activeNotifications = notifications.getActiveNotifications();
|
||||
for (StatusBarNotification activeNotification : activeNotifications) {
|
||||
notifications.cancel(activeNotification.getId());
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
// XXX Appears to be a ROM bug, see #6043
|
||||
Log.w(TAG, e);
|
||||
notifications.cancelAll();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
package org.thoughtcrime.securesms.notifications;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
|
||||
public class MessageNotifierCompat {
|
||||
|
||||
public static final int NO_VISIBLE_CHAT_ID = -1;
|
||||
static final int SUMMARY_NOTIFICATION_ID = 1339;
|
||||
static final String EXTRA_REMOTE_REPLY = "extra_remote_reply";
|
||||
|
||||
|
||||
private static MessageNotifier instance;
|
||||
|
||||
public static void init(Context context) {
|
||||
if (instance != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT < 23) {
|
||||
instance = new MessageNotifierPreApi23(context);
|
||||
} else {
|
||||
instance = new MessageNotifierApi23(context);
|
||||
}
|
||||
}
|
||||
|
||||
public static void playSendSound() {
|
||||
instance.playSendSound();
|
||||
}
|
||||
|
||||
public static void updateNotification(int chatId, int messageId) {
|
||||
Util.runOnAnyBackgroundThread(() -> instance.updateNotification(chatId, messageId));
|
||||
}
|
||||
|
||||
public static void updateVisibleChat(int chatId) {
|
||||
Util.runOnAnyBackgroundThread(() -> instance.updateVisibleChat(chatId));
|
||||
}
|
||||
|
||||
public static void onNotificationPrivacyChanged() {
|
||||
Util.runOnAnyBackgroundThread(() -> instance.onNotificationPrivacyChanged());
|
||||
}
|
||||
|
||||
static void removeNotifications(int[] chatIds) {
|
||||
Util.runOnAnyBackgroundThread(() -> instance.removeNotifications(chatIds));
|
||||
}
|
||||
|
||||
public static void removeNotifications(int chatId) {
|
||||
Util.runOnAnyBackgroundThread(() -> instance.removeNotifications(chatId));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
package org.thoughtcrime.securesms.notifications;
|
||||
|
||||
import android.content.Context;
|
||||
import androidx.core.app.NotificationManagerCompat;
|
||||
|
||||
import com.b44t.messenger.DcChat;
|
||||
|
||||
import org.thoughtcrime.securesms.connect.ApplicationDcContext;
|
||||
import org.thoughtcrime.securesms.connect.DcHelper;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.thoughtcrime.securesms.notifications.MessageNotifierCompat.SUMMARY_NOTIFICATION_ID;
|
||||
|
||||
class MessageNotifierPreApi23 extends MessageNotifier {
|
||||
|
||||
MessageNotifierPreApi23(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeNotifications(int chatId) {
|
||||
synchronized (lock) {
|
||||
notificationState.removeNotificationsForChat(chatId);
|
||||
}
|
||||
recreateSummaryNotification();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeNotifications(int[] chatIds) {
|
||||
synchronized (lock) {
|
||||
for (int id : chatIds) {
|
||||
notificationState.removeNotificationsForChat(id);
|
||||
}
|
||||
}
|
||||
recreateSummaryNotification();
|
||||
}
|
||||
|
||||
@Override
|
||||
void cancelNotifications(List<NotificationItem> removedItems) {
|
||||
cancelNotifications();
|
||||
}
|
||||
|
||||
@Override
|
||||
void sendNotifications(DcChat chat, int messageId, boolean signal) {
|
||||
ApplicationDcContext dcContext = DcHelper.getContext(appContext);
|
||||
if (signal = isSignalAllowed(signal)) {
|
||||
lastAudibleNotification = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
if (chat.isDeviceTalk()) {
|
||||
// currently, we just never notify on device chat.
|
||||
// esp. on first start, this is annoying.
|
||||
return;
|
||||
}
|
||||
|
||||
addMessageToNotificationState(dcContext, chat, messageId);
|
||||
synchronized (lock) {
|
||||
if (notificationState.hasMultipleChats()) {
|
||||
sendMultipleChatNotification(appContext, notificationState, signal);
|
||||
} else {
|
||||
sendSingleChatNotification(appContext, notificationState, signal, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void cancelNotifications() {
|
||||
NotificationManagerCompat notificationManagerCompat = NotificationManagerCompat.from(appContext);
|
||||
notificationManagerCompat.cancel(SUMMARY_NOTIFICATION_ID);
|
||||
}
|
||||
|
||||
private void recreateSummaryNotification() {
|
||||
cancelNotifications();
|
||||
synchronized (lock) {
|
||||
if (notificationState.hasMultipleChats()) {
|
||||
sendMultipleChatNotification(appContext, notificationState, false);
|
||||
} else {
|
||||
sendSingleChatNotification(appContext, notificationState, false, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
-147
@@ -1,147 +0,0 @@
|
||||
package org.thoughtcrime.securesms.notifications;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.app.NotificationCompat;
|
||||
|
||||
import org.thoughtcrime.securesms.ConversationListActivity;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.preferences.widgets.NotificationPrivacyPreference;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.util.Prefs;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class MultipleRecipientNotificationBuilder extends AbstractNotificationBuilder {
|
||||
|
||||
private final LinkedList<MessageBody> messageBodies = new LinkedList<>();
|
||||
|
||||
private static class MessageBody {
|
||||
final @Nullable Recipient group;
|
||||
final @NonNull Recipient sender;
|
||||
final @NonNull CharSequence message;
|
||||
|
||||
MessageBody(@Nullable Recipient group, @NonNull Recipient sender, @NonNull CharSequence message) {
|
||||
this.group = group;
|
||||
this.sender = sender;
|
||||
this.message = message;
|
||||
}
|
||||
}
|
||||
|
||||
MultipleRecipientNotificationBuilder(Context context, NotificationPrivacyPreference privacy) {
|
||||
super(context, privacy);
|
||||
|
||||
setColor(context.getResources().getColor(R.color.delta_primary));
|
||||
setSmallIcon(R.drawable.icon_notification);
|
||||
setContentTitle(context.getString(R.string.app_name));
|
||||
setContentIntent(PendingIntent.getActivity(context, 0, new Intent(context, ConversationListActivity.class), 0));
|
||||
setCategory(NotificationCompat.CATEGORY_MESSAGE);
|
||||
setPriority(Prefs.getNotificationPriority(context));
|
||||
setGroupSummary(true);
|
||||
}
|
||||
|
||||
void setMessageCount(int messageCount, int chatCount) {
|
||||
setSubText(context.getString(R.string.notify_n_messages_in_m_chats,
|
||||
messageCount, chatCount));
|
||||
setContentInfo(String.valueOf(messageCount));
|
||||
setNumber(messageCount); // this also sets badges on android8 and newer
|
||||
}
|
||||
|
||||
void setMostRecentSender(Recipient recipient) {
|
||||
if (privacy.isDisplayContact()) {
|
||||
setContentText(context.getString(R.string.notify_most_recent_from,
|
||||
recipient.toShortString()));
|
||||
}
|
||||
}
|
||||
|
||||
void addActions(PendingIntent markAsReadIntent) {
|
||||
NotificationCompat.Action markAllAsReadAction = new NotificationCompat.Action(R.drawable.check,
|
||||
context.getString(R.string.notify_mark_all_read),
|
||||
markAsReadIntent);
|
||||
addAction(markAllAsReadAction);
|
||||
extend(new NotificationCompat.WearableExtender().addAction(markAllAsReadAction));
|
||||
}
|
||||
|
||||
void addMessageBody(@Nullable Recipient group, @NonNull Recipient sender, @Nullable CharSequence body) {
|
||||
messageBodies.add(new MessageBody(group, sender, body));
|
||||
|
||||
if (privacy.isDisplayContact() && sender.getContactUri() != null) {
|
||||
addPerson(sender.getContactUri().toString());
|
||||
} else if (privacy.isDisplayContact() && group != null && group.getContactUri() != null) {
|
||||
addPerson(group.getContactUri().toString());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Notification build() {
|
||||
if (privacy.isDisplayMessage() || privacy.isDisplayContact()) {
|
||||
NotificationCompat.InboxStyle style = new NotificationCompat.InboxStyle();
|
||||
Map<Recipient, List<MessageBody>> byGroup = new LinkedHashMap<>();
|
||||
for (MessageBody body : messageBodies) {
|
||||
Recipient key = body.group == null ? body.sender : body.group;
|
||||
if(byGroup.containsKey(key)) {
|
||||
LinkedList<MessageBody> messagebodies = (LinkedList<MessageBody>) byGroup.remove(key);
|
||||
messagebodies.addFirst(body);
|
||||
byGroup.put(key, messagebodies);
|
||||
} else {
|
||||
byGroup.put(key, new LinkedList<>());
|
||||
byGroup.get(key).add(body);
|
||||
}
|
||||
}
|
||||
|
||||
if (privacy.isDisplayMessage()) {
|
||||
LinkedList<Recipient> list = new LinkedList<>(byGroup.keySet());
|
||||
Iterator<Recipient> iterator = list.descendingIterator();
|
||||
while(iterator.hasNext()) {
|
||||
Recipient nextGroup = iterator.next();
|
||||
String groupName = nextGroup.getName();
|
||||
List<MessageBody> messages = byGroup.get(nextGroup);
|
||||
String firstMessageSender = messages.get(0).sender.getName();
|
||||
if(groupName != null && groupName.equals(firstMessageSender)) { // individual
|
||||
for (MessageBody body : messages) {
|
||||
style.addLine(getStyledMessage(body.sender, body.message));
|
||||
}
|
||||
} else { // group chat
|
||||
style.addLine(Util.getBoldedString(groupName));
|
||||
for (MessageBody body : messages) {
|
||||
style.addLine("- " + getStyledMessage(body.sender, body.message));
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (privacy.isDisplayContact()) {
|
||||
LinkedList<Recipient> list = new LinkedList<>(byGroup.keySet());
|
||||
Iterator<Recipient> iterator = list.descendingIterator();
|
||||
while(iterator.hasNext()) {
|
||||
Recipient nextGroup = iterator.next();
|
||||
String groupName = nextGroup.getName();
|
||||
List<MessageBody> messages = byGroup.get(nextGroup);
|
||||
String firstMessageSender = messages.get(0).sender.getName();
|
||||
if(groupName != null && groupName.equals(firstMessageSender)) { // individual
|
||||
for (MessageBody body : messages) {
|
||||
style.addLine(body.sender.getName());
|
||||
}
|
||||
} else { // group chat
|
||||
style.addLine(Util.getBoldedString(groupName));
|
||||
for (MessageBody body : messages) {
|
||||
style.addLine("- " + body.sender.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setStyle(style);
|
||||
}
|
||||
|
||||
return super.build();
|
||||
}
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
package org.thoughtcrime.securesms.notifications;
|
||||
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.app.TaskStackBuilder;
|
||||
|
||||
import org.thoughtcrime.securesms.ConversationActivity;
|
||||
import org.thoughtcrime.securesms.mms.SlideDeck;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
|
||||
public class NotificationItem {
|
||||
|
||||
private final int id;
|
||||
private final @NonNull Recipient threadRecipient;
|
||||
private final @NonNull Recipient individualRecipient;
|
||||
private final int chatId;
|
||||
private final @Nullable CharSequence text;
|
||||
private final long timestamp;
|
||||
private final @Nullable SlideDeck slideDeck;
|
||||
|
||||
NotificationItem(int id,
|
||||
@NonNull Recipient threadRecipient,
|
||||
@NonNull Recipient individualRecipient,
|
||||
int chatId, @Nullable CharSequence text, long timestamp,
|
||||
@Nullable SlideDeck slideDeck)
|
||||
{
|
||||
this.id = id;
|
||||
this.threadRecipient = threadRecipient;
|
||||
this.individualRecipient = individualRecipient;
|
||||
this.text = text;
|
||||
this.chatId = chatId;
|
||||
this.timestamp = timestamp;
|
||||
this.slideDeck = slideDeck;
|
||||
}
|
||||
|
||||
public @NonNull Recipient getRecipient() {
|
||||
return threadRecipient;
|
||||
}
|
||||
|
||||
public @Nullable CharSequence getText() {
|
||||
return text;
|
||||
}
|
||||
|
||||
public @NonNull CharSequence getText(@NonNull CharSequence defaul) {
|
||||
return (text == null ? defaul : text);
|
||||
}
|
||||
|
||||
public long getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
public int getChatId() {
|
||||
return chatId;
|
||||
}
|
||||
|
||||
@NonNull Recipient getIndividualRecipient() {
|
||||
return individualRecipient;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public int getThreadId() {
|
||||
return chatId;
|
||||
}
|
||||
|
||||
@Nullable SlideDeck getSlideDeck() {
|
||||
return slideDeck;
|
||||
}
|
||||
|
||||
@NonNull PendingIntent getPendingIntent(Context context) {
|
||||
Intent intent = new Intent(context, ConversationActivity.class);
|
||||
|
||||
intent.putExtra(ConversationActivity.CHAT_ID_EXTRA, chatId);
|
||||
intent.setData((Uri.parse("custom://"+System.currentTimeMillis())));
|
||||
|
||||
return TaskStackBuilder.create(context)
|
||||
.addNextIntentWithParentStack(intent)
|
||||
.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
@@ -1,142 +0,0 @@
|
||||
package org.thoughtcrime.securesms.notifications;
|
||||
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import android.util.Log;
|
||||
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.util.Prefs;
|
||||
import org.thoughtcrime.securesms.util.Prefs.VibrateState;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.thoughtcrime.securesms.notifications.MessageNotifierCompat.SUMMARY_NOTIFICATION_ID;
|
||||
|
||||
public class NotificationState {
|
||||
|
||||
private final LinkedList<NotificationItem> notifications = new LinkedList<>();
|
||||
private final LinkedHashSet<Integer> chats = new LinkedHashSet<>();
|
||||
|
||||
private int notificationCount = 0;
|
||||
|
||||
NotificationState() {}
|
||||
|
||||
NotificationState(@NonNull List<NotificationItem> items) {
|
||||
for (NotificationItem item : items) {
|
||||
addNotification(item);
|
||||
}
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
notificationCount = 0;
|
||||
notifications.clear();
|
||||
chats.clear();
|
||||
}
|
||||
|
||||
void addNotification(NotificationItem item) {
|
||||
notifications.addFirst(item);
|
||||
|
||||
if (chats.contains(item.getChatId())) {
|
||||
chats.remove(item.getChatId());
|
||||
}
|
||||
|
||||
chats.add(item.getChatId());
|
||||
notificationCount++;
|
||||
}
|
||||
|
||||
@Nullable Uri getRingtone(Context context) {
|
||||
if (!notifications.isEmpty()) {
|
||||
Recipient recipient = notifications.iterator().next().getRecipient();
|
||||
if (recipient.getAddress().isDcChat()) {
|
||||
return Prefs.getChatRingtone(context, recipient.getAddress().getDcChatId());
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
VibrateState getVibrate(Context context) {
|
||||
if (!notifications.isEmpty()) {
|
||||
Recipient recipient = notifications.iterator().next().getRecipient();
|
||||
|
||||
if (recipient.getAddress().isDcChat()) {
|
||||
return Prefs.getChatVibrate(context, recipient.getAddress().getDcChatId());
|
||||
}
|
||||
}
|
||||
|
||||
return VibrateState.DEFAULT;
|
||||
}
|
||||
|
||||
boolean hasMultipleChats() {
|
||||
return chats.size() > 1;
|
||||
}
|
||||
|
||||
public LinkedHashSet<Integer> getChats() {
|
||||
return chats;
|
||||
}
|
||||
|
||||
int getChatCount() {
|
||||
return chats.size();
|
||||
}
|
||||
|
||||
int getMessageCount() {
|
||||
return notificationCount;
|
||||
}
|
||||
|
||||
public List<NotificationItem> getNotifications() {
|
||||
return notifications;
|
||||
}
|
||||
|
||||
List<NotificationItem> getNotificationsForChat(int chatId) {
|
||||
LinkedList<NotificationItem> list = new LinkedList<>();
|
||||
|
||||
for (NotificationItem item : notifications) {
|
||||
if (item.getChatId() == chatId) list.addFirst(item);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
List<NotificationItem> removeNotificationsForChat(int chatId) {
|
||||
LinkedList<NotificationItem> removedItems = new LinkedList<>();
|
||||
chats.remove(chatId);
|
||||
for (Iterator<NotificationItem> it = notifications.iterator(); it.hasNext();) {
|
||||
NotificationItem item = it.next();
|
||||
if (item.getChatId() == chatId) {
|
||||
removedItems.add(item);
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
notificationCount -= removedItems.size();
|
||||
return removedItems;
|
||||
}
|
||||
|
||||
PendingIntent getMarkAsReadIntent(Context context, int chatId, int notificationId) {
|
||||
int index = 0;
|
||||
int[] chatArray;
|
||||
if (notificationId == SUMMARY_NOTIFICATION_ID) {
|
||||
chatArray = new int[chats.size()];
|
||||
for (int chat : chats) {
|
||||
Log.w("NotificationState", "Added chat: " + chat);
|
||||
chatArray[index++] = chat;
|
||||
}
|
||||
} else {
|
||||
chatArray = new int[]{chatId};
|
||||
}
|
||||
|
||||
Intent intent = new Intent(MarkReadReceiver.CLEAR_ACTION);
|
||||
intent.setClass(context, MarkReadReceiver.class);
|
||||
intent.setData((Uri.parse("custom://"+System.currentTimeMillis())));
|
||||
//intent.putExtra(MarkReadReceiver.CHAT_IDS_EXTRA, chatArray);
|
||||
//intent.putExtra(MarkReadReceiver.NOTIFICATION_ID_EXTRA, notificationId);
|
||||
|
||||
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
}
|
||||
}
|
||||
@@ -1,250 +0,0 @@
|
||||
package org.thoughtcrime.securesms.notifications;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.app.NotificationCompat;
|
||||
import androidx.core.app.NotificationCompat.Action;
|
||||
import androidx.core.app.RemoteInput;
|
||||
import android.text.SpannableStringBuilder;
|
||||
import android.util.Log;
|
||||
|
||||
import com.bumptech.glide.load.engine.DiskCacheStrategy;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.contacts.avatars.ContactPhoto;
|
||||
import org.thoughtcrime.securesms.contacts.avatars.FallbackContactPhoto;
|
||||
import org.thoughtcrime.securesms.contacts.avatars.GeneratedContactPhoto;
|
||||
import org.thoughtcrime.securesms.mms.DecryptableStreamUriLoader;
|
||||
import org.thoughtcrime.securesms.mms.GlideApp;
|
||||
import org.thoughtcrime.securesms.mms.Slide;
|
||||
import org.thoughtcrime.securesms.mms.SlideDeck;
|
||||
import org.thoughtcrime.securesms.preferences.widgets.NotificationPrivacyPreference;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.util.BitmapUtil;
|
||||
import org.thoughtcrime.securesms.util.Prefs;
|
||||
import org.thoughtcrime.securesms.util.ThemeUtil;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
public class SingleRecipientNotificationBuilder extends AbstractNotificationBuilder {
|
||||
|
||||
private static final String TAG = SingleRecipientNotificationBuilder.class.getSimpleName();
|
||||
|
||||
private final LinkedList<CharSequence> messageBodies = new LinkedList<>();
|
||||
|
||||
private SlideDeck slideDeck;
|
||||
private CharSequence contentTitle;
|
||||
private CharSequence contentText;
|
||||
|
||||
SingleRecipientNotificationBuilder(@NonNull Context context, @NonNull NotificationPrivacyPreference privacy)
|
||||
{
|
||||
super(context, privacy);
|
||||
|
||||
setSmallIcon(R.drawable.icon_notification);
|
||||
setColor(context.getResources().getColor(R.color.delta_primary));
|
||||
setPriority(Prefs.getNotificationPriority(context));
|
||||
setCategory(NotificationCompat.CATEGORY_MESSAGE);
|
||||
}
|
||||
|
||||
public void setChat(@NonNull Recipient recipient) {
|
||||
if (privacy.isDisplayContact()) {
|
||||
setContentTitle(recipient.toShortString());
|
||||
|
||||
if (recipient.getContactUri() != null) {
|
||||
addPerson(recipient.getContactUri().toString());
|
||||
}
|
||||
|
||||
ContactPhoto contactPhoto = recipient.getContactPhoto(context);
|
||||
FallbackContactPhoto fallbackContactPhoto = recipient.getFallbackContactPhoto();
|
||||
|
||||
if (contactPhoto != null) {
|
||||
try {
|
||||
setLargeIcon(GlideApp.with(context.getApplicationContext())
|
||||
.load(contactPhoto)
|
||||
.diskCacheStrategy(DiskCacheStrategy.NONE)
|
||||
.circleCrop()
|
||||
.submit(context.getResources().getDimensionPixelSize(android.R.dimen.notification_large_icon_width),
|
||||
context.getResources().getDimensionPixelSize(android.R.dimen.notification_large_icon_height))
|
||||
.get());
|
||||
} catch (Exception e) {
|
||||
Log.w(TAG, e);
|
||||
setLargeIcon(fallbackContactPhoto.asDrawable(context, recipient.getFallbackAvatarColor(context)));
|
||||
}
|
||||
} else {
|
||||
setLargeIcon(fallbackContactPhoto.asDrawable(context, recipient.getFallbackAvatarColor(context)));
|
||||
}
|
||||
|
||||
} else {
|
||||
setContentTitle(context.getString(R.string.app_name));
|
||||
setLargeIcon(new GeneratedContactPhoto("Unknown").asDrawable(context, ThemeUtil.getDummyContactColor(context)));
|
||||
}
|
||||
}
|
||||
|
||||
public void setMessageCount(int messageCount) {
|
||||
setContentInfo(String.valueOf(messageCount));
|
||||
setNumber(messageCount); // this also sets badges on android8 and newer
|
||||
}
|
||||
|
||||
public void setPrimaryMessageBody(@NonNull Recipient chatRecipients,
|
||||
@NonNull Recipient individualRecipient,
|
||||
@NonNull CharSequence message,
|
||||
@Nullable SlideDeck slideDeck)
|
||||
{
|
||||
SpannableStringBuilder stringBuilder = new SpannableStringBuilder();
|
||||
|
||||
if (privacy.isDisplayContact() && chatRecipients.isGroupRecipient()) {
|
||||
stringBuilder.append(Util.getBoldedString(individualRecipient.toShortString() + ": "));
|
||||
}
|
||||
|
||||
if (privacy.isDisplayMessage()) {
|
||||
setContentText(stringBuilder.append(message));
|
||||
this.slideDeck = slideDeck;
|
||||
} else {
|
||||
setContentText(stringBuilder.append(context.getString(R.string.notify_new_message)));
|
||||
}
|
||||
}
|
||||
|
||||
void addActions(@NonNull PendingIntent markReadIntent,
|
||||
@NonNull PendingIntent inNotificationReplyIntent)
|
||||
{
|
||||
Action markAsReadAction = new Action(R.drawable.check,
|
||||
context.getString(R.string.notify_mark_read),
|
||||
markReadIntent);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
Action replyAction = new Action.Builder(R.drawable.ic_reply_white_36dp,
|
||||
context.getString(R.string.notify_reply_button),
|
||||
inNotificationReplyIntent)
|
||||
.addRemoteInput(new RemoteInput.Builder(MessageNotifierCompat.EXTRA_REMOTE_REPLY)
|
||||
.setLabel(context.getString(R.string.notify_reply_button)).build())
|
||||
.build();
|
||||
addAction(replyAction);
|
||||
}
|
||||
|
||||
Action wearableReplyAction = new Action.Builder(R.drawable.ic_reply,
|
||||
context.getString(R.string.notify_reply_button),
|
||||
inNotificationReplyIntent)
|
||||
.addRemoteInput(new RemoteInput.Builder(MessageNotifierCompat.EXTRA_REMOTE_REPLY)
|
||||
.setLabel(context.getString(R.string.notify_reply_button)).build())
|
||||
.build();
|
||||
|
||||
addAction(markAsReadAction);
|
||||
|
||||
extend(new NotificationCompat.WearableExtender().addAction(markAsReadAction)
|
||||
.addAction(wearableReplyAction));
|
||||
}
|
||||
|
||||
void addMessageBody(@NonNull Recipient chatRecipient,
|
||||
@NonNull Recipient individualRecipient,
|
||||
@Nullable CharSequence messageBody)
|
||||
{
|
||||
SpannableStringBuilder stringBuilder = new SpannableStringBuilder();
|
||||
|
||||
if (privacy.isDisplayContact() && chatRecipient.isGroupRecipient()) {
|
||||
stringBuilder.append(Util.getBoldedString(individualRecipient.toShortString() + ": "));
|
||||
}
|
||||
|
||||
if (privacy.isDisplayMessage()) {
|
||||
messageBodies.addFirst(stringBuilder.append(messageBody == null ? "" : messageBody));
|
||||
} else {
|
||||
messageBodies.addFirst(stringBuilder.append(context.getString(R.string.notify_new_message)));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Notification build() {
|
||||
// the filtering whether or not to display messages and contacts is done in addMessageBody
|
||||
// and setPrimaryMessageBody, no need to do it here again.
|
||||
NotificationCompat.Style style;
|
||||
if (Build.VERSION.SDK_INT < 23) {
|
||||
style = new NotificationCompat.InboxStyle();
|
||||
for (CharSequence messageBody : messageBodies) {
|
||||
((NotificationCompat.InboxStyle) style).addLine(messageBody);
|
||||
}
|
||||
} else if (messageBodies.size() == 1 && hasBigPictureSlide(slideDeck)) {
|
||||
style = new NotificationCompat.BigPictureStyle()
|
||||
.bigPicture(getBigPicture(slideDeck))
|
||||
.setSummaryText(getBigText(messageBodies));
|
||||
} else {
|
||||
style = new NotificationCompat.BigTextStyle().bigText(getBigText(messageBodies));
|
||||
}
|
||||
|
||||
setStyle(style);
|
||||
return super.build();
|
||||
}
|
||||
|
||||
private void setLargeIcon(@Nullable Drawable drawable) {
|
||||
if (drawable != null) {
|
||||
int largeIconTargetSize = context.getResources().getDimensionPixelSize(R.dimen.contact_photo_target_size);
|
||||
Bitmap recipientPhotoBitmap = BitmapUtil.createFromDrawable(drawable, largeIconTargetSize, largeIconTargetSize);
|
||||
|
||||
if (recipientPhotoBitmap != null) {
|
||||
setLargeIcon(recipientPhotoBitmap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasBigPictureSlide(@Nullable SlideDeck slideDeck) {
|
||||
if (slideDeck == null || Build.VERSION.SDK_INT < 16) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Slide thumbnailSlide = slideDeck.getThumbnailSlide();
|
||||
|
||||
return thumbnailSlide != null &&
|
||||
thumbnailSlide.hasImage() &&
|
||||
thumbnailSlide.getThumbnailUri() != null;
|
||||
}
|
||||
|
||||
private Bitmap getBigPicture(@NonNull SlideDeck slideDeck)
|
||||
{
|
||||
try {
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
Uri uri = slideDeck.getThumbnailSlide().getThumbnailUri();
|
||||
|
||||
return GlideApp.with(context.getApplicationContext())
|
||||
.asBitmap()
|
||||
.load(new DecryptableStreamUriLoader.DecryptableUri(uri))
|
||||
.diskCacheStrategy(DiskCacheStrategy.NONE)
|
||||
.submit(500, 500)
|
||||
.get();
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
Log.w(TAG, e);
|
||||
return Bitmap.createBitmap(500, 500, Bitmap.Config.RGB_565);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public NotificationCompat.Builder setContentTitle(CharSequence contentTitle) {
|
||||
this.contentTitle = contentTitle;
|
||||
return super.setContentTitle(contentTitle);
|
||||
}
|
||||
|
||||
public NotificationCompat.Builder setContentText(CharSequence contentText) {
|
||||
this.contentText = contentText;
|
||||
return super.setContentText(contentText);
|
||||
}
|
||||
|
||||
private CharSequence getBigText(List<CharSequence> messageBodies) {
|
||||
SpannableStringBuilder content = new SpannableStringBuilder();
|
||||
|
||||
for (CharSequence message : messageBodies) {
|
||||
content.append(message);
|
||||
content.append('\n');
|
||||
}
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user