From 71c7ef5b5e401cfc6e1c0658bc4e47f72145883f Mon Sep 17 00:00:00 2001 From: Moxie Marlinspike Date: Fri, 16 Feb 2018 11:10:35 -0800 Subject: [PATCH] Support for custom call ringtone selection and per-chat ringtones --- res/values/strings.xml | 4 + res/xml/preferences_notifications.xml | 24 +++ res/xml/recipient_preferences.xml | 19 ++ .../RecipientPreferenceActivity.java | 175 ++++++++++++------ .../securesms/database/RecipientDatabase.java | 76 ++++++-- .../database/helpers/SQLCipherOpenHelper.java | 10 +- .../notifications/MessageNotifier.java | 2 +- .../notifications/NotificationState.java | 4 +- .../NotificationsPreferenceFragment.java | 45 +++++ .../securesms/recipients/Recipient.java | 76 ++++++-- .../recipients/RecipientProvider.java | 12 +- .../securesms/service/WebRtcCallService.java | 13 +- .../securesms/util/TextSecurePreferences.java | 36 ++++ .../webrtc/audio/IncomingRinger.java | 31 ++-- .../webrtc/audio/SignalAudioManager.java | 6 +- 15 files changed, 408 insertions(+), 125 deletions(-) diff --git a/res/values/strings.xml b/res/values/strings.xml index f0402fce6e..fb3b147725 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -963,6 +963,8 @@ View safety number Chat settings Privacy + Call settings + Ringtone Signal Call @@ -1159,6 +1161,8 @@ Events In-chat sounds Show + Calls + Ringtone Show invitation prompts Display invitation prompts for contacts without Signal Message font size diff --git a/res/xml/preferences_notifications.xml b/res/xml/preferences_notifications.xml index 04ef9563f5..1fa08efe50 100644 --- a/res/xml/preferences_notifications.xml +++ b/res/xml/preferences_notifications.xml @@ -71,6 +71,30 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/org/thoughtcrime/securesms/RecipientPreferenceActivity.java b/src/org/thoughtcrime/securesms/RecipientPreferenceActivity.java index b4b2259bbb..16135c7e8e 100644 --- a/src/org/thoughtcrime/securesms/RecipientPreferenceActivity.java +++ b/src/org/thoughtcrime/securesms/RecipientPreferenceActivity.java @@ -27,6 +27,7 @@ import android.support.v7.preference.Preference; import android.support.v7.preference.PreferenceCategory; import android.support.v7.widget.Toolbar; import android.util.Log; +import android.util.Pair; import android.view.MenuItem; import android.view.View; import android.view.WindowManager; @@ -74,12 +75,14 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi public static final String ADDRESS_EXTRA = "recipient_address"; public static final String CAN_HAVE_SAFETY_NUMBER_EXTRA = "can_have_safety_number"; - private static final String PREFERENCE_MUTED = "pref_key_recipient_mute"; - private static final String PREFERENCE_TONE = "pref_key_recipient_ringtone"; - private static final String PREFERENCE_VIBRATE = "pref_key_recipient_vibrate"; - private static final String PREFERENCE_BLOCK = "pref_key_recipient_block"; - 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_MUTED = "pref_key_recipient_mute"; + private static final String PREFERENCE_MESSAGE_TONE = "pref_key_recipient_ringtone"; + private static final String PREFERENCE_CALL_TONE = "pref_key_recipient_call_ringtone"; + private static final String PREFERENCE_MESSAGE_VIBRATE = "pref_key_recipient_vibrate"; + private static final String PREFERENCE_CALL_VIBRATE = "pref_key_recipient_call_vibrate"; + private static final String PREFERENCE_BLOCK = "pref_key_recipient_block"; + private static final String PREFERENCE_COLOR = "pref_key_recipient_color"; + private static final String PREFERENCE_IDENTITY = "pref_key_recipient_identity"; private final DynamicTheme dynamicTheme = new DynamicNoActionBarTheme(); private final DynamicLanguage dynamicLanguage = new DynamicLanguage(); @@ -244,12 +247,18 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi this.canHaveSafetyNumber = getActivity().getIntent() .getBooleanExtra(RecipientPreferenceActivity.CAN_HAVE_SAFETY_NUMBER_EXTRA, false); - this.findPreference(PREFERENCE_TONE) - .setOnPreferenceChangeListener(new RingtoneChangeListener()); - this.findPreference(PREFERENCE_TONE) - .setOnPreferenceClickListener(new RingtoneClickedListener()); - this.findPreference(PREFERENCE_VIBRATE) - .setOnPreferenceChangeListener(new VibrateChangeListener()); + this.findPreference(PREFERENCE_MESSAGE_TONE) + .setOnPreferenceChangeListener(new RingtoneChangeListener(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) .setOnPreferenceClickListener(new MuteClickedListener()); this.findPreference(PREFERENCE_BLOCK) @@ -281,7 +290,11 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi if (requestCode == 1 && resultCode == RESULT_OK && data != null) { Uri uri = data.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI); - findPreference(PREFERENCE_TONE).getOnPreferenceChangeListener().onPreferenceChange(findPreference(PREFERENCE_TONE), uri); + findPreference(PREFERENCE_MESSAGE_TONE).getOnPreferenceChangeListener().onPreferenceChange(findPreference(PREFERENCE_MESSAGE_TONE), uri); + } else if (requestCode == 2 && resultCode == RESULT_OK && data != null) { + Uri uri = data.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI); + + findPreference(PREFERENCE_CALL_TONE).getOnPreferenceChangeListener().onPreferenceChange(findPreference(PREFERENCE_CALL_TONE), uri); } } @@ -291,41 +304,30 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi } private void setSummaries(Recipient recipient) { - CheckBoxPreference mutePreference = (CheckBoxPreference) this.findPreference(PREFERENCE_MUTED); - Preference ringtonePreference = this.findPreference(PREFERENCE_TONE); - ListPreference vibratePreference = (ListPreference) this.findPreference(PREFERENCE_VIBRATE); - ColorPickerPreference colorPreference = (ColorPickerPreference) this.findPreference(PREFERENCE_COLOR); - Preference blockPreference = this.findPreference(PREFERENCE_BLOCK); - Preference identityPreference = this.findPreference(PREFERENCE_IDENTITY); - PreferenceCategory privacyCategory = (PreferenceCategory)this.findPreference("privacy_settings"); - PreferenceCategory divider = (PreferenceCategory)this.findPreference("divider"); + CheckBoxPreference mutePreference = (CheckBoxPreference) this.findPreference(PREFERENCE_MUTED); + Preference ringtoneMessagePreference = this.findPreference(PREFERENCE_MESSAGE_TONE); + Preference ringtoneCallPreference = this.findPreference(PREFERENCE_CALL_TONE); + ListPreference vibrateMessagePreference = (ListPreference) this.findPreference(PREFERENCE_MESSAGE_VIBRATE); + ListPreference vibrateCallPreference = (ListPreference) this.findPreference(PREFERENCE_CALL_VIBRATE); + ColorPickerPreference colorPreference = (ColorPickerPreference) this.findPreference(PREFERENCE_COLOR); + Preference blockPreference = this.findPreference(PREFERENCE_BLOCK); + Preference identityPreference = this.findPreference(PREFERENCE_IDENTITY); + PreferenceCategory privacyCategory = (PreferenceCategory) this.findPreference("privacy_settings"); + PreferenceCategory divider = (PreferenceCategory) this.findPreference("divider"); mutePreference.setChecked(recipient.isMuted()); - final Uri toneUri = recipient.getRingtone(); + ringtoneMessagePreference.setSummary(getRingtoneSummary(getContext(), recipient.getMessageRingtone())); + ringtoneCallPreference.setSummary(getRingtoneSummary(getContext(), recipient.getCallRingtone())); - if (toneUri == null) { - ringtonePreference.setSummary(R.string.preferences__default); - } else if (toneUri.toString().isEmpty()) { - ringtonePreference.setSummary(R.string.preferences__silent); - } else { - Ringtone tone = RingtoneManager.getRingtone(getActivity(), toneUri); + Pair vibrateMessageSummary = getVibrateSummary(getContext(), recipient.getMessageVibrate()); + Pair vibrateCallSummary = getVibrateSummary(getContext(), recipient.getCallVibrate()); - if (tone != null) { - ringtonePreference.setSummary(tone.getTitle(getActivity())); - } - } + vibrateMessagePreference.setSummary(vibrateMessageSummary.first); + vibrateMessagePreference.setValueIndex(vibrateMessageSummary.second); - if (recipient.getVibrate() == VibrateState.DEFAULT) { - vibratePreference.setSummary(R.string.preferences__default); - vibratePreference.setValueIndex(0); - } else if (recipient.getVibrate() == VibrateState.ENABLED) { - vibratePreference.setSummary(R.string.RecipientPreferenceActivity_enabled); - vibratePreference.setValueIndex(1); - } else { - vibratePreference.setSummary(R.string.RecipientPreferenceActivity_disabled); - vibratePreference.setValueIndex(2); - } + vibrateCallPreference.setSummary(vibrateCallSummary.first); + vibrateCallPreference.setValueIndex(vibrateCallSummary.second); if (recipient.isGroupRecipient()) { if (colorPreference != null) colorPreference.setVisible(false); @@ -362,27 +364,62 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi } } + private @NonNull String getRingtoneSummary(@NonNull Context context, @Nullable Uri ringtone) { + if (ringtone == null) { + return context.getString(R.string.preferences__default); + } else if (ringtone.toString().isEmpty()) { + return context.getString(R.string.preferences__silent); + } else { + Ringtone tone = RingtoneManager.getRingtone(getActivity(), ringtone); + + if (tone != null) { + return tone.getTitle(context); + } + } + + return context.getString(R.string.preferences__default); + } + + private @NonNull Pair getVibrateSummary(@NonNull Context context, @NonNull VibrateState vibrateState) { + if (vibrateState == VibrateState.DEFAULT) { + return new Pair<>(context.getString(R.string.preferences__default), 0); + } else if (vibrateState == VibrateState.ENABLED) { + return new Pair<>(context.getString(R.string.RecipientPreferenceActivity_enabled), 1); + } else { + return new Pair<>(context.getString(R.string.RecipientPreferenceActivity_disabled), 2); + } + } + @Override public void onModified(final Recipient recipient) { Util.runOnMain(() -> setSummaries(recipient)); } private class RingtoneChangeListener implements Preference.OnPreferenceChangeListener { + + private final boolean calls; + + RingtoneChangeListener(boolean calls) { + this.calls = calls; + } + @Override public boolean onPreferenceChange(Preference preference, Object newValue) { Uri value = (Uri)newValue; - if (TextSecurePreferences.getNotificationRingtone(getContext()).equals(value)) { - value = null; - } else if (value == null) { - value = Uri.EMPTY; - } + Uri defaultValue; + + if (calls) defaultValue = TextSecurePreferences.getCallNotificationRingtone(getContext()); + else defaultValue = TextSecurePreferences.getNotificationRingtone(getContext()); + + if (defaultValue.equals(value)) value = null; + else if (value == null) value = Uri.EMPTY; new AsyncTask() { @Override protected Void doInBackground(Uri... params) { - DatabaseFactory.getRecipientDatabase(getActivity()) - .setRingtone(recipient, params[0]); + if (calls) DatabaseFactory.getRecipientDatabase(getActivity()).setCallRingtone(recipient, params[0]); + else DatabaseFactory.getRecipientDatabase(getActivity()).setMessageRingtone(recipient, params[0]); return null; } }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, value); @@ -393,27 +430,49 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi private class RingtoneClickedListener implements Preference.OnPreferenceClickListener { + private final boolean calls; + + RingtoneClickedListener(boolean calls) { + this.calls = calls; + } + @Override public boolean onPreferenceClick(Preference preference) { - Uri uri = recipient.getRingtone(); + Uri current; + Uri defaultUri; - if (uri == null) uri = Settings.System.DEFAULT_NOTIFICATION_URI; - else if (uri.toString().isEmpty()) uri = null; + if (calls) { + current = recipient.getCallRingtone(); + defaultUri = TextSecurePreferences.getCallNotificationRingtone(getContext()); + } else { + current = recipient.getMessageRingtone(); + defaultUri = TextSecurePreferences.getNotificationRingtone(getContext()); + } + + if (current == null) current = Settings.System.DEFAULT_NOTIFICATION_URI; + else if (current.toString().isEmpty()) current = null; Intent intent = new Intent(RingtoneManager.ACTION_RINGTONE_PICKER); intent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_SILENT, true); intent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_DEFAULT, true); - intent.putExtra(RingtoneManager.EXTRA_RINGTONE_DEFAULT_URI, TextSecurePreferences.getNotificationRingtone(getContext())); - intent.putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, RingtoneManager.TYPE_NOTIFICATION); - intent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, uri); + intent.putExtra(RingtoneManager.EXTRA_RINGTONE_DEFAULT_URI, defaultUri); + intent.putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, calls ? RingtoneManager.TYPE_RINGTONE : RingtoneManager.TYPE_NOTIFICATION); + intent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, current); - startActivityForResult(intent, 1); + startActivityForResult(intent, calls ? 2 : 1); return true; } } private class VibrateChangeListener implements Preference.OnPreferenceChangeListener { + + private final boolean call; + + VibrateChangeListener(boolean call) { + this.call = call; + } + @Override public boolean onPreferenceChange(Preference preference, Object newValue) { int value = Integer.parseInt((String) newValue); @@ -422,8 +481,8 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi new AsyncTask() { @Override protected Void doInBackground(Void... params) { - DatabaseFactory.getRecipientDatabase(getActivity()) - .setVibrate(recipient, vibrateState); + if (call) DatabaseFactory.getRecipientDatabase(getActivity()).setCallVibrate(recipient, vibrateState); + else DatabaseFactory.getRecipientDatabase(getActivity()).setMessageVibrate(recipient, vibrateState); return null; } }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); diff --git a/src/org/thoughtcrime/securesms/database/RecipientDatabase.java b/src/org/thoughtcrime/securesms/database/RecipientDatabase.java index 7858a96106..2ee6a381e2 100644 --- a/src/org/thoughtcrime/securesms/database/RecipientDatabase.java +++ b/src/org/thoughtcrime/securesms/database/RecipientDatabase.java @@ -51,9 +51,11 @@ public class RecipientDatabase extends Database { private static final String SIGNAL_PROFILE_NAME = "signal_profile_name"; private static final String SIGNAL_PROFILE_AVATAR = "signal_profile_avatar"; 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[] RECIPIENT_PROJECTION = new String[] { - BLOCK, NOTIFICATION, VIBRATE, MUTE_UNTIL, COLOR, SEEN_INVITE_REMINDER, DEFAULT_SUBSCRIPTION_ID, EXPIRE_MESSAGES, REGISTERED, + 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 }; @@ -118,7 +120,9 @@ public class RecipientDatabase extends Database { PROFILE_KEY + " TEXT DEFAULT NULL, " + SIGNAL_PROFILE_NAME + " TEXT DEFAULT NULL, " + SIGNAL_PROFILE_AVATAR + " TEXT DEFAULT NULL, " + - PROFILE_SHARING + " INTEGER DEFAULT 0);"; + PROFILE_SHARING + " INTEGER DEFAULT 0, " + + CALL_RINGTONE + " TEXT DEFAULT NULL, " + + CALL_VIBRATE + " INTEGER DEFAULT " + VibrateState.DEFAULT.getId() + ");"; public RecipientDatabase(Context context, SQLCipherOpenHelper databaseHelper) { super(context, databaseHelper); @@ -155,8 +159,10 @@ public class RecipientDatabase extends Database { Optional getRecipientSettings(@NonNull Cursor cursor) { boolean blocked = cursor.getInt(cursor.getColumnIndexOrThrow(BLOCK)) == 1; - String notification = cursor.getString(cursor.getColumnIndexOrThrow(NOTIFICATION)); - int vibrateState = cursor.getInt(cursor.getColumnIndexOrThrow(VIBRATE)); + String messageRingtone = cursor.getString(cursor.getColumnIndexOrThrow(NOTIFICATION)); + String callRingtone = cursor.getString(cursor.getColumnIndexOrThrow(CALL_RINGTONE)); + int messageVibrateState = cursor.getInt(cursor.getColumnIndexOrThrow(VIBRATE)); + int callVibrateState = cursor.getInt(cursor.getColumnIndexOrThrow(CALL_VIBRATE)); long muteUntil = cursor.getLong(cursor.getColumnIndexOrThrow(MUTE_UNTIL)); String serializedColor = cursor.getString(cursor.getColumnIndexOrThrow(COLOR)); boolean seenInviteReminder = cursor.getInt(cursor.getColumnIndexOrThrow(SEEN_INVITE_REMINDER)) == 1; @@ -192,8 +198,10 @@ public class RecipientDatabase extends Database { } return Optional.of(new RecipientSettings(blocked, muteUntil, - VibrateState.fromId(vibrateState), - Util.uri(notification), color, seenInviteReminder, + VibrateState.fromId(messageVibrateState), + VibrateState.fromId(callVibrateState), + Util.uri(messageRingtone), Util.uri(callRingtone), + color, seenInviteReminder, defaultSubscriptionId, expireMessages, RegisteredState.fromId(registeredState), profileKey, systemDisplayName, systemContactPhoto, @@ -237,18 +245,32 @@ public class RecipientDatabase extends Database { recipient.resolve().setBlocked(blocked); } - public void setRingtone(@NonNull Recipient recipient, @Nullable Uri notification) { + public void setMessageRingtone(@NonNull Recipient recipient, @Nullable Uri notification) { ContentValues values = new ContentValues(); values.put(NOTIFICATION, notification == null ? null : notification.toString()); updateOrInsert(recipient.getAddress(), values); - recipient.resolve().setRingtone(notification); + recipient.resolve().setMessageRingtone(notification); } - public void setVibrate(@NonNull Recipient recipient, @NonNull VibrateState enabled) { + public void setCallRingtone(@NonNull Recipient recipient, @Nullable Uri ringtone) { + ContentValues values = new ContentValues(); + values.put(CALL_RINGTONE, ringtone == null ? null : ringtone.toString()); + updateOrInsert(recipient.getAddress(), values); + recipient.resolve().setCallRingtone(ringtone); + } + + public void setMessageVibrate(@NonNull Recipient recipient, @NonNull VibrateState enabled) { ContentValues values = new ContentValues(); values.put(VIBRATE, enabled.getId()); updateOrInsert(recipient.getAddress(), values); - recipient.resolve().setVibrate(enabled); + recipient.resolve().setMessageVibrate(enabled); + } + + public void setCallVibrate(@NonNull Recipient recipient, @NonNull VibrateState enabled) { + ContentValues values = new ContentValues(); + values.put(CALL_VIBRATE, enabled.getId()); + updateOrInsert(recipient.getAddress(), values); + recipient.resolve().setCallVibrate(enabled); } public void setMuted(@NonNull Recipient recipient, long until) { @@ -433,8 +455,10 @@ public class RecipientDatabase extends Database { public static class RecipientSettings { private final boolean blocked; private final long muteUntil; - private final VibrateState vibrateState; - private final Uri notification; + private final VibrateState messageVibrateState; + private final VibrateState callVibrateState; + private final Uri messageRingtone; + private final Uri callRingtone; private final MaterialColor color; private final boolean seenInviteReminder; private final int defaultSubscriptionId; @@ -450,8 +474,10 @@ public class RecipientDatabase extends Database { private final boolean profileSharing; RecipientSettings(boolean blocked, long muteUntil, - @NonNull VibrateState vibrateState, - @Nullable Uri notification, + @NonNull VibrateState messageVibrateState, + @NonNull VibrateState callVibrateState, + @Nullable Uri messageRingtone, + @Nullable Uri callRingtone, @Nullable MaterialColor color, boolean seenInviteReminder, int defaultSubscriptionId, @@ -468,8 +494,10 @@ public class RecipientDatabase extends Database { { this.blocked = blocked; this.muteUntil = muteUntil; - this.vibrateState = vibrateState; - this.notification = notification; + this.messageVibrateState = messageVibrateState; + this.callVibrateState = callVibrateState; + this.messageRingtone = messageRingtone; + this.callRingtone = callRingtone; this.color = color; this.seenInviteReminder = seenInviteReminder; this.defaultSubscriptionId = defaultSubscriptionId; @@ -497,12 +525,20 @@ public class RecipientDatabase extends Database { return muteUntil; } - public @NonNull VibrateState getVibrateState() { - return vibrateState; + public @NonNull VibrateState getMessageVibrateState() { + return messageVibrateState; } - public @Nullable Uri getRingtone() { - return notification; + public @NonNull VibrateState getCallVibrateState() { + return callVibrateState; + } + + public @Nullable Uri getMessageRingtone() { + return messageRingtone; + } + + public @Nullable Uri getCallRingtone() { + return callRingtone; } public boolean hasSeenInviteReminder() { diff --git a/src/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java b/src/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java index c7728a4793..7dda134b89 100644 --- a/src/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java +++ b/src/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java @@ -26,9 +26,12 @@ import org.thoughtcrime.securesms.util.TextSecurePreferences; public class SQLCipherOpenHelper extends SQLiteOpenHelper { + @SuppressWarnings("unused") private static final String TAG = SQLCipherOpenHelper.class.getSimpleName(); - private static final int DATABASE_VERSION = 1; + private static final int RECIPIENT_CALL_RINGTONE_VERSION = 2; + + private static final int DATABASE_VERSION = 2; private static final String DATABASE_NAME = "signal.db"; private final Context context; @@ -89,7 +92,12 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper { @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { + Log.w(TAG, "Upgrading database: " + oldVersion + ", " + newVersion); + if (oldVersion < RECIPIENT_CALL_RINGTONE_VERSION) { + db.execSQL("ALTER TABLE recipient_preferences ADD COLUMN call_ringtone TEXT DEFAULT NULL"); + db.execSQL("ALTER TABLE recipient_preferences ADD COLUMN call_vibrate INTEGER DEFAULT " + RecipientDatabase.VibrateState.DEFAULT.getId()); + } } public SQLiteDatabase getReadableDatabase() { diff --git a/src/org/thoughtcrime/securesms/notifications/MessageNotifier.java b/src/org/thoughtcrime/securesms/notifications/MessageNotifier.java index fba5fb0c43..240c425d6f 100644 --- a/src/org/thoughtcrime/securesms/notifications/MessageNotifier.java +++ b/src/org/thoughtcrime/securesms/notifications/MessageNotifier.java @@ -373,7 +373,7 @@ public class MessageNotifier { return; } - Uri uri = recipient != null ? recipient.getRingtone() : null; + Uri uri = recipient != null ? recipient.resolve().getMessageRingtone() : null; if (uri == null) { uri = TextSecurePreferences.getNotificationRingtone(context); diff --git a/src/org/thoughtcrime/securesms/notifications/NotificationState.java b/src/org/thoughtcrime/securesms/notifications/NotificationState.java index 89c58a5d86..3595545f08 100644 --- a/src/org/thoughtcrime/securesms/notifications/NotificationState.java +++ b/src/org/thoughtcrime/securesms/notifications/NotificationState.java @@ -48,7 +48,7 @@ public class NotificationState { Recipient recipient = notifications.getFirst().getRecipient(); if (recipient != null) { - return recipient.getRingtone(); + return recipient.resolve().getMessageRingtone(); } } @@ -60,7 +60,7 @@ public class NotificationState { Recipient recipient = notifications.getFirst().getRecipient(); if (recipient != null) { - return recipient.getVibrate(); + return recipient.resolve().getMessageVibrate(); } } diff --git a/src/org/thoughtcrime/securesms/preferences/NotificationsPreferenceFragment.java b/src/org/thoughtcrime/securesms/preferences/NotificationsPreferenceFragment.java index 83df74f7b8..4d29b6f0cb 100644 --- a/src/org/thoughtcrime/securesms/preferences/NotificationsPreferenceFragment.java +++ b/src/org/thoughtcrime/securesms/preferences/NotificationsPreferenceFragment.java @@ -16,8 +16,11 @@ import android.text.TextUtils; import org.thoughtcrime.securesms.ApplicationPreferencesActivity; import org.thoughtcrime.securesms.R; +import org.thoughtcrime.securesms.components.SwitchPreferenceCompat; import org.thoughtcrime.securesms.notifications.MessageNotifier; +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; @@ -42,6 +45,8 @@ public class NotificationsPreferenceFragment extends ListSummaryPreferenceFragme .setOnPreferenceChangeListener(new NotificationPrivacyListener()); this.findPreference(TextSecurePreferences.NOTIFICATION_PRIORITY_PREF) .setOnPreferenceChangeListener(new ListSummaryListener()); + this.findPreference(TextSecurePreferences.CALL_RINGTONE_PREF) + .setOnPreferenceChangeListener(new RingtoneSummaryListener()); this.findPreference(TextSecurePreferences.RINGTONE_PREF) .setOnPreferenceClickListener(preference -> { @@ -59,12 +64,31 @@ public class NotificationsPreferenceFragment extends ListSummaryPreferenceFragme return true; }); + this.findPreference(TextSecurePreferences.CALL_RINGTONE_PREF) + .setOnPreferenceClickListener(preference -> { + Uri current = TextSecurePreferences.getCallNotificationRingtone(getContext()); + + Intent intent = new Intent(RingtoneManager.ACTION_RINGTONE_PICKER); + intent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_DEFAULT, true); + intent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_SILENT, true); + intent.putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, RingtoneManager.TYPE_RINGTONE); + intent.putExtra(RingtoneManager.EXTRA_RINGTONE_DEFAULT_URI, Settings.System.DEFAULT_RINGTONE_URI); + intent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, current); + + startActivityForResult(intent, 2); + + return true; + }); + 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)); 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)); } @Override @@ -90,6 +114,16 @@ public class NotificationsPreferenceFragment extends ListSummaryPreferenceFragme } initializeRingtoneSummary(findPreference(TextSecurePreferences.RINGTONE_PREF)); + } else if (requestCode == 2 && resultCode == RESULT_OK && data != null) { + Uri uri = data.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI); + + if (Settings.System.DEFAULT_RINGTONE_URI.equals(uri)) { + TextSecurePreferences.removeCallNotificationRingtone(getContext()); + } else { + TextSecurePreferences.setCallNotificationRingtone(getContext(), uri != null ? uri.toString() : Uri.EMPTY.toString()); + } + + initializeCallRingtoneSummary(findPreference(TextSecurePreferences.CALL_RINGTONE_PREF)); } } @@ -119,6 +153,17 @@ public class NotificationsPreferenceFragment extends ListSummaryPreferenceFragme listener.onPreferenceChange(pref, uri); } + private void initializeCallRingtoneSummary(Preference pref) { + RingtoneSummaryListener listener = (RingtoneSummaryListener) pref.getOnPreferenceChangeListener(); + Uri uri = TextSecurePreferences.getCallNotificationRingtone(getContext()); + + listener.onPreferenceChange(pref, uri); + } + + private void initializeCallVibrateSummary(SwitchPreferenceCompat pref) { + pref.setChecked(TextSecurePreferences.isCallNotificationVibrateEnabled(getContext())); + } + public static CharSequence getSummary(Context context) { final int onCapsResId = R.string.ApplicationPreferencesActivity_On; final int offCapsResId = R.string.ApplicationPreferencesActivity_Off; diff --git a/src/org/thoughtcrime/securesms/recipients/Recipient.java b/src/org/thoughtcrime/securesms/recipients/Recipient.java index f0a0786c7d..55e2b8073a 100644 --- a/src/org/thoughtcrime/securesms/recipients/Recipient.java +++ b/src/org/thoughtcrime/securesms/recipients/Recipient.java @@ -74,10 +74,12 @@ public class Recipient implements RecipientModifiedListener { private @Nullable Uri systemContactPhoto; private @Nullable Long groupAvatarId; private Uri contactUri; - private @Nullable Uri ringtone = null; + private @Nullable Uri messageRingtone = null; + private @Nullable Uri callRingtone = null; private long mutedUntil = 0; private boolean blocked = false; - private VibrateState vibrate = VibrateState.DEFAULT; + private VibrateState messageVibrate = VibrateState.DEFAULT; + private VibrateState callVibrate = VibrateState.DEFAULT; private int expireMessages = 0; private Optional defaultSubscriptionId = Optional.absent(); private @NonNull RegisteredState registered = RegisteredState.UNKNOWN; @@ -124,10 +126,12 @@ public class Recipient implements RecipientModifiedListener { this.groupAvatarId = stale.groupAvatarId; this.color = stale.color; this.customLabel = stale.customLabel; - this.ringtone = stale.ringtone; + this.messageRingtone = stale.messageRingtone; + this.callRingtone = stale.callRingtone; this.mutedUntil = stale.mutedUntil; this.blocked = stale.blocked; - this.vibrate = stale.vibrate; + this.messageVibrate = stale.messageVibrate; + this.callVibrate = stale.callVibrate; this.expireMessages = stale.expireMessages; this.seenInviteReminder = stale.seenInviteReminder; this.defaultSubscriptionId = stale.defaultSubscriptionId; @@ -146,10 +150,12 @@ public class Recipient implements RecipientModifiedListener { this.systemContactPhoto = details.get().systemContactPhoto; this.groupAvatarId = details.get().groupAvatarId; this.color = details.get().color; - this.ringtone = details.get().ringtone; + this.messageRingtone = details.get().messageRingtone; + this.callRingtone = details.get().callRingtone; this.mutedUntil = details.get().mutedUntil; this.blocked = details.get().blocked; - this.vibrate = details.get().vibrateState; + this.messageVibrate = details.get().messageVibrateState; + this.callVibrate = details.get().callVibrateState; this.expireMessages = details.get().expireMessages; this.seenInviteReminder = details.get().seenInviteReminder; this.defaultSubscriptionId = details.get().defaultSubscriptionId; @@ -174,10 +180,12 @@ public class Recipient implements RecipientModifiedListener { Recipient.this.groupAvatarId = result.groupAvatarId; Recipient.this.color = result.color; Recipient.this.customLabel = result.customLabel; - Recipient.this.ringtone = result.ringtone; + Recipient.this.messageRingtone = result.messageRingtone; + Recipient.this.callRingtone = result.callRingtone; Recipient.this.mutedUntil = result.mutedUntil; Recipient.this.blocked = result.blocked; - Recipient.this.vibrate = result.vibrateState; + Recipient.this.messageVibrate = result.messageVibrateState; + Recipient.this.callVibrate = result.callVibrateState; Recipient.this.expireMessages = result.expireMessages; Recipient.this.seenInviteReminder = result.seenInviteReminder; Recipient.this.defaultSubscriptionId = result.defaultSubscriptionId; @@ -219,10 +227,12 @@ public class Recipient implements RecipientModifiedListener { this.groupAvatarId = details.groupAvatarId; this.color = details.color; this.customLabel = details.customLabel; - this.ringtone = details.ringtone; + this.messageRingtone = details.messageRingtone; + this.callRingtone = details.callRingtone; this.mutedUntil = details.mutedUntil; this.blocked = details.blocked; - this.vibrate = details.vibrateState; + this.messageVibrate = details.messageVibrateState; + this.callVibrate = details.callVibrateState; this.expireMessages = details.expireMessages; this.seenInviteReminder = details.seenInviteReminder; this.defaultSubscriptionId = details.defaultSubscriptionId; @@ -452,17 +462,33 @@ public class Recipient implements RecipientModifiedListener { if (notify) notifyListeners(); } - public synchronized @Nullable Uri getRingtone() { - if (ringtone != null && ringtone.getScheme() != null && ringtone.getScheme().startsWith("file")) { + public synchronized @Nullable Uri getMessageRingtone() { + if (messageRingtone != null && messageRingtone.getScheme() != null && messageRingtone.getScheme().startsWith("file")) { return null; } - return ringtone; + return messageRingtone; } - public void setRingtone(@Nullable Uri ringtone) { + public void setMessageRingtone(@Nullable Uri ringtone) { synchronized (this) { - this.ringtone = ringtone; + this.messageRingtone = ringtone; + } + + notifyListeners(); + } + + public synchronized @Nullable Uri getCallRingtone() { + if (callRingtone != null && callRingtone.getScheme() != null && callRingtone.getScheme().startsWith("file")) { + return null; + } + + return callRingtone; + } + + public void setCallRingtone(@Nullable Uri ringtone) { + synchronized (this) { + this.callRingtone = ringtone; } notifyListeners(); @@ -492,13 +518,25 @@ public class Recipient implements RecipientModifiedListener { notifyListeners(); } - public synchronized VibrateState getVibrate() { - return vibrate; + public synchronized VibrateState getMessageVibrate() { + return messageVibrate; } - public void setVibrate(VibrateState vibrate) { + public void setMessageVibrate(VibrateState vibrate) { synchronized (this) { - this.vibrate = vibrate; + this.messageVibrate = vibrate; + } + + notifyListeners(); + } + + public synchronized VibrateState getCallVibrate() { + return callVibrate; + } + + public void setCallVibrate(VibrateState vibrate) { + synchronized (this) { + this.callVibrate = vibrate; } notifyListeners(); diff --git a/src/org/thoughtcrime/securesms/recipients/RecipientProvider.java b/src/org/thoughtcrime/securesms/recipients/RecipientProvider.java index a05912c12a..468932bbfd 100644 --- a/src/org/thoughtcrime/securesms/recipients/RecipientProvider.java +++ b/src/org/thoughtcrime/securesms/recipients/RecipientProvider.java @@ -158,9 +158,11 @@ class RecipientProvider { @Nullable final Uri contactUri; @Nullable final Long groupAvatarId; @Nullable final MaterialColor color; - @Nullable final Uri ringtone; + @Nullable final Uri messageRingtone; + @Nullable final Uri callRingtone; final long mutedUntil; - @Nullable final VibrateState vibrateState; + @Nullable final VibrateState messageVibrateState; + @Nullable final VibrateState callVibrateState; final boolean blocked; final int expireMessages; @NonNull final List participants; @@ -182,9 +184,11 @@ class RecipientProvider { this.customLabel = settings != null ? settings.getSystemPhoneLabel() : null; this.contactUri = settings != null ? Util.uri(settings.getSystemContactUri()) : null; this.color = settings != null ? settings.getColor() : null; - this.ringtone = settings != null ? settings.getRingtone() : null; + this.messageRingtone = settings != null ? settings.getMessageRingtone() : null; + this.callRingtone = settings != null ? settings.getCallRingtone() : null; this.mutedUntil = settings != null ? settings.getMuteUntil() : 0; - this.vibrateState = settings != null ? settings.getVibrateState() : null; + this.messageVibrateState = settings != null ? settings.getMessageVibrateState() : null; + this.callVibrateState = settings != null ? settings.getCallVibrateState() : null; this.blocked = settings != null && settings.isBlocked(); this.expireMessages = settings != null ? settings.getExpireMessages() : 0; this.participants = participants == null ? new LinkedList<>() : participants; diff --git a/src/org/thoughtcrime/securesms/service/WebRtcCallService.java b/src/org/thoughtcrime/securesms/service/WebRtcCallService.java index e2dd5f3b8e..2734cb586d 100644 --- a/src/org/thoughtcrime/securesms/service/WebRtcCallService.java +++ b/src/org/thoughtcrime/securesms/service/WebRtcCallService.java @@ -8,6 +8,7 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.media.AudioManager; +import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.os.Handler; @@ -29,6 +30,8 @@ import org.thoughtcrime.securesms.WebRtcCallActivity; import org.thoughtcrime.securesms.contacts.ContactAccessor; 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.dependencies.InjectableType; import org.thoughtcrime.securesms.events.WebRtcViewModel; import org.thoughtcrime.securesms.notifications.MessageNotifier; @@ -540,7 +543,15 @@ public class WebRtcCallService extends Service implements InjectableType, PeerCo sendMessage(WebRtcViewModel.State.CALL_INCOMING, recipient, localVideoEnabled, remoteVideoEnabled, bluetoothAvailable, microphoneEnabled); startCallCardActivity(); audioManager.initializeAudioForCall(); - audioManager.startIncomingRinger(); + + if (TextSecurePreferences.isCallNotificationsEnabled(this)) { + Uri ringtone = recipient.resolve().getCallRingtone(); + VibrateState vibrateState = recipient.resolve().getCallVibrate(); + + if (ringtone == null) ringtone = TextSecurePreferences.getCallNotificationRingtone(this); + + audioManager.startIncomingRinger(ringtone, vibrateState == VibrateState.ENABLED || (vibrateState == VibrateState.DEFAULT && TextSecurePreferences.isCallNotificationVibrateEnabled(this))); + } registerPowerButtonReceiver(); diff --git a/src/org/thoughtcrime/securesms/util/TextSecurePreferences.java b/src/org/thoughtcrime/securesms/util/TextSecurePreferences.java index 2a1f318160..289f1c40b9 100644 --- a/src/org/thoughtcrime/securesms/util/TextSecurePreferences.java +++ b/src/org/thoughtcrime/securesms/util/TextSecurePreferences.java @@ -127,6 +127,10 @@ public class TextSecurePreferences { private static final String ATTACHMENT_UNENCRYPTED_SECRET = "pref_attachment_unencrypted_secret"; private static final String NEEDS_SQLCIPHER_MIGRATION = "pref_needs_sql_cipher_migration"; + public static final String CALL_NOTIFICATIONS_PREF = "pref_call_notifications"; + public static final String CALL_RINGTONE_PREF = "pref_call_ringtone"; + public static final String CALL_VIBRATE_PREF = "pref_call_vibrate"; + public static void setNeedsSqlCipherMigration(@NonNull Context context, boolean value) { setBooleanPreference(context, NEEDS_SQLCIPHER_MIGRATION, value); EventBus.getDefault().post(new SqlCipherMigrationRequirementProvider.SqlCipherNeedsMigrationEvent()); @@ -684,6 +688,10 @@ public class TextSecurePreferences { return getBooleanPreference(context, NOTIFICATION_PREF, true); } + public static boolean isCallNotificationsEnabled(Context context) { + return getBooleanPreference(context, CALL_NOTIFICATIONS_PREF, true); + } + public static @NonNull Uri getNotificationRingtone(Context context) { String result = getStringPreference(context, RINGTONE_PREF, Settings.System.DEFAULT_NOTIFICATION_URI.toString()); @@ -694,18 +702,46 @@ public class TextSecurePreferences { return Uri.parse(result); } + public static @NonNull Uri getCallNotificationRingtone(Context context) { + String result = getStringPreference(context, CALL_RINGTONE_PREF, Settings.System.DEFAULT_RINGTONE_URI.toString()); + + if (result != null && result.startsWith("file:")) { + result = Settings.System.DEFAULT_RINGTONE_URI.toString(); + } + + return Uri.parse(result); + } + public static void removeNotificationRingtone(Context context) { removePreference(context, RINGTONE_PREF); } + public static void removeCallNotificationRingtone(Context context) { + removePreference(context, CALL_RINGTONE_PREF); + } + public static void setNotificationRingtone(Context context, String ringtone) { setStringPreference(context, RINGTONE_PREF, ringtone); } + public static void setCallNotificationRingtone(Context context, String ringtone) { + setStringPreference(context, CALL_RINGTONE_PREF, ringtone); + } + public static boolean isNotificationVibrateEnabled(Context context) { return getBooleanPreference(context, VIBRATE_PREF, true); } + public static boolean isCallNotificationVibrateEnabled(Context context) { + boolean defaultValue = true; + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + defaultValue = (Settings.System.getInt(context.getContentResolver(), Settings.System.VIBRATE_WHEN_RINGING, 1) == 1); + } + + return getBooleanPreference(context, CALL_VIBRATE_PREF, defaultValue); + } + public static String getNotificationLedColor(Context context) { return getStringPreference(context, LED_COLOR_PREF, "blue"); } diff --git a/src/org/thoughtcrime/securesms/webrtc/audio/IncomingRinger.java b/src/org/thoughtcrime/securesms/webrtc/audio/IncomingRinger.java index d8afa93c05..15f5cbb798 100644 --- a/src/org/thoughtcrime/securesms/webrtc/audio/IncomingRinger.java +++ b/src/org/thoughtcrime/securesms/webrtc/audio/IncomingRinger.java @@ -5,11 +5,11 @@ import android.annotation.TargetApi; import android.content.Context; import android.media.AudioManager; import android.media.MediaPlayer; -import android.media.RingtoneManager; import android.net.Uri; import android.os.Build; import android.os.Vibrator; -import android.provider.Settings; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; import android.util.Log; import org.thoughtcrime.securesms.util.ServiceUtil; @@ -27,20 +27,20 @@ public class IncomingRinger { private MediaPlayer player; - public IncomingRinger(Context context) { + IncomingRinger(Context context) { this.context = context.getApplicationContext(); this.vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE); } - public void start() { + public void start(@Nullable Uri uri, boolean vibrate) { AudioManager audioManager = ServiceUtil.getAudioManager(context); if (player != null) player.release(); - player = createPlayer(); + if (uri != null) player = createPlayer(uri); int ringerMode = audioManager.getRingerMode(); - if (shouldVibrate(context, player, ringerMode)) { + if (shouldVibrate(context, player, ringerMode, vibrate)) { Log.i(TAG, "Starting vibration"); vibrator.vibrate(VIBRATE_PATTERN, 1); } @@ -74,44 +74,41 @@ public class IncomingRinger { vibrator.cancel(); } - private boolean shouldVibrate(Context context, MediaPlayer player, int ringerMode) { + private boolean shouldVibrate(Context context, MediaPlayer player, int ringerMode, boolean vibrate) { if (player == null) { return true; } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { - return shouldVibrateNew(context, ringerMode); + return shouldVibrateNew(context, ringerMode, vibrate); } else { - return shouldVibrateOld(context); + return shouldVibrateOld(context, vibrate); } } @TargetApi(Build.VERSION_CODES.HONEYCOMB) - private boolean shouldVibrateNew(Context context, int ringerMode) { + private boolean shouldVibrateNew(Context context, int ringerMode, boolean vibrate) { Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE); if (vibrator == null || !vibrator.hasVibrator()) { return false; } - boolean vibrateWhenRinging = Settings.System.getInt(context.getContentResolver(), "vibrate_when_ringing", 0) != 0; - - if (vibrateWhenRinging) { + if (vibrate) { return ringerMode != AudioManager.RINGER_MODE_SILENT; } else { return ringerMode == AudioManager.RINGER_MODE_VIBRATE; } } - private boolean shouldVibrateOld(Context context) { + private boolean shouldVibrateOld(Context context, boolean vibrate) { AudioManager audioManager = ServiceUtil.getAudioManager(context); - return audioManager.shouldVibrate(AudioManager.VIBRATE_TYPE_RINGER); + return vibrate && audioManager.shouldVibrate(AudioManager.VIBRATE_TYPE_RINGER); } - private MediaPlayer createPlayer() { + private MediaPlayer createPlayer(@NonNull Uri ringtoneUri) { try { MediaPlayer mediaPlayer = new MediaPlayer(); - Uri ringtoneUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE); mediaPlayer.setOnErrorListener(new MediaPlayerErrorListener()); mediaPlayer.setDataSource(context, ringtoneUri); diff --git a/src/org/thoughtcrime/securesms/webrtc/audio/SignalAudioManager.java b/src/org/thoughtcrime/securesms/webrtc/audio/SignalAudioManager.java index bf5dfe6721..43894d6619 100644 --- a/src/org/thoughtcrime/securesms/webrtc/audio/SignalAudioManager.java +++ b/src/org/thoughtcrime/securesms/webrtc/audio/SignalAudioManager.java @@ -4,8 +4,10 @@ package org.thoughtcrime.securesms.webrtc.audio; import android.content.Context; import android.media.AudioManager; import android.media.SoundPool; +import android.net.Uri; import android.os.Build; import android.support.annotation.NonNull; +import android.support.annotation.Nullable; import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.util.ServiceUtil; @@ -43,7 +45,7 @@ public class SignalAudioManager { } } - public void startIncomingRinger() { + public void startIncomingRinger(@Nullable Uri ringtoneUri, boolean vibrate) { AudioManager audioManager = ServiceUtil.getAudioManager(context); boolean speaker = !audioManager.isWiredHeadsetOn() && !audioManager.isBluetoothScoOn(); @@ -51,7 +53,7 @@ public class SignalAudioManager { audioManager.setMicrophoneMute(false); audioManager.setSpeakerphoneOn(speaker); - incomingRinger.start(); + incomingRinger.start(ringtoneUri, vibrate); } public void startOutgoingRinger(OutgoingRinger.Type type) {