mirror of
https://github.com/oxen-io/session-android.git
synced 2025-01-11 18:43:49 +00:00
Add per-contact notification channels.
Fixes #8119 Fixes #8121 Fixes #8122
This commit is contained in:
parent
e23fd9d491
commit
e9b85a10a6
@ -288,7 +288,12 @@
|
||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
|
||||
|
||||
<activity android:name=".ApplicationPreferencesActivity"
|
||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
|
||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.NOTIFICATION_PREFERENCES" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity android:name=".RegistrationActivity"
|
||||
android:launchMode="singleTask"
|
||||
|
@ -666,13 +666,14 @@
|
||||
<string name="MessageNotifier_unknown_contact_message">Contact</string>
|
||||
|
||||
<!-- Notification Channels -->
|
||||
<string name="NotificationChannel_messages">Messages</string>
|
||||
<string name="NotificationChannel_messages">Default</string>
|
||||
<string name="NotificationChannel_calls">Calls</string>
|
||||
<string name="NotificationChannel_failures">Failures</string>
|
||||
<string name="NotificationChannel_backups">Backups</string>
|
||||
<string name="NotificationChannel_locked_status">Lock status</string>
|
||||
<string name="NotificationChannel_app_updates">App updates</string>
|
||||
<string name="NotificationChannel_other">Other</string>
|
||||
<string name="NotificationChannel_group_messages">Messages</string>
|
||||
|
||||
<!-- QuickResponseService -->
|
||||
<string name="QuickResponseService_quick_response_unavailable_when_Signal_is_locked">Quick response unavailable when Signal is locked!</string>
|
||||
@ -960,6 +961,8 @@
|
||||
|
||||
<!-- recipient_preferences -->
|
||||
<string name="recipient_preferences__mute_conversation">Mute conversation</string>
|
||||
<string name="recipient_preferences__custom_notifications">Custom notifications</string>
|
||||
<string name="recipient_preferences__custom_notifications_settings">System notification settings</string>
|
||||
<string name="recipient_preferences__notification_sound">Notification sound</string>
|
||||
<string name="recipient_preferences__vibrate">Vibrate</string>
|
||||
<string name="recipient_preferences__block">Block</string>
|
||||
@ -1086,6 +1089,7 @@
|
||||
<string name="preferences__inactivity_timeout_passphrase">Inactivity timeout passphrase</string>
|
||||
<string name="preferences__inactivity_timeout_interval">Inactivity timeout interval</string>
|
||||
<string name="preferences__notifications">Notifications</string>
|
||||
<string name="preferences__system_notification_settings">System notification settings</string>
|
||||
<string name="preferences__led_color">LED color</string>
|
||||
<string name="preferences__led_color_unknown">Unknown</string>
|
||||
<string name="preferences__pref_led_blink_title">LED blink pattern</string>
|
||||
|
@ -9,6 +9,12 @@
|
||||
android:title="@string/preferences__notifications"
|
||||
android:defaultValue="true" />
|
||||
|
||||
<org.thoughtcrime.securesms.preferences.widgets.SignalPreference
|
||||
android:key="pref_key_system_notification_settings"
|
||||
android:dependency="pref_key_enable_notifications"
|
||||
android:persistent="false"
|
||||
android:title="@string/preferences__system_notification_settings" />
|
||||
|
||||
<org.thoughtcrime.securesms.preferences.widgets.SignalPreference
|
||||
android:dependency="pref_key_enable_notifications"
|
||||
android:key="pref_key_ringtone"
|
||||
|
@ -16,6 +16,18 @@
|
||||
android:disableDependentsState="true"
|
||||
android:persistent="false" />
|
||||
|
||||
<org.thoughtcrime.securesms.components.SwitchPreferenceCompat
|
||||
android:key="pref_key_recipient_custom_notifications"
|
||||
android:title="@string/recipient_preferences__custom_notifications"
|
||||
android:defaultValue="false"
|
||||
android:persistent="false" />
|
||||
|
||||
<org.thoughtcrime.securesms.preferences.widgets.SignalPreference
|
||||
android:key="pref_key_recipient_notification_settings"
|
||||
android:dependency="pref_key_recipient_custom_notifications"
|
||||
android:title="@string/recipient_preferences__custom_notifications_settings"
|
||||
android:persistent="false" />
|
||||
|
||||
<org.thoughtcrime.securesms.preferences.widgets.SignalPreference
|
||||
android:dependency="pref_key_recipient_mute"
|
||||
android:key="pref_key_recipient_ringtone"
|
||||
|
@ -83,7 +83,9 @@ public class ApplicationPreferencesActivity extends PassphraseRequiredActionBarA
|
||||
//noinspection ConstantConditions
|
||||
this.getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
|
||||
if (icicle == null) {
|
||||
if (getIntent() != null && getIntent().getCategories() != null && getIntent().getCategories().contains("android.intent.category.NOTIFICATION_PREFERENCES")) {
|
||||
initFragment(android.R.id.content, new NotificationsPreferenceFragment());
|
||||
} else if (icicle == null) {
|
||||
initFragment(android.R.id.content, new ApplicationPreferenceFragment());
|
||||
}
|
||||
}
|
||||
|
@ -143,6 +143,7 @@ import org.thoughtcrime.securesms.mms.Slide;
|
||||
import org.thoughtcrime.securesms.mms.SlideDeck;
|
||||
import org.thoughtcrime.securesms.notifications.MarkReadReceiver;
|
||||
import org.thoughtcrime.securesms.notifications.MessageNotifier;
|
||||
import org.thoughtcrime.securesms.notifications.NotificationChannels;
|
||||
import org.thoughtcrime.securesms.permissions.Permissions;
|
||||
import org.thoughtcrime.securesms.profiles.GroupShareProfileView;
|
||||
import org.thoughtcrime.securesms.providers.PersistentBlobProvider;
|
||||
@ -462,6 +463,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
recipient = Recipient.from(this, data.getParcelableExtra(GroupCreateActivity.GROUP_ADDRESS_EXTRA), true);
|
||||
recipient.addListener(this);
|
||||
titleView.setTitle(glideRequests, recipient);
|
||||
NotificationChannels.updateContactChannelName(this, recipient);
|
||||
setBlockedUserState(recipient, isSecureText, isDefaultSms);
|
||||
supportInvalidateOptionsMenu();
|
||||
break;
|
||||
|
@ -28,6 +28,8 @@ import android.support.v7.preference.Preference;
|
||||
import android.support.v7.preference.PreferenceCategory;
|
||||
import android.support.v7.widget.Toolbar;
|
||||
import android.telephony.PhoneNumberUtils;
|
||||
|
||||
import org.thoughtcrime.securesms.components.SwitchPreferenceCompat;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import android.util.Pair;
|
||||
import android.view.MenuItem;
|
||||
@ -53,6 +55,7 @@ import org.thoughtcrime.securesms.jobs.MultiDeviceBlockedUpdateJob;
|
||||
import org.thoughtcrime.securesms.jobs.MultiDeviceContactUpdateJob;
|
||||
import org.thoughtcrime.securesms.mms.GlideApp;
|
||||
import org.thoughtcrime.securesms.mms.GlideRequests;
|
||||
import org.thoughtcrime.securesms.notifications.NotificationChannels;
|
||||
import org.thoughtcrime.securesms.permissions.Permissions;
|
||||
import org.thoughtcrime.securesms.preferences.CorrectedPreferenceFragment;
|
||||
import org.thoughtcrime.securesms.preferences.widgets.ColorPickerPreference;
|
||||
@ -90,6 +93,8 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
|
||||
private static final String PREFERENCE_COLOR = "pref_key_recipient_color";
|
||||
private static final String PREFERENCE_IDENTITY = "pref_key_recipient_identity";
|
||||
private static final String PREFERENCE_ABOUT = "pref_key_number";
|
||||
private static final String PREFERENCE_CUSTOM_NOTIFICATIONS = "pref_key_recipient_custom_notifications";
|
||||
private static final String PREFERENCE_NOTIFICATION_SETTINGS = "pref_key_recipient_notification_settings";
|
||||
|
||||
private final DynamicTheme dynamicTheme = new DynamicNoActionBarTheme();
|
||||
private final DynamicLanguage dynamicLanguage = new DynamicLanguage();
|
||||
@ -255,16 +260,32 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
|
||||
this.canHaveSafetyNumber = getActivity().getIntent()
|
||||
.getBooleanExtra(RecipientPreferenceActivity.CAN_HAVE_SAFETY_NUMBER_EXTRA, false);
|
||||
|
||||
this.findPreference(PREFERENCE_MESSAGE_TONE)
|
||||
.setOnPreferenceChangeListener(new RingtoneChangeListener(false));
|
||||
Preference customNotificationsPref = this.findPreference(PREFERENCE_CUSTOM_NOTIFICATIONS);
|
||||
Preference notificationSettingsPref = this.findPreference(PREFERENCE_NOTIFICATION_SETTINGS);
|
||||
Preference messageTonePref = this.findPreference(PREFERENCE_MESSAGE_TONE);
|
||||
Preference messageVibratePref = this.findPreference(PREFERENCE_MESSAGE_VIBRATE);
|
||||
|
||||
if (NotificationChannels.supported()) {
|
||||
messageTonePref.setVisible(false);
|
||||
messageVibratePref.setVisible(false);
|
||||
|
||||
((SwitchPreferenceCompat) customNotificationsPref).setChecked(recipient.hasCustomNotifications());
|
||||
customNotificationsPref.setOnPreferenceChangeListener(new CustomNotificationsChangedListener());
|
||||
notificationSettingsPref.setOnPreferenceClickListener(new NotificationSettingsClickedListener());
|
||||
} else {
|
||||
customNotificationsPref.setVisible(false);
|
||||
notificationSettingsPref.setVisible(false);
|
||||
|
||||
messageTonePref.setOnPreferenceChangeListener(new RingtoneChangeListener(false));
|
||||
messageVibratePref.setOnPreferenceChangeListener(new VibrateChangeListener(false));
|
||||
}
|
||||
|
||||
this.findPreference(PREFERENCE_MESSAGE_TONE)
|
||||
.setOnPreferenceClickListener(new RingtoneClickedListener(false));
|
||||
this.findPreference(PREFERENCE_CALL_TONE)
|
||||
.setOnPreferenceChangeListener(new RingtoneChangeListener(true));
|
||||
this.findPreference(PREFERENCE_CALL_TONE)
|
||||
.setOnPreferenceClickListener(new RingtoneClickedListener(true));
|
||||
this.findPreference(PREFERENCE_MESSAGE_VIBRATE)
|
||||
.setOnPreferenceChangeListener(new VibrateChangeListener(false));
|
||||
this.findPreference(PREFERENCE_CALL_VIBRATE)
|
||||
.setOnPreferenceChangeListener(new VibrateChangeListener(true));
|
||||
this.findPreference(PREFERENCE_MUTED)
|
||||
@ -688,5 +709,38 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class CustomNotificationsChangedListener implements Preference.OnPreferenceChangeListener {
|
||||
|
||||
@Override
|
||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||
final boolean enabled = (boolean) newValue;
|
||||
|
||||
new AsyncTask<Void, Void, Void>() {
|
||||
@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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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<String> 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<Address> getAllAddresses() {
|
||||
SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
||||
Set<Address> 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;
|
||||
|
||||
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 {
|
||||
|
@ -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();
|
||||
|
@ -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,7 +45,8 @@ public class MultiDeviceBlockedUpdateJob extends MasterSecretJob implements Inje
|
||||
throws IOException, UntrustedIdentityException
|
||||
{
|
||||
RecipientDatabase database = DatabaseFactory.getRecipientDatabase(context);
|
||||
BlockedReader reader = database.readerForBlocked(database.getBlocked());
|
||||
|
||||
try (RecipientReader reader = database.readerForBlocked(database.getBlocked())) {
|
||||
List<String> blocked = new LinkedList<>();
|
||||
|
||||
Recipient recipient;
|
||||
@ -58,6 +59,7 @@ public class MultiDeviceBlockedUpdateJob extends MasterSecretJob implements Inje
|
||||
|
||||
messageSender.sendMessage(SignalServiceSyncMessage.forBlocked(new BlockedListMessage(blocked)));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onShouldRetryThrowable(Exception exception) {
|
||||
|
@ -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)
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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());
|
||||
|
||||
|
@ -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<Void, Void, Void>() {
|
||||
@Override
|
||||
protected Void doInBackground(Void... voids) {
|
||||
NotificationChannels.updateMessagesLedColor(getActivity(), (String) value);
|
||||
return null;
|
||||
}
|
||||
}.execute();
|
||||
}
|
||||
return super.onPreferenceChange(preference, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
@ -18,7 +19,7 @@ public class SignalListPreference extends ListPreference {
|
||||
|
||||
private TextView rightSummary;
|
||||
private CharSequence summary;
|
||||
private boolean dialogDisabled;
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user