diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index cdaa85d8e0..e07e098efe 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -288,7 +288,12 @@
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
+ android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize">
+
+
+
+
+
Contact
- Messages
+ Default
Calls
Failures
Backups
Lock status
App updates
Other
+ Messages
Quick response unavailable when Signal is locked!
@@ -960,6 +961,8 @@
Mute conversation
+ Custom notifications
+ System notification settings
Notification sound
Vibrate
Block
@@ -1086,6 +1089,7 @@
Inactivity timeout passphrase
Inactivity timeout interval
Notifications
+ System notification settings
LED color
Unknown
LED blink pattern
diff --git a/res/xml/preferences_notifications.xml b/res/xml/preferences_notifications.xml
index 1fa08efe50..b53048beb7 100644
--- a/res/xml/preferences_notifications.xml
+++ b/res/xml/preferences_notifications.xml
@@ -9,6 +9,12 @@
android:title="@string/preferences__notifications"
android:defaultValue="true" />
+
+
+
+
+
+
() {
+ @Override
+ protected Void doInBackground(Void... params) {
+ if (enabled) {
+ String channel = NotificationChannels.createChannelFor(getActivity(), recipient);
+ DatabaseFactory.getRecipientDatabase(getActivity()).setNotificationChannel(recipient, channel);
+ } else {
+ NotificationChannels.deleteChannelFor(getActivity(), recipient);
+ DatabaseFactory.getRecipientDatabase(getActivity()).setNotificationChannel(recipient, null);
+ }
+ return null;
+ }
+ }.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
+
+ return true;
+ }
+ }
+
+ private class NotificationSettingsClickedListener implements Preference.OnPreferenceClickListener {
+
+ @Override
+ public boolean onPreferenceClick(Preference preference) {
+ NotificationChannels.openChannelSettings(getActivity(), recipient.getNotificationChannel(getActivity()));
+ return true;
+ }
+ }
}
}
diff --git a/src/org/thoughtcrime/securesms/database/RecipientDatabase.java b/src/org/thoughtcrime/securesms/database/RecipientDatabase.java
index 3b1fd26f07..dbafebcc52 100644
--- a/src/org/thoughtcrime/securesms/database/RecipientDatabase.java
+++ b/src/org/thoughtcrime/securesms/database/RecipientDatabase.java
@@ -19,6 +19,7 @@ import org.thoughtcrime.securesms.util.Base64;
import org.thoughtcrime.securesms.util.Util;
import org.whispersystems.libsignal.util.guava.Optional;
+import java.io.Closeable;
import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
@@ -53,11 +54,12 @@ public class RecipientDatabase extends Database {
private static final String PROFILE_SHARING = "profile_sharing_approval";
private static final String CALL_RINGTONE = "call_ringtone";
private static final String CALL_VIBRATE = "call_vibrate";
+ private static final String NOTIFICATION_CHANNEL = "notification_channel";
private static final String[] RECIPIENT_PROJECTION = new String[] {
BLOCK, NOTIFICATION, CALL_RINGTONE, VIBRATE, CALL_VIBRATE, MUTE_UNTIL, COLOR, SEEN_INVITE_REMINDER, DEFAULT_SUBSCRIPTION_ID, EXPIRE_MESSAGES, REGISTERED,
PROFILE_KEY, SYSTEM_DISPLAY_NAME, SYSTEM_PHOTO_URI, SYSTEM_PHONE_LABEL, SYSTEM_CONTACT_URI,
- SIGNAL_PROFILE_NAME, SIGNAL_PROFILE_AVATAR, PROFILE_SHARING
+ SIGNAL_PROFILE_NAME, SIGNAL_PROFILE_AVATAR, PROFILE_SHARING, NOTIFICATION_CHANNEL
};
static final List TYPED_RECIPIENT_PROJECTION = Stream.of(RECIPIENT_PROJECTION)
@@ -122,7 +124,8 @@ public class RecipientDatabase extends Database {
SIGNAL_PROFILE_AVATAR + " TEXT DEFAULT NULL, " +
PROFILE_SHARING + " INTEGER DEFAULT 0, " +
CALL_RINGTONE + " TEXT DEFAULT NULL, " +
- CALL_VIBRATE + " INTEGER DEFAULT " + VibrateState.DEFAULT.getId() + ");";
+ CALL_VIBRATE + " INTEGER DEFAULT " + VibrateState.DEFAULT.getId() + ", " +
+ NOTIFICATION_CHANNEL + " TEXT DEFAULT NULL);";
public RecipientDatabase(Context context, SQLCipherOpenHelper databaseHelper) {
super(context, databaseHelper);
@@ -135,8 +138,16 @@ public class RecipientDatabase extends Database {
null, null, null, null, null);
}
- public BlockedReader readerForBlocked(Cursor cursor) {
- return new BlockedReader(context, cursor);
+ public RecipientReader readerForBlocked(Cursor cursor) {
+ return new RecipientReader(context, cursor);
+ }
+
+ public RecipientReader getRecipientsWithNotificationChannels() {
+ SQLiteDatabase database = databaseHelper.getReadableDatabase();
+ Cursor cursor = database.query(TABLE_NAME, new String[] {ID, ADDRESS}, NOTIFICATION_CHANNEL + " NOT NULL",
+ null, null, null, null, null);
+
+ return new RecipientReader(context, cursor);
}
@@ -177,6 +188,7 @@ public class RecipientDatabase extends Database {
String signalProfileName = cursor.getString(cursor.getColumnIndexOrThrow(SIGNAL_PROFILE_NAME));
String signalProfileAvatar = cursor.getString(cursor.getColumnIndexOrThrow(SIGNAL_PROFILE_AVATAR));
boolean profileSharing = cursor.getInt(cursor.getColumnIndexOrThrow(PROFILE_SHARING)) == 1;
+ String notificationChannel = cursor.getString(cursor.getColumnIndexOrThrow(NOTIFICATION_CHANNEL));
MaterialColor color;
byte[] profileKey = null;
@@ -206,7 +218,8 @@ public class RecipientDatabase extends Database {
RegisteredState.fromId(registeredState),
profileKey, systemDisplayName, systemContactPhoto,
systemPhoneLabel, systemContactUri,
- signalProfileName, signalProfileAvatar, profileSharing));
+ signalProfileName, signalProfileAvatar, profileSharing,
+ notificationChannel));
}
public BulkOperationsHandle resetAllSystemContactInfo() {
@@ -324,6 +337,22 @@ public class RecipientDatabase extends Database {
recipient.setProfileSharing(enabled);
}
+ public void setNotificationChannel(@NonNull Recipient recipient, @Nullable String notificationChannel) {
+ ContentValues contentValues = new ContentValues(1);
+ contentValues.put(NOTIFICATION_CHANNEL, notificationChannel);
+ updateOrInsert(recipient.getAddress(), contentValues);
+ recipient.setNotificationChannel(notificationChannel);
+ }
+
+ public boolean isNotificationChannelPresent(@NonNull String notificationChannel) {
+ SQLiteDatabase database = databaseHelper.getReadableDatabase();
+
+ try (Cursor cursor = database.query(TABLE_NAME, new String[] { ID }, NOTIFICATION_CHANNEL + " = ?",
+ new String[] { notificationChannel }, null, null, null, null)) {
+ return cursor != null && cursor.moveToFirst();
+ }
+ }
+
public Set getAllAddresses() {
SQLiteDatabase db = databaseHelper.getReadableDatabase();
Set results = new HashSet<>();
@@ -472,6 +501,7 @@ public class RecipientDatabase extends Database {
private final String signalProfileName;
private final String signalProfileAvatar;
private final boolean profileSharing;
+ private final String notificationChannel;
RecipientSettings(boolean blocked, long muteUntil,
@NonNull VibrateState messageVibrateState,
@@ -490,7 +520,8 @@ public class RecipientDatabase extends Database {
@Nullable String systemContactUri,
@Nullable String signalProfileName,
@Nullable String signalProfileAvatar,
- boolean profileSharing)
+ boolean profileSharing,
+ @Nullable String notificationChannel)
{
this.blocked = blocked;
this.muteUntil = muteUntil;
@@ -511,6 +542,7 @@ public class RecipientDatabase extends Database {
this.signalProfileName = signalProfileName;
this.signalProfileAvatar = signalProfileAvatar;
this.profileSharing = profileSharing;
+ this.notificationChannel = notificationChannel;
}
public @Nullable MaterialColor getColor() {
@@ -588,14 +620,18 @@ public class RecipientDatabase extends Database {
public boolean isProfileSharing() {
return profileSharing;
}
+
+ public @Nullable String getNotificationChannel() {
+ return notificationChannel;
+ }
}
- public static class BlockedReader {
+ public static class RecipientReader implements Closeable {
private final Context context;
- private final Cursor cursor;
+ private final Cursor cursor;
- BlockedReader(Context context, Cursor cursor) {
+ RecipientReader(Context context, Cursor cursor) {
this.context = context;
this.cursor = cursor;
}
@@ -612,6 +648,10 @@ public class RecipientDatabase extends Database {
return getCurrent();
}
+
+ public void close() {
+ cursor.close();
+ }
}
private static class PendingContactInfo {
diff --git a/src/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java b/src/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java
index 2caa72319a..021208e660 100644
--- a/src/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java
+++ b/src/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java
@@ -4,9 +4,12 @@ package org.thoughtcrime.securesms.database.helpers;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
+import android.net.Uri;
import android.os.SystemClock;
import android.support.annotation.NonNull;
import android.text.TextUtils;
+
+import org.thoughtcrime.securesms.database.Address;
import org.thoughtcrime.securesms.logging.Log;
import net.sqlcipher.database.SQLiteDatabase;
@@ -31,6 +34,7 @@ import org.thoughtcrime.securesms.database.SignedPreKeyDatabase;
import org.thoughtcrime.securesms.database.SmsDatabase;
import org.thoughtcrime.securesms.database.ThreadDatabase;
import org.thoughtcrime.securesms.jobs.RefreshPreKeysJob;
+import org.thoughtcrime.securesms.notifications.NotificationChannels;
import org.thoughtcrime.securesms.service.KeyCachingService;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
@@ -51,8 +55,9 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
private static final int FULL_TEXT_SEARCH = 9;
private static final int BAD_IMPORT_CLEANUP = 10;
private static final int QUOTE_MISSING = 11;
+ private static final int NOTIFICATION_CHANNELS = 12;
- private static final int DATABASE_VERSION = 11;
+ private static final int DATABASE_VERSION = 12;
private static final String DATABASE_NAME = "signal.db";
private final Context context;
@@ -240,6 +245,30 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
db.execSQL("ALTER TABLE mms ADD COLUMN quote_missing INTEGER DEFAULT 0");
}
+ if (oldVersion < NOTIFICATION_CHANNELS) {
+ db.execSQL("ALTER TABLE recipient_preferences ADD COLUMN notification_channel TEXT DEFAULT NULL");
+
+ try (Cursor cursor = db.rawQuery("SELECT recipient_ids, system_display_name, signal_profile_name, notification, vibrate FROM recipient_preferences WHERE notification NOT NULL OR vibrate != 0", null)) {
+ while (cursor != null && cursor.moveToNext()) {
+ String addressString = cursor.getString(cursor.getColumnIndexOrThrow("recipient_ids"));
+ Address address = Address.fromExternal(context, addressString);
+ String systemName = cursor.getString(cursor.getColumnIndexOrThrow("system_display_name"));
+ String profileName = cursor.getString(cursor.getColumnIndexOrThrow("signal_profile_name"));
+ String messageSound = cursor.getString(cursor.getColumnIndexOrThrow("notification"));
+ Uri messageSoundUri = messageSound != null ? Uri.parse(messageSound) : null;
+ int vibrateState = cursor.getInt(cursor.getColumnIndexOrThrow("vibrate"));
+ String displayName = NotificationChannels.getChannelDisplayNameFor(systemName, profileName, address);
+ boolean vibrateEnabled = vibrateState == 0 ? TextSecurePreferences.isNotificationVibrateEnabled(context) : vibrateState == 1;
+
+ String channelId = NotificationChannels.createChannelFor(context, address, displayName, messageSoundUri, vibrateEnabled);
+
+ ContentValues values = new ContentValues(1);
+ values.put("notification_channel", channelId);
+ db.update("recipient_preferences", values, "recipient_ids = ?", new String[] { addressString });
+ }
+ }
+ }
+
db.setTransactionSuccessful();
} finally {
db.endTransaction();
diff --git a/src/org/thoughtcrime/securesms/jobs/MultiDeviceBlockedUpdateJob.java b/src/org/thoughtcrime/securesms/jobs/MultiDeviceBlockedUpdateJob.java
index 311df39092..8e79ca9f4d 100644
--- a/src/org/thoughtcrime/securesms/jobs/MultiDeviceBlockedUpdateJob.java
+++ b/src/org/thoughtcrime/securesms/jobs/MultiDeviceBlockedUpdateJob.java
@@ -5,7 +5,7 @@ import android.content.Context;
import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.RecipientDatabase;
-import org.thoughtcrime.securesms.database.RecipientDatabase.BlockedReader;
+import org.thoughtcrime.securesms.database.RecipientDatabase.RecipientReader;
import org.thoughtcrime.securesms.dependencies.InjectableType;
import org.thoughtcrime.securesms.jobmanager.JobParameters;
import org.thoughtcrime.securesms.jobmanager.requirements.NetworkRequirement;
@@ -45,18 +45,20 @@ public class MultiDeviceBlockedUpdateJob extends MasterSecretJob implements Inje
throws IOException, UntrustedIdentityException
{
RecipientDatabase database = DatabaseFactory.getRecipientDatabase(context);
- BlockedReader reader = database.readerForBlocked(database.getBlocked());
- List blocked = new LinkedList<>();
- Recipient recipient;
+ try (RecipientReader reader = database.readerForBlocked(database.getBlocked())) {
+ List blocked = new LinkedList<>();
- while ((recipient = reader.getNext()) != null) {
- if (!recipient.isGroupRecipient()) {
- blocked.add(recipient.getAddress().serialize());
+ Recipient recipient;
+
+ while ((recipient = reader.getNext()) != null) {
+ if (!recipient.isGroupRecipient()) {
+ blocked.add(recipient.getAddress().serialize());
+ }
}
- }
- messageSender.sendMessage(SignalServiceSyncMessage.forBlocked(new BlockedListMessage(blocked)));
+ messageSender.sendMessage(SignalServiceSyncMessage.forBlocked(new BlockedListMessage(blocked)));
+ }
}
@Override
diff --git a/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java b/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java
index 9b675a7b7d..9bc277f377 100644
--- a/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java
+++ b/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java
@@ -136,7 +136,7 @@ public class PushDecryptJob extends ContextJob {
if (TextSecurePreferences.getNeedsSqlCipherMigration(context)) {
Log.w(TAG, "Skipping job, waiting for sqlcipher migration...");
NotificationManagerCompat.from(context).notify(494949,
- new NotificationCompat.Builder(context, NotificationChannels.MESSAGES)
+ new NotificationCompat.Builder(context, NotificationChannels.getMessagesChannel(context))
.setSmallIcon(R.drawable.icon_notification)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setCategory(NotificationCompat.CATEGORY_MESSAGE)
diff --git a/src/org/thoughtcrime/securesms/notifications/AbstractNotificationBuilder.java b/src/org/thoughtcrime/securesms/notifications/AbstractNotificationBuilder.java
index 341bed7116..f10c51f305 100644
--- a/src/org/thoughtcrime/securesms/notifications/AbstractNotificationBuilder.java
+++ b/src/org/thoughtcrime/securesms/notifications/AbstractNotificationBuilder.java
@@ -31,7 +31,7 @@ public abstract class AbstractNotificationBuilder extends NotificationCompat.Bui
this.context = context;
this.privacy = privacy;
- setChannelId(NotificationChannels.MESSAGES);
+ setChannelId(NotificationChannels.getMessagesChannel(context));
setLed();
}
diff --git a/src/org/thoughtcrime/securesms/notifications/NotificationChannels.java b/src/org/thoughtcrime/securesms/notifications/NotificationChannels.java
index 0cd8e593b3..359bab5858 100644
--- a/src/org/thoughtcrime/securesms/notifications/NotificationChannels.java
+++ b/src/org/thoughtcrime/securesms/notifications/NotificationChannels.java
@@ -1,25 +1,51 @@
package org.thoughtcrime.securesms.notifications;
+import android.annotation.TargetApi;
import android.app.NotificationChannel;
+import android.app.NotificationChannelGroup;
import android.app.NotificationManager;
import android.content.Context;
+import android.content.Intent;
+import android.graphics.Color;
+import android.media.AudioAttributes;
+import android.net.Uri;
import android.os.Build;
+import android.provider.Settings;
import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.WorkerThread;
+import android.text.TextUtils;
import org.thoughtcrime.securesms.BuildConfig;
import org.thoughtcrime.securesms.R;
+import org.thoughtcrime.securesms.database.Address;
+import org.thoughtcrime.securesms.database.DatabaseFactory;
+import org.thoughtcrime.securesms.database.RecipientDatabase;
+import org.thoughtcrime.securesms.database.RecipientDatabase.VibrateState;
+import org.thoughtcrime.securesms.recipients.Recipient;
+import org.thoughtcrime.securesms.util.TextSecurePreferences;
+import org.whispersystems.libsignal.logging.Log;
import java.util.Arrays;
public class NotificationChannels {
- public static String MESSAGES = "messages";
- public static String CALLS = "calls";
- public static String FAILURES = "failures";
- public static String APP_UPDATES = "app_updates";
- public static String BACKUPS = "backups";
- public static String LOCKED_STATUS = "locked_status";
- public static String OTHER = "other";
+ private static final String TAG = NotificationChannels.class.getSimpleName();
+
+ private static final int VERSION_MESSAGES_CATEGORY = 2;
+
+ private static final int VERSION = 2;
+
+ private static final String CATEGORY_MESSAGES = "messages";
+ private static final String CONTACT_PREFIX = "contact_";
+ private static final String MESSAGES_PREFIX = "messages_";
+
+ public static final String CALLS = "calls_v2";
+ public static final String FAILURES = "failures";
+ public static final String APP_UPDATES = "app_updates";
+ public static final String BACKUPS = "backups_v2";
+ public static final String LOCKED_STATUS = "locked_status_v2";
+ public static final String OTHER = "other_v2";
/**
* Ensures all of the notification channels are created. No harm in repeat calls. Call is safely
@@ -30,14 +56,193 @@ public class NotificationChannels {
return;
}
- NotificationChannel messages = new NotificationChannel(MESSAGES, context.getString(R.string.NotificationChannel_messages), NotificationManager.IMPORTANCE_HIGH);
+ NotificationManager notificationManager = context.getSystemService(NotificationManager.class);
+ if (notificationManager == null) {
+ Log.w(TAG, "Unable to retrieve notification manager. Can't setup channels.");
+ return;
+ }
+
+ int oldVersion = TextSecurePreferences.getNotificationChannelVersion(context);
+ if (oldVersion != VERSION) {
+ onUpgrade(notificationManager, oldVersion, VERSION);
+ TextSecurePreferences.setNotificationChannelVersion(context, VERSION);
+ }
+
+ onCreate(context, notificationManager);
+ }
+
+ /**
+ * @return The channel ID for the default messages channel. Prefer
+ * {@link Recipient#getNotificationChannel(Context)} if you know the recipient.
+ */
+ public static @NonNull String getMessagesChannel(@NonNull Context context) {
+ return getMessagesChannelId(TextSecurePreferences.getNotificationMessagesChannelVersion(context));
+ }
+
+ /**
+ * @return Whether or not notification channels are supported.
+ */
+ public static boolean supported() {
+ return Build.VERSION.SDK_INT >= 26;
+ }
+
+ public static String getChannelDisplayNameFor(@Nullable String systemName, @Nullable String profileName, @NonNull Address address) {
+ return TextUtils.isEmpty(systemName) ? (TextUtils.isEmpty(profileName) ? address.serialize() : profileName) : systemName;
+ }
+
+ /**
+ * Creates a channel for the specified recipient.
+ * @return The channel ID for the newly-created channel.
+ */
+ public static String createChannelFor(@NonNull Context context, @NonNull Recipient recipient) {
+ VibrateState vibrateState = recipient.getMessageVibrate();
+ boolean vibrationEnabled = vibrateState == VibrateState.DEFAULT ? TextSecurePreferences.isNotificationVibrateEnabled(context) : vibrateState == VibrateState.ENABLED;
+ String displayName = getChannelDisplayNameFor(recipient.getName(), recipient.getProfileName(), recipient.getAddress());
+
+ return createChannelFor(context, recipient.getAddress(), displayName, recipient.getMessageRingtone(), vibrationEnabled);
+ }
+
+ /**
+ * More verbose version of {@link #createChannelFor(Context, Recipient)}.
+ */
+ public static String createChannelFor(@NonNull Context context,
+ @NonNull Address address,
+ @NonNull String displayName,
+ @Nullable Uri messageSound,
+ boolean vibrationEnabled)
+ {
+ if (!supported()) {
+ return getMessagesChannel(context);
+ }
+
+ String channelId = generateChannelIdFor(address);
+ NotificationChannel channel = new NotificationChannel(channelId, displayName, NotificationManager.IMPORTANCE_HIGH);
+
+ setLedPreference(channel, TextSecurePreferences.getNotificationLedColor(context));
+ channel.setGroup(CATEGORY_MESSAGES);
+ channel.enableVibration(vibrationEnabled);
+ channel.setSound(messageSound, new AudioAttributes.Builder().setContentType(AudioAttributes.CONTENT_TYPE_UNKNOWN)
+ .setUsage(AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_INSTANT)
+ .build());
+
+ NotificationManager notificationManager = context.getSystemService(NotificationManager.class);
+ if (notificationManager == null) {
+ Log.w(TAG, "Unable to retrieve notification manager. Cannot create channel for recipient.");
+ return channelId;
+ }
+
+ notificationManager.createNotificationChannel(channel);
+
+ return channelId;
+ }
+
+ /**
+ * Deletes the channel generated for the provided recipient. Safe to call even if there was never
+ * a channel made for that recipient.
+ */
+ public static void deleteChannelFor(@NonNull Context context, @NonNull Recipient recipient) {
+ if (!supported()) {
+ return;
+ }
+
+ NotificationManager notificationManager = context.getSystemService(NotificationManager.class);
+ if (notificationManager == null) {
+ Log.w(TAG, "Unable to retrieve notification manager. Cannot delete channel.");
+ return;
+ }
+
+ String channel = recipient.getNotificationChannel(context);
+
+ if (!TextUtils.isEmpty(channel) && !getMessagesChannel(context).equals(channel)) {
+ notificationManager.deleteNotificationChannel(channel);
+ }
+ }
+
+ /**
+ * Navigates the user to the system settings for the desired notification channel.
+ */
+ public static void openChannelSettings(@NonNull Context context, @NonNull String channelId) {
+ if (!supported()) {
+ return;
+ }
+
+ Intent intent = new Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS);
+ intent.putExtra(Settings.EXTRA_CHANNEL_ID, channelId);
+ intent.putExtra(Settings.EXTRA_APP_PACKAGE, context.getPackageName());
+ context.startActivity(intent);
+ }
+
+ /**
+ * Updates the LED color for message notifications and all contact-specific message notification
+ * channels. Performs database operations and should therefore be invoked on a background thread.
+ */
+ @WorkerThread
+ public static void updateMessagesLedColor(@NonNull Context context, @NonNull String color) {
+ if (!supported()) {
+ return;
+ }
+
+ NotificationManager notificationManager = context.getSystemService(NotificationManager.class);
+ if (notificationManager == null) {
+ Log.w(TAG, "Unable to retrieve notification manager. Cannot update led color.");
+ return;
+ }
+
+ updateMessageChannelLedColor(context, notificationManager, color);
+ updateAllRecipientChannelLedColors(context, notificationManager, color);
+ }
+
+ /**
+ * Updates the name of an existing channel to match the recipient's current name. Will have no
+ * effect if the recipient doesn't have an existing valid channel.
+ */
+ public static void updateContactChannelName(@NonNull Context context, @NonNull Recipient recipient) {
+ if (!supported() || !recipient.hasCustomNotifications()) {
+ return;
+ }
+
+ NotificationManager notificationManager = context.getSystemService(NotificationManager.class);
+ if (notificationManager == null) {
+ Log.w(TAG, "Unable to retrieve notification manager. Cannot update channel name.");
+ return;
+ }
+
+ if (notificationManager.getNotificationChannel(recipient.getNotificationChannel(context)) == null) {
+ Log.w(TAG, "Tried to update the name of a channel, but that channel doesn't exist.");
+ return;
+ }
+
+ NotificationChannel channel = new NotificationChannel(recipient.getNotificationChannel(context),
+ getChannelDisplayNameFor(recipient.getName(), recipient.getProfileName(), recipient.getAddress()),
+ NotificationManager.IMPORTANCE_HIGH);
+ channel.setGroup(CATEGORY_MESSAGES);
+ notificationManager.createNotificationChannel(channel);
+ }
+
+ @TargetApi(26)
+ private static void onCreate(@NonNull Context context, @NonNull NotificationManager notificationManager) {
+ NotificationChannelGroup messagesGroup = new NotificationChannelGroup(CATEGORY_MESSAGES, context.getResources().getString(R.string.NotificationChannel_group_messages));
+ notificationManager.createNotificationChannelGroup(messagesGroup);
+
+ NotificationChannel messages = new NotificationChannel(getMessagesChannel(context), context.getString(R.string.NotificationChannel_messages), NotificationManager.IMPORTANCE_HIGH);
NotificationChannel calls = new NotificationChannel(CALLS, context.getString(R.string.NotificationChannel_calls), NotificationManager.IMPORTANCE_LOW);
NotificationChannel failures = new NotificationChannel(FAILURES, context.getString(R.string.NotificationChannel_failures), NotificationManager.IMPORTANCE_HIGH);
NotificationChannel backups = new NotificationChannel(BACKUPS, context.getString(R.string.NotificationChannel_backups), NotificationManager.IMPORTANCE_LOW);
NotificationChannel lockedStatus = new NotificationChannel(LOCKED_STATUS, context.getString(R.string.NotificationChannel_locked_status), NotificationManager.IMPORTANCE_LOW);
NotificationChannel other = new NotificationChannel(OTHER, context.getString(R.string.NotificationChannel_other), NotificationManager.IMPORTANCE_LOW);
- NotificationManager notificationManager = context.getSystemService(NotificationManager.class);
+ messages.setGroup(CATEGORY_MESSAGES);
+ messages.enableVibration(TextSecurePreferences.isNotificationVibrateEnabled(context));
+ messages.setSound(TextSecurePreferences.getNotificationRingtone(context), new AudioAttributes.Builder().setContentType(AudioAttributes.CONTENT_TYPE_UNKNOWN)
+ .setUsage(AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_INSTANT)
+ .build());
+ setLedPreference(messages, TextSecurePreferences.getNotificationLedColor(context));
+
+ calls.setShowBadge(false);
+ backups.setShowBadge(false);
+ lockedStatus.setShowBadge(false);
+ other.setShowBadge(false);
+
notificationManager.createNotificationChannels(Arrays.asList(messages, calls, failures, backups, lockedStatus, other));
if (BuildConfig.PLAY_STORE_DISABLED) {
@@ -48,7 +253,90 @@ public class NotificationChannels {
}
}
- public static boolean supported() {
- return Build.VERSION.SDK_INT >= 26;
+ @TargetApi(26)
+ private static void onUpgrade(@NonNull NotificationManager notificationManager, int oldVersion, int newVersion) {
+ Log.i(TAG, "Upgrading channels from " + oldVersion + " to " + newVersion);
+
+ if (oldVersion < VERSION_MESSAGES_CATEGORY) {
+ notificationManager.deleteNotificationChannel("messages");
+ notificationManager.deleteNotificationChannel("calls");
+ notificationManager.deleteNotificationChannel("locked_status");
+ notificationManager.deleteNotificationChannel("backups");
+ notificationManager.deleteNotificationChannel("other");
+ }
+ }
+
+ @TargetApi(26)
+ private static void setLedPreference(@NonNull NotificationChannel channel, @NonNull String ledColor) {
+ if ("none".equals(ledColor)) {
+ channel.enableLights(false);
+ } else {
+ channel.enableLights(true);
+ channel.setLightColor(Color.parseColor(ledColor));
+ }
+ }
+
+
+ private static @NonNull String generateChannelIdFor(@NonNull Address address) {
+ return CONTACT_PREFIX + address.serialize() + "_" + System.currentTimeMillis();
+ }
+
+ @TargetApi(26)
+ private static @NonNull NotificationChannel copyChannel(@NonNull NotificationChannel original, @NonNull String id) {
+ NotificationChannel copy = new NotificationChannel(id, original.getName(), original.getImportance());
+
+ copy.setGroup(original.getGroup());
+ copy.setSound(original.getSound(), original.getAudioAttributes());
+ copy.setBypassDnd(original.canBypassDnd());
+ copy.enableVibration(original.shouldVibrate());
+ copy.setVibrationPattern(original.getVibrationPattern());
+ copy.setLockscreenVisibility(original.getLockscreenVisibility());
+ copy.setShowBadge(original.canShowBadge());
+ copy.setLightColor(original.getLightColor());
+ copy.enableLights(original.shouldShowLights());
+
+ return copy;
+ }
+
+ private static String getMessagesChannelId(int version) {
+ return MESSAGES_PREFIX + version;
+ }
+
+ @TargetApi(26)
+ private static void updateMessageChannelLedColor(@NonNull Context context, @NonNull NotificationManager notificationManager, @NonNull String color) {
+ int existingVersion = TextSecurePreferences.getNotificationMessagesChannelVersion(context);
+ NotificationChannel existingChannel = notificationManager.getNotificationChannel(getMessagesChannelId(existingVersion));
+
+ notificationManager.deleteNotificationChannel(existingChannel.getId());
+
+ int newVersion = existingVersion + 1;
+ NotificationChannel newChannel = copyChannel(existingChannel, getMessagesChannelId(newVersion));
+
+ setLedPreference(newChannel, color);
+ notificationManager.createNotificationChannel(newChannel);
+
+ TextSecurePreferences.setNotificationMessagesChannelVersion(context, newVersion);
+ }
+
+ @WorkerThread
+ @TargetApi(26)
+ private static void updateAllRecipientChannelLedColors(@NonNull Context context, @NonNull NotificationManager notificationManager, @NonNull String color) {
+ RecipientDatabase database = DatabaseFactory.getRecipientDatabase(context);
+
+ try (RecipientDatabase.RecipientReader recipients = database.getRecipientsWithNotificationChannels()) {
+ Recipient recipient;
+ while ((recipient = recipients.getNext()) != null) {
+ NotificationChannel existingChannel = notificationManager.getNotificationChannel(recipient.getNotificationChannel(context));
+ notificationManager.deleteNotificationChannel(existingChannel.getId());
+
+ NotificationChannel newChannel = copyChannel(existingChannel, generateChannelIdFor(recipient.getAddress()));
+ newChannel.setGroup(CATEGORY_MESSAGES);
+ setLedPreference(newChannel, color);
+
+ database.setNotificationChannel(recipient, newChannel.getId());
+
+ notificationManager.createNotificationChannel(newChannel);
+ }
+ }
}
}
diff --git a/src/org/thoughtcrime/securesms/notifications/SingleRecipientNotificationBuilder.java b/src/org/thoughtcrime/securesms/notifications/SingleRecipientNotificationBuilder.java
index 5394e13cdd..34221cb7d0 100644
--- a/src/org/thoughtcrime/securesms/notifications/SingleRecipientNotificationBuilder.java
+++ b/src/org/thoughtcrime/securesms/notifications/SingleRecipientNotificationBuilder.java
@@ -60,6 +60,8 @@ public class SingleRecipientNotificationBuilder extends AbstractNotificationBuil
}
public void setThread(@NonNull Recipient recipient) {
+ setChannelId(recipient.getNotificationChannel(context));
+
if (privacy.isDisplayContact()) {
setContentTitle(recipient.toShortString());
diff --git a/src/org/thoughtcrime/securesms/preferences/NotificationsPreferenceFragment.java b/src/org/thoughtcrime/securesms/preferences/NotificationsPreferenceFragment.java
index ae49264fa1..b7fe00aad4 100644
--- a/src/org/thoughtcrime/securesms/preferences/NotificationsPreferenceFragment.java
+++ b/src/org/thoughtcrime/securesms/preferences/NotificationsPreferenceFragment.java
@@ -19,10 +19,7 @@ import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.components.SwitchPreferenceCompat;
import org.thoughtcrime.securesms.notifications.MessageNotifier;
import org.thoughtcrime.securesms.notifications.NotificationChannels;
-import org.thoughtcrime.securesms.preferences.widgets.SignalListPreference;
-import org.thoughtcrime.securesms.preferences.widgets.SignalPreference;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
-import org.w3c.dom.Text;
import static android.app.Activity.RESULT_OK;
@@ -31,16 +28,38 @@ public class NotificationsPreferenceFragment extends ListSummaryPreferenceFragme
@SuppressWarnings("unused")
private static final String TAG = NotificationsPreferenceFragment.class.getSimpleName();
+ private static final String PREF_SYSTEM_SETTINGS = "pref_key_system_notification_settings";
+
@Override
public void onCreate(Bundle paramBundle) {
super.onCreate(paramBundle);
+ Preference ledBlinkPref = this.findPreference(TextSecurePreferences.LED_BLINK_PREF);
+ Preference messageTonePref = this.findPreference(TextSecurePreferences.RINGTONE_PREF);
+ Preference vibratePref = this.findPreference(TextSecurePreferences.VIBRATE_PREF);
+ Preference systemPref = this.findPreference(PREF_SYSTEM_SETTINGS);
+
+ if (NotificationChannels.supported()) {
+ ledBlinkPref.setVisible(false);
+ messageTonePref.setVisible(false);
+ vibratePref.setVisible(false);
+
+ systemPref.setOnPreferenceClickListener(p -> {
+ NotificationChannels.openChannelSettings(getContext(), NotificationChannels.getMessagesChannel(getContext()));
+ return true;
+ });
+ } else {
+ systemPref.setVisible(false);
+
+ ledBlinkPref.setOnPreferenceChangeListener(new ListSummaryListener());
+ messageTonePref.setOnPreferenceChangeListener(new RingtoneSummaryListener());
+
+ initializeListSummary((ListPreference) ledBlinkPref);
+ initializeRingtoneSummary(messageTonePref);
+ }
+
this.findPreference(TextSecurePreferences.LED_COLOR_PREF)
- .setOnPreferenceChangeListener(new ListSummaryListener());
- this.findPreference(TextSecurePreferences.LED_BLINK_PREF)
- .setOnPreferenceChangeListener(new ListSummaryListener());
- this.findPreference(TextSecurePreferences.RINGTONE_PREF)
- .setOnPreferenceChangeListener(new RingtoneSummaryListener());
+ .setOnPreferenceChangeListener(new LedColorChangeListener());
this.findPreference(TextSecurePreferences.REPEAT_ALERTS_PREF)
.setOnPreferenceChangeListener(new ListSummaryListener());
this.findPreference(TextSecurePreferences.NOTIFICATION_PRIVACY_PREF)
@@ -83,17 +102,14 @@ public class NotificationsPreferenceFragment extends ListSummaryPreferenceFragme
});
initializeListSummary((ListPreference) findPreference(TextSecurePreferences.LED_COLOR_PREF));
- initializeListSummary((ListPreference) findPreference(TextSecurePreferences.LED_BLINK_PREF));
initializeListSummary((ListPreference) findPreference(TextSecurePreferences.REPEAT_ALERTS_PREF));
initializeListSummary((ListPreference) findPreference(TextSecurePreferences.NOTIFICATION_PRIVACY_PREF));
if (NotificationChannels.supported()) {
- ((SignalListPreference) this.findPreference(TextSecurePreferences.NOTIFICATION_PRIORITY_PREF)).disableDialog();
-
this.findPreference(TextSecurePreferences.NOTIFICATION_PRIORITY_PREF)
.setOnPreferenceClickListener(preference -> {
Intent intent = new Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS);
- intent.putExtra(Settings.EXTRA_CHANNEL_ID, NotificationChannels.MESSAGES);
+ intent.putExtra(Settings.EXTRA_CHANNEL_ID, NotificationChannels.getMessagesChannel(getContext()));
intent.putExtra(Settings.EXTRA_APP_PACKAGE, getContext().getPackageName());
startActivity(intent);
return true;
@@ -102,7 +118,6 @@ public class NotificationsPreferenceFragment extends ListSummaryPreferenceFragme
initializeListSummary((ListPreference) findPreference(TextSecurePreferences.NOTIFICATION_PRIORITY_PREF));
}
- initializeRingtoneSummary(findPreference(TextSecurePreferences.RINGTONE_PREF));
initializeCallRingtoneSummary(findPreference(TextSecurePreferences.CALL_RINGTONE_PREF));
initializeCallVibrateSummary((SwitchPreferenceCompat)findPreference(TextSecurePreferences.CALL_VIBRATE_PREF));
}
@@ -201,6 +216,22 @@ public class NotificationsPreferenceFragment extends ListSummaryPreferenceFragme
return super.onPreferenceChange(preference, value);
}
+ }
+ @SuppressLint("StaticFieldLeak")
+ private class LedColorChangeListener extends ListSummaryListener {
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object value) {
+ if (NotificationChannels.supported()) {
+ new AsyncTask() {
+ @Override
+ protected Void doInBackground(Void... voids) {
+ NotificationChannels.updateMessagesLedColor(getActivity(), (String) value);
+ return null;
+ }
+ }.execute();
+ }
+ return super.onPreferenceChange(preference, value);
+ }
}
}
diff --git a/src/org/thoughtcrime/securesms/preferences/widgets/SignalListPreference.java b/src/org/thoughtcrime/securesms/preferences/widgets/SignalListPreference.java
index 643e70bd2e..5423085371 100644
--- a/src/org/thoughtcrime/securesms/preferences/widgets/SignalListPreference.java
+++ b/src/org/thoughtcrime/securesms/preferences/widgets/SignalListPreference.java
@@ -5,6 +5,7 @@ import android.content.Context;
import android.os.Build;
import android.support.annotation.RequiresApi;
import android.support.v7.preference.ListPreference;
+import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceViewHolder;
import android.util.AttributeSet;
import android.util.TypedValue;
@@ -16,9 +17,9 @@ import org.thoughtcrime.securesms.util.ViewUtil;
public class SignalListPreference extends ListPreference {
- private TextView rightSummary;
- private CharSequence summary;
- private boolean dialogDisabled;
+ private TextView rightSummary;
+ private CharSequence summary;
+ private OnPreferenceClickListener clickListener;
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public SignalListPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
@@ -65,13 +66,15 @@ public class SignalListPreference extends ListPreference {
}
}
- public void disableDialog() {
- dialogDisabled = true;
+ @Override
+ public void setOnPreferenceClickListener(OnPreferenceClickListener onPreferenceClickListener) {
+ super.setOnPreferenceClickListener(onPreferenceClickListener);
+ this.clickListener = onPreferenceClickListener;
}
@Override
protected void onClick() {
- if (!dialogDisabled) {
+ if (clickListener == null || !clickListener.onPreferenceClick(this)) {
super.onClick();
}
}
diff --git a/src/org/thoughtcrime/securesms/recipients/Recipient.java b/src/org/thoughtcrime/securesms/recipients/Recipient.java
index e18f97b7bb..e7a81ec816 100644
--- a/src/org/thoughtcrime/securesms/recipients/Recipient.java
+++ b/src/org/thoughtcrime/securesms/recipients/Recipient.java
@@ -17,6 +17,7 @@
*/
package org.thoughtcrime.securesms.recipients;
+import android.app.NotificationChannel;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.net.Uri;
@@ -43,6 +44,7 @@ import org.thoughtcrime.securesms.database.RecipientDatabase.RecipientSettings;
import org.thoughtcrime.securesms.database.RecipientDatabase.RegisteredState;
import org.thoughtcrime.securesms.database.RecipientDatabase.VibrateState;
import org.thoughtcrime.securesms.logging.Log;
+import org.thoughtcrime.securesms.notifications.NotificationChannels;
import org.thoughtcrime.securesms.recipients.RecipientProvider.RecipientDetails;
import org.thoughtcrime.securesms.util.FutureTaskListener;
import org.thoughtcrime.securesms.util.ListenableFutureTask;
@@ -90,6 +92,7 @@ public class Recipient implements RecipientModifiedListener {
private @Nullable String profileName;
private @Nullable String profileAvatar;
private boolean profileSharing;
+ private String notificationChannel;
@SuppressWarnings("ConstantConditions")
@@ -135,6 +138,7 @@ public class Recipient implements RecipientModifiedListener {
this.seenInviteReminder = stale.seenInviteReminder;
this.defaultSubscriptionId = stale.defaultSubscriptionId;
this.registered = stale.registered;
+ this.notificationChannel = stale.notificationChannel;
this.profileKey = stale.profileKey;
this.profileName = stale.profileName;
this.profileAvatar = stale.profileAvatar;
@@ -158,6 +162,7 @@ public class Recipient implements RecipientModifiedListener {
this.seenInviteReminder = details.get().seenInviteReminder;
this.defaultSubscriptionId = details.get().defaultSubscriptionId;
this.registered = details.get().registered;
+ this.notificationChannel = details.get().notificationChannel;
this.profileKey = details.get().profileKey;
this.profileName = details.get().profileName;
this.profileAvatar = details.get().profileAvatar;
@@ -187,6 +192,7 @@ public class Recipient implements RecipientModifiedListener {
Recipient.this.seenInviteReminder = result.seenInviteReminder;
Recipient.this.defaultSubscriptionId = result.defaultSubscriptionId;
Recipient.this.registered = result.registered;
+ Recipient.this.notificationChannel = result.notificationChannel;
Recipient.this.profileKey = result.profileKey;
Recipient.this.profileName = result.profileName;
Recipient.this.profileAvatar = result.profileAvatar;
@@ -233,6 +239,7 @@ public class Recipient implements RecipientModifiedListener {
this.seenInviteReminder = details.seenInviteReminder;
this.defaultSubscriptionId = details.defaultSubscriptionId;
this.registered = details.registered;
+ this.notificationChannel = details.notificationChannel;
this.profileKey = details.profileKey;
this.profileName = details.profileName;
this.profileAvatar = details.profileAvatar;
@@ -581,6 +588,30 @@ public class Recipient implements RecipientModifiedListener {
if (notify) notifyListeners();
}
+ public synchronized @NonNull String getNotificationChannel(@NonNull Context context) {
+ if (!NotificationChannels.supported() || notificationChannel == null) {
+ return NotificationChannels.getMessagesChannel(context);
+ }
+ return notificationChannel;
+ }
+
+ public void setNotificationChannel(@Nullable String value) {
+ boolean notify = false;
+
+ synchronized (this) {
+ if (!Util.equals(this.notificationChannel, value)) {
+ this.notificationChannel = value;
+ notify = true;
+ }
+ }
+
+ if (notify) notifyListeners();
+ }
+
+ public synchronized boolean hasCustomNotifications() {
+ return NotificationChannels.supported() && notificationChannel != null;
+ }
+
public synchronized @Nullable byte[] getProfileKey() {
return profileKey;
}
diff --git a/src/org/thoughtcrime/securesms/recipients/RecipientProvider.java b/src/org/thoughtcrime/securesms/recipients/RecipientProvider.java
index 468932bbfd..5398662ffb 100644
--- a/src/org/thoughtcrime/securesms/recipients/RecipientProvider.java
+++ b/src/org/thoughtcrime/securesms/recipients/RecipientProvider.java
@@ -174,6 +174,7 @@ class RecipientProvider {
@Nullable final String profileAvatar;
final boolean profileSharing;
final boolean systemContact;
+ @Nullable final String notificationChannel;
RecipientDetails(@Nullable String name, @Nullable Long groupAvatarId,
boolean systemContact, @Nullable RecipientSettings settings,
@@ -200,6 +201,7 @@ class RecipientProvider {
this.profileAvatar = settings != null ? settings.getProfileAvatar() : null;
this.profileSharing = settings != null && settings.isProfileSharing();
this.systemContact = systemContact;
+ this.notificationChannel = settings != null ? settings.getNotificationChannel() : null;
if (name == null && settings != null) this.name = settings.getSystemDisplayName();
else this.name = name;
diff --git a/src/org/thoughtcrime/securesms/util/DirectoryHelper.java b/src/org/thoughtcrime/securesms/util/DirectoryHelper.java
index 2b615363fd..e60cbebf21 100644
--- a/src/org/thoughtcrime/securesms/util/DirectoryHelper.java
+++ b/src/org/thoughtcrime/securesms/util/DirectoryHelper.java
@@ -28,6 +28,7 @@ import org.thoughtcrime.securesms.database.RecipientDatabase;
import org.thoughtcrime.securesms.database.RecipientDatabase.RegisteredState;
import org.thoughtcrime.securesms.jobs.MultiDeviceContactUpdateJob;
import org.thoughtcrime.securesms.notifications.MessageNotifier;
+import org.thoughtcrime.securesms.notifications.NotificationChannels;
import org.thoughtcrime.securesms.permissions.Permissions;
import org.thoughtcrime.securesms.push.AccountManagerFactory;
import org.thoughtcrime.securesms.recipients.Recipient;
@@ -182,6 +183,14 @@ public class DirectoryHelper {
handle.finish();
}
+ if (NotificationChannels.supported()) {
+ try (RecipientDatabase.RecipientReader recipients = DatabaseFactory.getRecipientDatabase(context).getRecipientsWithNotificationChannels()) {
+ Recipient recipient;
+ while ((recipient = recipients.getNext()) != null) {
+ NotificationChannels.updateContactChannelName(context, recipient);
+ }
+ }
+ }
} catch (RemoteException | OperationApplicationException e) {
Log.w(TAG, e);
}
diff --git a/src/org/thoughtcrime/securesms/util/TextSecurePreferences.java b/src/org/thoughtcrime/securesms/util/TextSecurePreferences.java
index 90fc664a16..1867e93690 100644
--- a/src/org/thoughtcrime/securesms/util/TextSecurePreferences.java
+++ b/src/org/thoughtcrime/securesms/util/TextSecurePreferences.java
@@ -54,7 +54,7 @@ public class TextSecurePreferences {
private static final String LAST_EXPERIENCE_VERSION_PREF = "last_experience_version_code";
private static final String EXPERIENCE_DISMISSED_PREF = "experience_dismissed";
public static final String RINGTONE_PREF = "pref_key_ringtone";
- private static final String VIBRATE_PREF = "pref_key_vibrate";
+ public static final String VIBRATE_PREF = "pref_key_vibrate";
private static final String NOTIFICATION_PREF = "pref_key_enable_notifications";
public static final String LED_COLOR_PREF = "pref_led_color";
public static final String LED_BLINK_PREF = "pref_led_blink";
@@ -159,6 +159,9 @@ public class TextSecurePreferences {
private static final String LOG_ENCRYPTED_SECRET = "pref_log_encrypted_secret";
private static final String LOG_UNENCRYPTED_SECRET = "pref_log_unencrypted_secret";
+ private static final String NOTIFICATION_CHANNEL_VERSION = "pref_notification_channel_version";
+ private static final String NOTIFICATION_MESSAGES_CHANNEL_VERSION = "pref_notification_messages_channel_version";
+
public static boolean isScreenLockEnabled(@NonNull Context context) {
return getBooleanPreference(context, SCREEN_LOCK, false);
}
@@ -960,6 +963,22 @@ public class TextSecurePreferences {
return getStringPreference(context, LOG_UNENCRYPTED_SECRET, null);
}
+ public static int getNotificationChannelVersion(Context context) {
+ return getIntegerPreference(context, NOTIFICATION_CHANNEL_VERSION, 1);
+ }
+
+ public static void setNotificationChannelVersion(Context context, int version) {
+ setIntegerPrefrence(context, NOTIFICATION_CHANNEL_VERSION, version);
+ }
+
+ public static int getNotificationMessagesChannelVersion(Context context) {
+ return getIntegerPreference(context, NOTIFICATION_MESSAGES_CHANNEL_VERSION, 1);
+ }
+
+ public static void setNotificationMessagesChannelVersion(Context context, int version) {
+ setIntegerPrefrence(context, NOTIFICATION_MESSAGES_CHANNEL_VERSION, version);
+ }
+
public static void setBooleanPreference(Context context, String key, boolean value) {
PreferenceManager.getDefaultSharedPreferences(context).edit().putBoolean(key, value).apply();
}