Move notification preferences back in-app for O+.

Fixes #8147
This commit is contained in:
Greyson Parrelli 2018-08-30 17:59:15 -07:00
parent 3f9ddaf409
commit e840dc6687
11 changed files with 282 additions and 161 deletions

View File

@ -9,12 +9,6 @@
android:title="@string/preferences__notifications" android:title="@string/preferences__notifications"
android:defaultValue="true" /> 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 <org.thoughtcrime.securesms.preferences.widgets.SignalPreference
android:dependency="pref_key_enable_notifications" android:dependency="pref_key_enable_notifications"
android:key="pref_key_ringtone" android:key="pref_key_ringtone"

View File

@ -22,12 +22,6 @@
android:defaultValue="false" android:defaultValue="false"
android:persistent="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 <org.thoughtcrime.securesms.preferences.widgets.SignalPreference
android:dependency="pref_key_recipient_mute" android:dependency="pref_key_recipient_mute"
android:key="pref_key_recipient_ringtone" android:key="pref_key_recipient_ringtone"

View File

@ -94,7 +94,6 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
private static final String PREFERENCE_IDENTITY = "pref_key_recipient_identity"; private static final String PREFERENCE_IDENTITY = "pref_key_recipient_identity";
private static final String PREFERENCE_ABOUT = "pref_key_number"; 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_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 DynamicTheme dynamicTheme = new DynamicNoActionBarTheme();
private final DynamicLanguage dynamicLanguage = new DynamicLanguage(); private final DynamicLanguage dynamicLanguage = new DynamicLanguage();
@ -261,31 +260,40 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
.getBooleanExtra(RecipientPreferenceActivity.CAN_HAVE_SAFETY_NUMBER_EXTRA, false); .getBooleanExtra(RecipientPreferenceActivity.CAN_HAVE_SAFETY_NUMBER_EXTRA, false);
Preference customNotificationsPref = this.findPreference(PREFERENCE_CUSTOM_NOTIFICATIONS); 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()) { if (NotificationChannels.supported()) {
messageTonePref.setVisible(false); ((SwitchPreferenceCompat) customNotificationsPref).setChecked(recipient.getNotificationChannel() != null);
messageVibratePref.setVisible(false);
((SwitchPreferenceCompat) customNotificationsPref).setChecked(recipient.hasCustomNotifications());
customNotificationsPref.setOnPreferenceChangeListener(new CustomNotificationsChangedListener()); customNotificationsPref.setOnPreferenceChangeListener(new CustomNotificationsChangedListener());
notificationSettingsPref.setOnPreferenceClickListener(new NotificationSettingsClickedListener());
this.findPreference(PREFERENCE_MESSAGE_TONE).setDependency(PREFERENCE_CUSTOM_NOTIFICATIONS);
this.findPreference(PREFERENCE_MESSAGE_VIBRATE).setDependency(PREFERENCE_CUSTOM_NOTIFICATIONS);
if (recipient.getNotificationChannel() != null) {
final Context context = getContext();
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... voids) {
RecipientDatabase db = DatabaseFactory.getRecipientDatabase(getContext());
db.setMessageRingtone(recipient, NotificationChannels.getMessageRingtone(context, recipient));
db.setMessageVibrate(recipient, NotificationChannels.getMessageVibrate(context, recipient) ? VibrateState.ENABLED : VibrateState.DISABLED);
return null;
}
}.execute();
}
} else { } else {
customNotificationsPref.setVisible(false); customNotificationsPref.setVisible(false);
notificationSettingsPref.setVisible(false);
messageTonePref.setOnPreferenceChangeListener(new RingtoneChangeListener(false));
messageVibratePref.setOnPreferenceChangeListener(new VibrateChangeListener(false));
} }
this.findPreference(PREFERENCE_MESSAGE_TONE)
.setOnPreferenceChangeListener(new RingtoneChangeListener(false));
this.findPreference(PREFERENCE_MESSAGE_TONE) this.findPreference(PREFERENCE_MESSAGE_TONE)
.setOnPreferenceClickListener(new RingtoneClickedListener(false)); .setOnPreferenceClickListener(new RingtoneClickedListener(false));
this.findPreference(PREFERENCE_CALL_TONE) this.findPreference(PREFERENCE_CALL_TONE)
.setOnPreferenceChangeListener(new RingtoneChangeListener(true)); .setOnPreferenceChangeListener(new RingtoneChangeListener(true));
this.findPreference(PREFERENCE_CALL_TONE) this.findPreference(PREFERENCE_CALL_TONE)
.setOnPreferenceClickListener(new RingtoneClickedListener(true)); .setOnPreferenceClickListener(new RingtoneClickedListener(true));
this.findPreference(PREFERENCE_MESSAGE_VIBRATE)
.setOnPreferenceChangeListener(new VibrateChangeListener(false));
this.findPreference(PREFERENCE_CALL_VIBRATE) this.findPreference(PREFERENCE_CALL_VIBRATE)
.setOnPreferenceChangeListener(new VibrateChangeListener(true)); .setOnPreferenceChangeListener(new VibrateChangeListener(true));
this.findPreference(PREFERENCE_MUTED) this.findPreference(PREFERENCE_MUTED)
@ -356,13 +364,13 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
mutePreference.setChecked(recipient.isMuted()); mutePreference.setChecked(recipient.isMuted());
ringtoneMessagePreference.setSummary(getRingtoneSummary(getContext(), recipient.getMessageRingtone(getContext()))); ringtoneMessagePreference.setSummary(ringtoneMessagePreference.isEnabled() ? getRingtoneSummary(getContext(), recipient.getMessageRingtone(getContext())) : "");
ringtoneCallPreference.setSummary(getRingtoneSummary(getContext(), recipient.getCallRingtone())); ringtoneCallPreference.setSummary(getRingtoneSummary(getContext(), recipient.getCallRingtone()));
Pair<String, Integer> vibrateMessageSummary = getVibrateSummary(getContext(), recipient.getMessageVibrate()); Pair<String, Integer> vibrateMessageSummary = getVibrateSummary(getContext(), recipient.getMessageVibrate());
Pair<String, Integer> vibrateCallSummary = getVibrateSummary(getContext(), recipient.getCallVibrate()); Pair<String, Integer> vibrateCallSummary = getVibrateSummary(getContext(), recipient.getCallVibrate());
vibrateMessagePreference.setSummary(vibrateMessageSummary.first); vibrateMessagePreference.setSummary(vibrateMessagePreference.isEnabled() ? vibrateMessageSummary.first : "");
vibrateMessagePreference.setValueIndex(vibrateMessageSummary.second); vibrateMessagePreference.setValueIndex(vibrateMessageSummary.second);
vibrateCallPreference.setSummary(vibrateCallSummary.first); vibrateCallPreference.setSummary(vibrateCallSummary.first);
@ -473,8 +481,12 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
new AsyncTask<Uri, Void, Void>() { new AsyncTask<Uri, Void, Void>() {
@Override @Override
protected Void doInBackground(Uri... params) { protected Void doInBackground(Uri... params) {
if (calls) DatabaseFactory.getRecipientDatabase(getActivity()).setCallRingtone(recipient, params[0]); if (calls) {
else DatabaseFactory.getRecipientDatabase(getActivity()).setMessageRingtone(recipient, params[0]); DatabaseFactory.getRecipientDatabase(getActivity()).setCallRingtone(recipient, params[0]);
} else {
DatabaseFactory.getRecipientDatabase(getActivity()).setMessageRingtone(recipient, params[0]);
NotificationChannels.updateMessageRingtone(getActivity(), recipient, params[0]);
}
return null; return null;
} }
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, value); }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, value);
@ -536,8 +548,13 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
new AsyncTask<Void, Void, Void>() { new AsyncTask<Void, Void, Void>() {
@Override @Override
protected Void doInBackground(Void... params) { protected Void doInBackground(Void... params) {
if (call) DatabaseFactory.getRecipientDatabase(getActivity()).setCallVibrate(recipient, vibrateState); if (call) {
else DatabaseFactory.getRecipientDatabase(getActivity()).setMessageVibrate(recipient, vibrateState); DatabaseFactory.getRecipientDatabase(getActivity()).setCallVibrate(recipient, vibrateState);
}
else {
DatabaseFactory.getRecipientDatabase(getActivity()).setMessageVibrate(recipient, vibrateState);
NotificationChannels.updateMessageVibrate(getActivity(), recipient, vibrateState);
}
return null; return null;
} }
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
@ -742,7 +759,10 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
@Override @Override
public boolean onPreferenceClick(Preference preference) { public boolean onPreferenceClick(Preference preference) {
NotificationChannels.openChannelSettings(getActivity(), recipient.getNotificationChannel(getActivity())); String channel = recipient.getNotificationChannel();
if (channel != null) {
NotificationChannels.openChannelSettings(getActivity(), channel);
}
return true; return true;
} }
} }

View File

@ -344,15 +344,6 @@ public class RecipientDatabase extends Database {
recipient.setNotificationChannel(notificationChannel); 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() { public Set<Address> getAllAddresses() {
SQLiteDatabase db = databaseHelper.getReadableDatabase(); SQLiteDatabase db = databaseHelper.getReadableDatabase();
Set<Address> results = new HashSet<>(); Set<Address> results = new HashSet<>();

View File

@ -45,8 +45,8 @@ public abstract class AbstractNotificationBuilder extends NotificationCompat.Bui
} }
public void setAlarms(@Nullable Uri ringtone, RecipientDatabase.VibrateState vibrate) { public void setAlarms(@Nullable Uri ringtone, RecipientDatabase.VibrateState vibrate) {
Uri defaultRingtone = TextSecurePreferences.getNotificationRingtone(context); Uri defaultRingtone = NotificationChannels.supported() ? NotificationChannels.getMessageRingtone(context) : TextSecurePreferences.getNotificationRingtone(context);
boolean defaultVibrate = TextSecurePreferences.isNotificationVibrateEnabled(context); boolean defaultVibrate = NotificationChannels.supported() ? NotificationChannels.getMessageVibrate(context) : TextSecurePreferences.isNotificationVibrateEnabled(context);
if (ringtone == null && !TextUtils.isEmpty(defaultRingtone.toString())) setSound(defaultRingtone); if (ringtone == null && !TextUtils.isEmpty(defaultRingtone.toString())) setSound(defaultRingtone);
else if (ringtone != null && !ringtone.toString().isEmpty()) setSound(ringtone); else if (ringtone != null && !ringtone.toString().isEmpty()) setSound(ringtone);

View File

@ -381,7 +381,7 @@ public class MessageNotifier {
Uri uri = recipient != null ? recipient.resolve().getMessageRingtone(context) : null; Uri uri = recipient != null ? recipient.resolve().getMessageRingtone(context) : null;
if (uri == null) { if (uri == null) {
uri = TextSecurePreferences.getNotificationRingtone(context); uri = NotificationChannels.supported() ? NotificationChannels.getMessageRingtone(context) : TextSecurePreferences.getNotificationRingtone(context);
} }
if (uri.toString().isEmpty()) { if (uri.toString().isEmpty()) {

View File

@ -56,11 +56,7 @@ public class NotificationChannels {
return; return;
} }
NotificationManager notificationManager = context.getSystemService(NotificationManager.class); NotificationManager notificationManager = getNotificationManager(context);
if (notificationManager == null) {
Log.w(TAG, "Unable to retrieve notification manager. Can't setup channels.");
return;
}
int oldVersion = TextSecurePreferences.getNotificationChannelVersion(context); int oldVersion = TextSecurePreferences.getNotificationChannelVersion(context);
if (oldVersion != VERSION) { if (oldVersion != VERSION) {
@ -72,8 +68,7 @@ public class NotificationChannels {
} }
/** /**
* @return The channel ID for the default messages channel. Prefer * @return The channel ID for the default messages channel.
* {@link Recipient#getNotificationChannel(Context)} if you know the recipient.
*/ */
public static @NonNull String getMessagesChannel(@NonNull Context context) { public static @NonNull String getMessagesChannel(@NonNull Context context) {
return getMessagesChannelId(TextSecurePreferences.getNotificationMessagesChannelVersion(context)); return getMessagesChannelId(TextSecurePreferences.getNotificationMessagesChannelVersion(context));
@ -86,6 +81,9 @@ public class NotificationChannels {
return Build.VERSION.SDK_INT >= 26; return Build.VERSION.SDK_INT >= 26;
} }
/**
* @return A name suitable to be displayed as the notification channel title.
*/
public static @NonNull String getChannelDisplayNameFor(@NonNull Context context, @Nullable String systemName, @Nullable String profileName, @NonNull Address address) { public static @NonNull String getChannelDisplayNameFor(@NonNull Context context, @Nullable String systemName, @Nullable String profileName, @NonNull Address address) {
if (!TextUtils.isEmpty(systemName)) { if (!TextUtils.isEmpty(systemName)) {
return systemName; return systemName;
@ -105,22 +103,23 @@ public class NotificationChannels {
public static String createChannelFor(@NonNull Context context, @NonNull Recipient recipient) { public static String createChannelFor(@NonNull Context context, @NonNull Recipient recipient) {
VibrateState vibrateState = recipient.getMessageVibrate(); VibrateState vibrateState = recipient.getMessageVibrate();
boolean vibrationEnabled = vibrateState == VibrateState.DEFAULT ? TextSecurePreferences.isNotificationVibrateEnabled(context) : vibrateState == VibrateState.ENABLED; boolean vibrationEnabled = vibrateState == VibrateState.DEFAULT ? TextSecurePreferences.isNotificationVibrateEnabled(context) : vibrateState == VibrateState.ENABLED;
Uri messageRingtone = recipient.getMessageRingtone(context) != null ? recipient.getMessageRingtone(context) : getMessageRingtone(context);
String displayName = getChannelDisplayNameFor(context, recipient.getName(), recipient.getProfileName(), recipient.getAddress()); String displayName = getChannelDisplayNameFor(context, recipient.getName(), recipient.getProfileName(), recipient.getAddress());
return createChannelFor(context, recipient.getAddress(), displayName, recipient.getMessageRingtone(context), vibrationEnabled); return createChannelFor(context, recipient.getAddress(), displayName, messageRingtone, vibrationEnabled);
} }
/** /**
* More verbose version of {@link #createChannelFor(Context, Recipient)}. * More verbose version of {@link #createChannelFor(Context, Recipient)}.
*/ */
public static String createChannelFor(@NonNull Context context, public static @Nullable String createChannelFor(@NonNull Context context,
@NonNull Address address, @NonNull Address address,
@NonNull String displayName, @NonNull String displayName,
@Nullable Uri messageSound, @Nullable Uri messageSound,
boolean vibrationEnabled) boolean vibrationEnabled)
{ {
if (!supported()) { if (!supported()) {
return getMessagesChannel(context); return null;
} }
String channelId = generateChannelIdFor(address); String channelId = generateChannelIdFor(address);
@ -136,12 +135,7 @@ public class NotificationChannels {
.build()); .build());
} }
NotificationManager notificationManager = context.getSystemService(NotificationManager.class); NotificationManager notificationManager = getNotificationManager(context);
if (notificationManager == null) {
Log.w(TAG, "Unable to retrieve notification manager. Cannot create channel for recipient.");
return channelId;
}
notificationManager.createNotificationChannel(channel); notificationManager.createNotificationChannel(channel);
return channelId; return channelId;
@ -156,15 +150,11 @@ public class NotificationChannels {
return; return;
} }
NotificationManager notificationManager = context.getSystemService(NotificationManager.class); NotificationManager notificationManager = getNotificationManager(context);
if (notificationManager == null) { String channel = recipient.getNotificationChannel();
Log.w(TAG, "Unable to retrieve notification manager. Cannot delete channel.");
return;
}
String channel = recipient.getNotificationChannel(context); if (channel != null) {
Log.i(TAG, "Deleting channel");
if (!TextUtils.isEmpty(channel) && !getMessagesChannel(context).equals(channel)) {
notificationManager.deleteNotificationChannel(channel); notificationManager.deleteNotificationChannel(channel);
} }
} }
@ -192,15 +182,144 @@ public class NotificationChannels {
if (!supported()) { if (!supported()) {
return; return;
} }
Log.i(TAG, "Updating LED color.");
NotificationManager notificationManager = context.getSystemService(NotificationManager.class); NotificationManager notificationManager = getNotificationManager(context);
if (notificationManager == null) {
Log.w(TAG, "Unable to retrieve notification manager. Cannot update led color."); updateMessageChannel(context, channel -> setLedPreference(channel, color));
return; updateAllRecipientChannelLedColors(context, notificationManager, color);
}
/**
* @return The message ringtone set for the default message channel.
*/
public static @NonNull Uri getMessageRingtone(@NonNull Context context) {
if (!supported()) {
return Uri.EMPTY;
} }
updateMessageChannelLedColor(context, notificationManager, color); Uri sound = getNotificationManager(context).getNotificationChannel(getMessagesChannel(context)).getSound();
updateAllRecipientChannelLedColors(context, notificationManager, color); return sound == null ? Uri.EMPTY : sound;
}
public static @Nullable Uri getMessageRingtone(@NonNull Context context, @NonNull Recipient recipient) {
if (!supported() || recipient.getNotificationChannel() == null) {
return null;
}
NotificationManager notificationManager = getNotificationManager(context);
NotificationChannel channel = notificationManager.getNotificationChannel(recipient.getNotificationChannel());
if (!channelExists(channel)) {
Log.w(TAG, "Recipient had no channel. Returning null.");
return null;
}
return channel.getSound();
}
/**
* Update the message ringtone for the default message channel.
*/
public static void updateMessageRingtone(@NonNull Context context, @Nullable Uri uri) {
if (!supported()) {
return;
}
Log.i(TAG, "Updating default message ringtone with URI: " + String.valueOf(uri));
updateMessageChannel(context, channel -> {
channel.setSound(uri == null ? Settings.System.DEFAULT_NOTIFICATION_URI : uri, getRingtoneAudioAttributes());
});
}
/**
* Updates the message ringtone for a specific recipient. If that recipient has no channel, this
* does nothing.
*
* This has to update the database, and therefore should be run on a background thread.
*/
@WorkerThread
public static void updateMessageRingtone(@NonNull Context context, @NonNull Recipient recipient, @Nullable Uri uri) {
if (!supported() || recipient.getNotificationChannel() == null) {
return;
}
Log.i(TAG, "Updating recipient message ringtone with URI: " + String.valueOf(uri));
String newChannelId = generateChannelIdFor(recipient.getAddress());
updateExistingChannel(getNotificationManager(context),
recipient.getNotificationChannel(),
generateChannelIdFor(recipient.getAddress()),
channel -> channel.setSound(uri == null ? Settings.System.DEFAULT_NOTIFICATION_URI : uri, getRingtoneAudioAttributes()));
DatabaseFactory.getRecipientDatabase(context).setNotificationChannel(recipient, newChannelId);
}
/**
* @return The vibrate settings for the default message channel.
*/
public static boolean getMessageVibrate(@NonNull Context context) {
if (!supported()) {
return false;
}
return getNotificationManager(context).getNotificationChannel(getMessagesChannel(context)).shouldVibrate();
}
/**
* @return The vibrate setting for a specific recipient. If that recipient has no channel, this
* will return the setting for the default message channel.
*/
public static boolean getMessageVibrate(@NonNull Context context, @NonNull Recipient recipient) {
if (!supported()) {
return getMessageVibrate(context);
}
NotificationManager notificationManager = getNotificationManager(context);
NotificationChannel channel = notificationManager.getNotificationChannel(recipient.getNotificationChannel());
if (!channelExists(channel)) {
Log.w(TAG, "Recipient didn't have a channel. Returning message default.");
return getMessageVibrate(context);
}
return channel.shouldVibrate();
}
/**
* Sets the vibrate property for the default message channel.
*/
public static void updateMessageVibrate(@NonNull Context context, boolean enabled) {
if (!supported()) {
return;
}
Log.i(TAG, "Updating default vibrate with value: " + enabled);
updateMessageChannel(context, channel -> channel.enableVibration(enabled));
}
/**
* Updates the message ringtone for a specific recipient. If that recipient has no channel, this
* does nothing.
*
* This has to update the database and should therefore be run on a background thread.
*/
@WorkerThread
public static void updateMessageVibrate(@NonNull Context context, @NonNull Recipient recipient, VibrateState vibrateState) {
if (!supported() || recipient.getNotificationChannel() == null) {
return ;
}
Log.i(TAG, "Updating recipient vibrate with value: " + vibrateState);
boolean enabled = vibrateState == VibrateState.DEFAULT ? getMessageVibrate(context) : vibrateState == VibrateState.ENABLED;
String newChannelId = generateChannelIdFor(recipient.getAddress());
updateExistingChannel(getNotificationManager(context),
recipient.getNotificationChannel(),
newChannelId,
channel -> channel.enableVibration(enabled));
DatabaseFactory.getRecipientDatabase(context).setNotificationChannel(recipient, newChannelId);
} }
/** /**
@ -208,48 +327,25 @@ public class NotificationChannels {
* effect if the recipient doesn't have an existing valid channel. * effect if the recipient doesn't have an existing valid channel.
*/ */
public static void updateContactChannelName(@NonNull Context context, @NonNull Recipient recipient) { public static void updateContactChannelName(@NonNull Context context, @NonNull Recipient recipient) {
if (!supported() || !recipient.hasCustomNotifications()) { if (!supported() || recipient.getNotificationChannel() == null) {
return; return;
} }
Log.i(TAG, "Updating contact channel name");
NotificationManager notificationManager = context.getSystemService(NotificationManager.class); NotificationManager notificationManager = getNotificationManager(context);
if (notificationManager == null) {
Log.w(TAG, "Unable to retrieve notification manager. Cannot update channel name.");
return;
}
if (notificationManager.getNotificationChannel(recipient.getNotificationChannel(context)) == null) { if (notificationManager.getNotificationChannel(recipient.getNotificationChannel()) == null) {
Log.w(TAG, "Tried to update the name of a channel, but that channel doesn't exist."); Log.w(TAG, "Tried to update the name of a channel, but that channel doesn't exist.");
return; return;
} }
NotificationChannel channel = new NotificationChannel(recipient.getNotificationChannel(context), NotificationChannel channel = new NotificationChannel(recipient.getNotificationChannel(),
getChannelDisplayNameFor(context, recipient.getName(), recipient.getProfileName(), recipient.getAddress()), getChannelDisplayNameFor(context, recipient.getName(), recipient.getProfileName(), recipient.getAddress()),
NotificationManager.IMPORTANCE_HIGH); NotificationManager.IMPORTANCE_HIGH);
channel.setGroup(CATEGORY_MESSAGES); channel.setGroup(CATEGORY_MESSAGES);
notificationManager.createNotificationChannel(channel); notificationManager.createNotificationChannel(channel);
} }
public static @Nullable Uri getMessageRingtone(@NonNull Context context, @NonNull Recipient recipient) {
if (!supported()) {
return null;
}
NotificationManager notificationManager = context.getSystemService(NotificationManager.class);
if (notificationManager == null) {
Log.w(TAG, "Unable to retrieve notification manager. Cannot update channel name.");
return null;
}
NotificationChannel channel = notificationManager.getNotificationChannel(recipient.getNotificationChannel(context));
if (channel == null) {
Log.w(TAG, "Recipient had an invalid channel. Returning null.");
return null;
}
return channel.getSound();
}
@TargetApi(26) @TargetApi(26)
private static void onCreate(@NonNull Context context, @NonNull NotificationManager notificationManager) { private static void onCreate(@NonNull Context context, @NonNull NotificationManager notificationManager) {
NotificationChannelGroup messagesGroup = new NotificationChannelGroup(CATEGORY_MESSAGES, context.getResources().getString(R.string.NotificationChannel_group_messages)); NotificationChannelGroup messagesGroup = new NotificationChannelGroup(CATEGORY_MESSAGES, context.getResources().getString(R.string.NotificationChannel_group_messages));
@ -264,9 +360,7 @@ public class NotificationChannels {
messages.setGroup(CATEGORY_MESSAGES); messages.setGroup(CATEGORY_MESSAGES);
messages.enableVibration(TextSecurePreferences.isNotificationVibrateEnabled(context)); messages.enableVibration(TextSecurePreferences.isNotificationVibrateEnabled(context));
messages.setSound(TextSecurePreferences.getNotificationRingtone(context), new AudioAttributes.Builder().setContentType(AudioAttributes.CONTENT_TYPE_UNKNOWN) messages.setSound(TextSecurePreferences.getNotificationRingtone(context), getRingtoneAudioAttributes());
.setUsage(AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_INSTANT)
.build());
setLedPreference(messages, TextSecurePreferences.getNotificationLedColor(context)); setLedPreference(messages, TextSecurePreferences.getNotificationLedColor(context));
calls.setShowBadge(false); calls.setShowBadge(false);
@ -333,22 +427,6 @@ public class NotificationChannels {
return MESSAGES_PREFIX + 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 @WorkerThread
@TargetApi(26) @TargetApi(26)
private static void updateAllRecipientChannelLedColors(@NonNull Context context, @NonNull NotificationManager notificationManager, @NonNull String color) { private static void updateAllRecipientChannelLedColors(@NonNull Context context, @NonNull NotificationManager notificationManager, @NonNull String color) {
@ -357,17 +435,62 @@ public class NotificationChannels {
try (RecipientDatabase.RecipientReader recipients = database.getRecipientsWithNotificationChannels()) { try (RecipientDatabase.RecipientReader recipients = database.getRecipientsWithNotificationChannels()) {
Recipient recipient; Recipient recipient;
while ((recipient = recipients.getNext()) != null) { while ((recipient = recipients.getNext()) != null) {
NotificationChannel existingChannel = notificationManager.getNotificationChannel(recipient.getNotificationChannel(context)); assert recipient.getNotificationChannel() != null;
notificationManager.deleteNotificationChannel(existingChannel.getId());
NotificationChannel newChannel = copyChannel(existingChannel, generateChannelIdFor(recipient.getAddress())); String newChannelId = generateChannelIdFor(recipient.getAddress());
newChannel.setGroup(CATEGORY_MESSAGES); updateExistingChannel(notificationManager, recipient.getNotificationChannel(), newChannelId, channel -> setLedPreference(channel, color));
setLedPreference(newChannel, color); database.setNotificationChannel(recipient, newChannelId);
database.setNotificationChannel(recipient, newChannel.getId());
notificationManager.createNotificationChannel(newChannel);
} }
} }
} }
@TargetApi(26)
private static void updateMessageChannel(@NonNull Context context, @NonNull ChannelUpdater updater) {
NotificationManager notificationManager = getNotificationManager(context);
int existingVersion = TextSecurePreferences.getNotificationMessagesChannelVersion(context);
int newVersion = existingVersion + 1;
Log.i(TAG, "Updating message channel from version " + existingVersion + " to " + newVersion);
updateExistingChannel(notificationManager, getMessagesChannelId(existingVersion), getMessagesChannelId(newVersion), updater);
TextSecurePreferences.setNotificationMessagesChannelVersion(context, newVersion);
}
@TargetApi(26)
private static void updateExistingChannel(@NonNull NotificationManager notificationManager,
@NonNull String channelId,
@NonNull String newChannelId,
@NonNull ChannelUpdater updater)
{
NotificationChannel existingChannel = notificationManager.getNotificationChannel(channelId);
notificationManager.deleteNotificationChannel(existingChannel.getId());
NotificationChannel newChannel = copyChannel(existingChannel, newChannelId);
updater.update(newChannel);
notificationManager.createNotificationChannel(newChannel);
}
@TargetApi(21)
private static AudioAttributes getRingtoneAudioAttributes() {
return new AudioAttributes.Builder().setContentType(AudioAttributes.CONTENT_TYPE_UNKNOWN)
.setUsage(AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_INSTANT)
.build();
}
@TargetApi(26)
private static @NonNull NotificationManager getNotificationManager(@NonNull Context context) {
NotificationManager notificationManager = context.getSystemService(NotificationManager.class);
assert notificationManager != null;
return notificationManager;
}
@TargetApi(26)
private static boolean channelExists(@Nullable NotificationChannel channel) {
return channel != null && !NotificationChannel.DEFAULT_CHANNEL_ID.equals(channel);
}
private interface ChannelUpdater {
@TargetApi(26)
void update(@NonNull NotificationChannel channel);
}
} }

View File

@ -60,7 +60,8 @@ public class SingleRecipientNotificationBuilder extends AbstractNotificationBuil
} }
public void setThread(@NonNull Recipient recipient) { public void setThread(@NonNull Recipient recipient) {
setChannelId(recipient.getNotificationChannel(context)); String channelId = recipient.getNotificationChannel();
setChannelId(channelId != null ? channelId : NotificationChannels.getMessagesChannel(context));
if (privacy.isDisplayContact()) { if (privacy.isDisplayContact()) {
setContentTitle(recipient.toShortString()); setContentTitle(recipient.toShortString());

View File

@ -28,38 +28,26 @@ public class NotificationsPreferenceFragment extends ListSummaryPreferenceFragme
@SuppressWarnings("unused") @SuppressWarnings("unused")
private static final String TAG = NotificationsPreferenceFragment.class.getSimpleName(); private static final String TAG = NotificationsPreferenceFragment.class.getSimpleName();
private static final String PREF_SYSTEM_SETTINGS = "pref_key_system_notification_settings";
@Override @Override
public void onCreate(Bundle paramBundle) { public void onCreate(Bundle paramBundle) {
super.onCreate(paramBundle); super.onCreate(paramBundle);
Preference ledBlinkPref = this.findPreference(TextSecurePreferences.LED_BLINK_PREF); 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()) { if (NotificationChannels.supported()) {
ledBlinkPref.setVisible(false); ledBlinkPref.setVisible(false);
messageTonePref.setVisible(false); TextSecurePreferences.setNotificationRingtone(getContext(), NotificationChannels.getMessageRingtone(getContext()).toString());
vibratePref.setVisible(false); TextSecurePreferences.setNotificationVibrateEnabled(getContext(), NotificationChannels.getMessageVibrate(getContext()));
systemPref.setOnPreferenceClickListener(p -> {
NotificationChannels.openChannelSettings(getContext(), NotificationChannels.getMessagesChannel(getContext()));
return true;
});
} else { } else {
systemPref.setVisible(false);
ledBlinkPref.setOnPreferenceChangeListener(new ListSummaryListener()); ledBlinkPref.setOnPreferenceChangeListener(new ListSummaryListener());
messageTonePref.setOnPreferenceChangeListener(new RingtoneSummaryListener());
initializeListSummary((ListPreference) ledBlinkPref); initializeListSummary((ListPreference) ledBlinkPref);
initializeRingtoneSummary(messageTonePref);
} }
this.findPreference(TextSecurePreferences.LED_COLOR_PREF) this.findPreference(TextSecurePreferences.LED_COLOR_PREF)
.setOnPreferenceChangeListener(new LedColorChangeListener()); .setOnPreferenceChangeListener(new LedColorChangeListener());
this.findPreference(TextSecurePreferences.RINGTONE_PREF)
.setOnPreferenceChangeListener(new RingtoneSummaryListener());
this.findPreference(TextSecurePreferences.REPEAT_ALERTS_PREF) this.findPreference(TextSecurePreferences.REPEAT_ALERTS_PREF)
.setOnPreferenceChangeListener(new ListSummaryListener()); .setOnPreferenceChangeListener(new ListSummaryListener());
this.findPreference(TextSecurePreferences.NOTIFICATION_PRIVACY_PREF) this.findPreference(TextSecurePreferences.NOTIFICATION_PRIVACY_PREF)
@ -68,6 +56,11 @@ public class NotificationsPreferenceFragment extends ListSummaryPreferenceFragme
.setOnPreferenceChangeListener(new ListSummaryListener()); .setOnPreferenceChangeListener(new ListSummaryListener());
this.findPreference(TextSecurePreferences.CALL_RINGTONE_PREF) this.findPreference(TextSecurePreferences.CALL_RINGTONE_PREF)
.setOnPreferenceChangeListener(new RingtoneSummaryListener()); .setOnPreferenceChangeListener(new RingtoneSummaryListener());
this.findPreference(TextSecurePreferences.VIBRATE_PREF)
.setOnPreferenceChangeListener((preference, newValue) -> {
NotificationChannels.updateMessageVibrate(getContext(), (boolean) newValue);
return true;
});
this.findPreference(TextSecurePreferences.RINGTONE_PREF) this.findPreference(TextSecurePreferences.RINGTONE_PREF)
.setOnPreferenceClickListener(preference -> { .setOnPreferenceClickListener(preference -> {
@ -118,7 +111,9 @@ public class NotificationsPreferenceFragment extends ListSummaryPreferenceFragme
initializeListSummary((ListPreference) findPreference(TextSecurePreferences.NOTIFICATION_PRIORITY_PREF)); initializeListSummary((ListPreference) findPreference(TextSecurePreferences.NOTIFICATION_PRIORITY_PREF));
} }
initializeRingtoneSummary(findPreference(TextSecurePreferences.RINGTONE_PREF));
initializeCallRingtoneSummary(findPreference(TextSecurePreferences.CALL_RINGTONE_PREF)); initializeCallRingtoneSummary(findPreference(TextSecurePreferences.CALL_RINGTONE_PREF));
initializeMessageVibrateSummary((SwitchPreferenceCompat)findPreference(TextSecurePreferences.VIBRATE_PREF));
initializeCallVibrateSummary((SwitchPreferenceCompat)findPreference(TextSecurePreferences.CALL_VIBRATE_PREF)); initializeCallVibrateSummary((SwitchPreferenceCompat)findPreference(TextSecurePreferences.CALL_VIBRATE_PREF));
} }
@ -139,8 +134,10 @@ public class NotificationsPreferenceFragment extends ListSummaryPreferenceFragme
Uri uri = data.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI); Uri uri = data.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI);
if (Settings.System.DEFAULT_NOTIFICATION_URI.equals(uri)) { if (Settings.System.DEFAULT_NOTIFICATION_URI.equals(uri)) {
NotificationChannels.updateMessageRingtone(getContext(), uri);
TextSecurePreferences.removeNotificationRingtone(getContext()); TextSecurePreferences.removeNotificationRingtone(getContext());
} else { } else {
NotificationChannels.updateMessageRingtone(getContext(), uri);
TextSecurePreferences.setNotificationRingtone(getContext(), uri != null ? uri.toString() : Uri.EMPTY.toString()); TextSecurePreferences.setNotificationRingtone(getContext(), uri != null ? uri.toString() : Uri.EMPTY.toString());
} }
@ -191,6 +188,10 @@ public class NotificationsPreferenceFragment extends ListSummaryPreferenceFragme
listener.onPreferenceChange(pref, uri); listener.onPreferenceChange(pref, uri);
} }
private void initializeMessageVibrateSummary(SwitchPreferenceCompat pref) {
pref.setChecked(TextSecurePreferences.isNotificationVibrateEnabled(getContext()));
}
private void initializeCallVibrateSummary(SwitchPreferenceCompat pref) { private void initializeCallVibrateSummary(SwitchPreferenceCompat pref) {
pref.setChecked(TextSecurePreferences.isCallNotificationVibrateEnabled(getContext())); pref.setChecked(TextSecurePreferences.isCallNotificationVibrateEnabled(getContext()));
} }

View File

@ -591,11 +591,8 @@ public class Recipient implements RecipientModifiedListener {
if (notify) notifyListeners(); if (notify) notifyListeners();
} }
public synchronized @NonNull String getNotificationChannel(@NonNull Context context) { public synchronized @Nullable String getNotificationChannel() {
if (!NotificationChannels.supported() || notificationChannel == null) { return !NotificationChannels.supported() ? null : notificationChannel;
return NotificationChannels.getMessagesChannel(context);
}
return notificationChannel;
} }
public void setNotificationChannel(@Nullable String value) { public void setNotificationChannel(@Nullable String value) {
@ -611,10 +608,6 @@ public class Recipient implements RecipientModifiedListener {
if (notify) notifyListeners(); if (notify) notifyListeners();
} }
public synchronized boolean hasCustomNotifications() {
return NotificationChannels.supported() && notificationChannel != null;
}
public synchronized @Nullable byte[] getProfileKey() { public synchronized @Nullable byte[] getProfileKey() {
return profileKey; return profileKey;
} }

View File

@ -855,6 +855,10 @@ public class TextSecurePreferences {
setStringPreference(context, CALL_RINGTONE_PREF, ringtone); setStringPreference(context, CALL_RINGTONE_PREF, ringtone);
} }
public static void setNotificationVibrateEnabled(Context context, boolean enabled) {
setBooleanPreference(context, VIBRATE_PREF, enabled);
}
public static boolean isNotificationVibrateEnabled(Context context) { public static boolean isNotificationVibrateEnabled(Context context) {
return getBooleanPreference(context, VIBRATE_PREF, true); return getBooleanPreference(context, VIBRATE_PREF, true);
} }