diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/RecipientDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/RecipientDatabase.java index 941014edb2..d41c030426 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/RecipientDatabase.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/RecipientDatabase.java @@ -170,6 +170,10 @@ public class RecipientDatabase extends Database { public static VibrateState fromId(int id) { return values()[id]; } + + public static VibrateState fromBoolean(boolean enabled) { + return enabled ? ENABLED : DISABLED; + } } public enum RegisteredState { diff --git a/app/src/main/java/org/thoughtcrime/securesms/notifications/NotificationChannels.java b/app/src/main/java/org/thoughtcrime/securesms/notifications/NotificationChannels.java index bb578db88e..3d749bcec6 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/notifications/NotificationChannels.java +++ b/app/src/main/java/org/thoughtcrime/securesms/notifications/NotificationChannels.java @@ -509,8 +509,8 @@ public class NotificationChannels { copy.setGroup(original.getGroup()); copy.setSound(original.getSound(), original.getAudioAttributes()); copy.setBypassDnd(original.canBypassDnd()); - copy.enableVibration(original.shouldVibrate()); copy.setVibrationPattern(original.getVibrationPattern()); + copy.enableVibration(original.shouldVibrate()); copy.setLockscreenVisibility(original.getLockscreenVisibility()); copy.setShowBadge(original.canShowBadge()); copy.setLightColor(original.getLightColor()); diff --git a/app/src/main/java/org/thoughtcrime/securesms/recipients/ui/notifications/CustomNotificationsDialogFragment.java b/app/src/main/java/org/thoughtcrime/securesms/recipients/ui/notifications/CustomNotificationsDialogFragment.java index 405064d8dd..a587e5ceba 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/recipients/ui/notifications/CustomNotificationsDialogFragment.java +++ b/app/src/main/java/org/thoughtcrime/securesms/recipients/ui/notifications/CustomNotificationsDialogFragment.java @@ -22,6 +22,8 @@ import androidx.appcompat.widget.Toolbar; import androidx.fragment.app.DialogFragment; import androidx.lifecycle.ViewModelProviders; +import com.annimon.stream.function.Consumer; + import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.database.RecipientDatabase; import org.thoughtcrime.securesms.notifications.NotificationChannels; @@ -43,9 +45,10 @@ public class CustomNotificationsDialogFragment extends DialogFragment { private View soundRow; private View soundLabel; private TextView soundSelector; - private View vibrateRow; - private View vibrateLabel; - private SwitchCompat vibrateSwitch; + private View messageVibrateRow; + private View messageVibrateLabel; + private TextView messageVibrateSelector; + private SwitchCompat messageVibrateSwitch; private View callHeading; private View ringtoneRow; private TextView ringtoneSelector; @@ -115,14 +118,15 @@ public class CustomNotificationsDialogFragment extends DialogFragment { soundRow = view.findViewById(R.id.custom_notifications_sound_row); soundLabel = view.findViewById(R.id.custom_notifications_sound_label); soundSelector = view.findViewById(R.id.custom_notifications_sound_selection); - vibrateRow = view.findViewById(R.id.custom_notifications_vibrate_row); - vibrateLabel = view.findViewById(R.id.custom_notifications_vibrate_label); - vibrateSwitch = view.findViewById(R.id.custom_notifications_vibrate_switch); + messageVibrateSwitch = view.findViewById(R.id.custom_notifications_vibrate_switch); + messageVibrateRow = view.findViewById(R.id.custom_notifications_message_vibrate_row); + messageVibrateLabel = view.findViewById(R.id.custom_notifications_message_vibrate_label); + messageVibrateSelector = view.findViewById(R.id.custom_notifications_message_vibrate_selector); callHeading = view.findViewById(R.id.custom_notifications_call_settings_section_header); ringtoneRow = view.findViewById(R.id.custom_notifications_ringtone_row); ringtoneSelector = view.findViewById(R.id.custom_notifications_ringtone_selection); callVibrateRow = view.findViewById(R.id.custom_notifications_call_vibrate_row); - callVibrateSelector = view.findViewById(R.id.custom_notifications_call_vibrate_selection); + callVibrateSelector = view.findViewById(R.id.custom_notifications_call_vibrate_selectior); Toolbar toolbar = view.findViewById(R.id.custom_notifications_toolbar); @@ -134,46 +138,56 @@ public class CustomNotificationsDialogFragment extends DialogFragment { viewModel.isInitialLoadComplete().observe(getViewLifecycleOwner(), customNotificationsSwitch::setEnabled); - viewModel.hasCustomNotifications().observe(getViewLifecycleOwner(), hasCustomNotifications -> { - if (customNotificationsSwitch.isChecked() != hasCustomNotifications) { - customNotificationsSwitch.setOnCheckedChangeListener(null); - customNotificationsSwitch.setChecked(hasCustomNotifications); - } + if (NotificationChannels.supported()) { + viewModel.hasCustomNotifications().observe(getViewLifecycleOwner(), hasCustomNotifications -> { + if (customNotificationsSwitch.isChecked() != hasCustomNotifications) { + customNotificationsSwitch.setOnCheckedChangeListener(null); + customNotificationsSwitch.setChecked(hasCustomNotifications); + } - customNotificationsSwitch.setOnCheckedChangeListener(onCustomNotificationsSwitchCheckChangedListener); - customNotificationsRow.setOnClickListener(v -> customNotificationsSwitch.toggle()); + customNotificationsSwitch.setOnCheckedChangeListener(onCustomNotificationsSwitchCheckChangedListener); + customNotificationsRow.setOnClickListener(v -> customNotificationsSwitch.toggle()); - soundRow.setEnabled(hasCustomNotifications); - soundLabel.setEnabled(hasCustomNotifications); - vibrateRow.setEnabled(hasCustomNotifications); - vibrateLabel.setEnabled(hasCustomNotifications); - soundSelector.setVisibility(hasCustomNotifications ? View.VISIBLE : View.GONE); - vibrateSwitch.setVisibility(hasCustomNotifications ? View.VISIBLE : View.GONE); - }); + soundRow.setEnabled(hasCustomNotifications); + soundLabel.setEnabled(hasCustomNotifications); + messageVibrateRow.setEnabled(hasCustomNotifications); + messageVibrateLabel.setEnabled(hasCustomNotifications); + soundSelector.setVisibility(hasCustomNotifications ? View.VISIBLE : View.GONE); + messageVibrateSwitch.setVisibility(hasCustomNotifications ? View.VISIBLE : View.GONE); + }); - if (!NotificationChannels.supported()) { - customNotificationsSwitch.setVisibility(View.GONE); - view.findViewById(R.id.custom_notifications_enable_label).setVisibility(View.GONE); + messageVibrateSelector.setVisibility(View.GONE); + messageVibrateSwitch.setVisibility(View.VISIBLE); + + messageVibrateRow.setOnClickListener(v -> messageVibrateSwitch.toggle()); + + CompoundButton.OnCheckedChangeListener onVibrateSwitchCheckChangedListener = (buttonView, isChecked) -> viewModel.setMessageVibrate(RecipientDatabase.VibrateState.fromBoolean(isChecked)); + + viewModel.getMessageVibrateToggle().observe(getViewLifecycleOwner(), vibrateEnabled -> { + if (messageVibrateSwitch.isChecked() != vibrateEnabled) { + messageVibrateSwitch.setOnCheckedChangeListener(null); + messageVibrateSwitch.setChecked(vibrateEnabled); + } + + messageVibrateSwitch.setOnCheckedChangeListener(onVibrateSwitchCheckChangedListener); + }); + } else { + customNotificationsRow.setVisibility(View.GONE); + + messageVibrateSwitch.setVisibility(View.GONE); + messageVibrateSelector.setVisibility(View.VISIBLE); + + soundRow.setEnabled(true); + soundLabel.setEnabled(true); + messageVibrateRow.setEnabled(true); + messageVibrateLabel.setEnabled(true); + soundSelector.setVisibility(View.VISIBLE); + + viewModel.getMessageVibrateState().observe(getViewLifecycleOwner(), vibrateState -> presentVibrateState(vibrateState, this.messageVibrateRow, this.messageVibrateSelector, (w) -> viewModel.setMessageVibrate(w))); } - CompoundButton.OnCheckedChangeListener onVibrateSwitchCheckChangedListener = (buttonView, isChecked) -> { - viewModel.setMessageVibrate(isChecked ? RecipientDatabase.VibrateState.ENABLED : RecipientDatabase.VibrateState.DISABLED); - }; - - viewModel.getVibrateState().observe(getViewLifecycleOwner(), vibrateState -> { - boolean vibrateEnabled = vibrateState != RecipientDatabase.VibrateState.DISABLED; - - if (vibrateSwitch.isChecked() != vibrateEnabled) { - vibrateSwitch.setOnCheckedChangeListener(null); - vibrateSwitch.setChecked(vibrateEnabled); - } - - vibrateSwitch.setOnCheckedChangeListener(onVibrateSwitchCheckChangedListener); - }); - vibrateRow.setOnClickListener(v -> vibrateSwitch.toggle()); - viewModel.getNotificationSound().observe(getViewLifecycleOwner(), sound -> { - soundSelector.setText(getRingtoneSummary(requireContext(), sound)); + soundSelector.setText(getRingtoneSummary(requireContext(), sound, Settings.System.DEFAULT_NOTIFICATION_URI)); soundSelector.setTag(sound); soundRow.setOnClickListener(v -> launchSoundSelector(sound, false)); }); @@ -185,26 +199,32 @@ public class CustomNotificationsDialogFragment extends DialogFragment { }); viewModel.getRingtone().observe(getViewLifecycleOwner(), sound -> { - ringtoneSelector.setText(getRingtoneSummary(requireContext(), sound)); + ringtoneSelector.setText(getRingtoneSummary(requireContext(), sound, Settings.System.DEFAULT_RINGTONE_URI)); ringtoneSelector.setTag(sound); ringtoneRow.setOnClickListener(v -> launchSoundSelector(sound, true)); }); - viewModel.getCallingVibrateState().observe(getViewLifecycleOwner(), vibrateState -> { - String vibrateSummary = getVibrateSummary(requireContext(), vibrateState); - callVibrateSelector.setText(vibrateSummary); - callVibrateRow.setOnClickListener(v -> new AlertDialog.Builder(requireContext()) - .setTitle(R.string.CustomNotificationsDialogFragment__vibrate) - .setSingleChoiceItems(R.array.recipient_vibrate_entries, vibrateState.ordinal(), ((dialog, which) -> { - viewModel.setCallingVibrate(RecipientDatabase.VibrateState.fromId(which)); - dialog.dismiss(); - })).setNegativeButton(android.R.string.cancel, null) - .show()); - }); + viewModel.getCallingVibrateState().observe(getViewLifecycleOwner(), vibrateState -> presentVibrateState(vibrateState, this.callVibrateRow, this.callVibrateSelector, (w) -> viewModel.setCallingVibrate(w))); } - private @NonNull String getRingtoneSummary(@NonNull Context context, @Nullable Uri ringtone) { - if (ringtone == null) { + private void presentVibrateState(@NonNull RecipientDatabase.VibrateState vibrateState, + @NonNull View vibrateRow, + @NonNull TextView vibrateSelector, + @NonNull Consumer onSelect) + { + vibrateSelector.setText(getVibrateSummary(requireContext(), vibrateState)); + vibrateRow.setOnClickListener(v -> new AlertDialog.Builder(requireContext()) + .setTitle(R.string.CustomNotificationsDialogFragment__vibrate) + .setSingleChoiceItems(R.array.recipient_vibrate_entries, vibrateState.ordinal(), ((dialog, which) -> { + onSelect.accept(RecipientDatabase.VibrateState.fromId(which)); + dialog.dismiss(); + })) + .setNegativeButton(android.R.string.cancel, null) + .show()); + } + + private @NonNull String getRingtoneSummary(@NonNull Context context, @Nullable Uri ringtone, @Nullable Uri defaultNotificationUri) { + if (ringtone == null || ringtone.equals(defaultNotificationUri)) { return context.getString(R.string.CustomNotificationsDialogFragment__default); } else if (ringtone.toString().isEmpty()) { return context.getString(R.string.preferences__silent); diff --git a/app/src/main/java/org/thoughtcrime/securesms/recipients/ui/notifications/CustomNotificationsRepository.java b/app/src/main/java/org/thoughtcrime/securesms/recipients/ui/notifications/CustomNotificationsRepository.java index 44b6f028e3..d5b3330712 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/recipients/ui/notifications/CustomNotificationsRepository.java +++ b/app/src/main/java/org/thoughtcrime/securesms/recipients/ui/notifications/CustomNotificationsRepository.java @@ -30,10 +30,9 @@ class CustomNotificationsRepository { Recipient recipient = getRecipient(); RecipientDatabase recipientDatabase = DatabaseFactory.getRecipientDatabase(context); - if (NotificationChannels.supported()) { + if (NotificationChannels.supported() && recipient.getNotificationChannel() != null) { recipientDatabase.setMessageRingtone(recipient.getId(), NotificationChannels.getMessageRingtone(context, recipient)); - recipientDatabase.setMessageVibrate(recipient.getId(), NotificationChannels.getMessageVibrate(context, recipient) ? RecipientDatabase.VibrateState.ENABLED - : RecipientDatabase.VibrateState.DISABLED); + recipientDatabase.setMessageVibrate(recipient.getId(), RecipientDatabase.VibrateState.fromBoolean(NotificationChannels.getMessageVibrate(context, recipient))); NotificationChannels.ensureCustomChannelConsistency(context); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/recipients/ui/notifications/CustomNotificationsViewModel.java b/app/src/main/java/org/thoughtcrime/securesms/recipients/ui/notifications/CustomNotificationsViewModel.java index f5b726253f..90c0caa695 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/recipients/ui/notifications/CustomNotificationsViewModel.java +++ b/app/src/main/java/org/thoughtcrime/securesms/recipients/ui/notifications/CustomNotificationsViewModel.java @@ -11,80 +11,95 @@ import androidx.lifecycle.ViewModel; import androidx.lifecycle.ViewModelProvider; import org.thoughtcrime.securesms.database.RecipientDatabase; +import org.thoughtcrime.securesms.dependencies.ApplicationDependencies; import org.thoughtcrime.securesms.notifications.NotificationChannels; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.RecipientId; +import org.thoughtcrime.securesms.util.TextSecurePreferences; public final class CustomNotificationsViewModel extends ViewModel { private final LiveData hasCustomNotifications; - private final LiveData isVibrateEnabled; + private final LiveData messageVibrateState; private final LiveData notificationSound; private final CustomNotificationsRepository repository; - private final MutableLiveData isInitialLoadComplete = new MutableLiveData<>(); + private final MutableLiveData isInitialLoadComplete = new MutableLiveData<>(); private final LiveData showCallingOptions; private final LiveData ringtone; - private final LiveData isCallingVibrateEnabled; + private final LiveData callingVibrateState; + private final LiveData messageVibrateToggle; private CustomNotificationsViewModel(@NonNull RecipientId recipientId, @NonNull CustomNotificationsRepository repository) { LiveData recipient = Recipient.live(recipientId).getLiveData(); - this.repository = repository; - this.hasCustomNotifications = Transformations.map(recipient, r -> r.getNotificationChannel() != null || !NotificationChannels.supported()); - this.isVibrateEnabled = Transformations.map(recipient, Recipient::getMessageVibrate); - this.notificationSound = Transformations.map(recipient, Recipient::getMessageRingtone); - this.showCallingOptions = Transformations.map(recipient, r -> !r.isGroup() && r.isRegistered()); - this.ringtone = Transformations.map(recipient, Recipient::getCallRingtone); - this.isCallingVibrateEnabled = Transformations.map(recipient, Recipient::getCallVibrate); + this.repository = repository; + this.hasCustomNotifications = Transformations.map(recipient, r -> r.getNotificationChannel() != null || !NotificationChannels.supported()); + this.callingVibrateState = Transformations.map(recipient, Recipient::getCallVibrate); + this.messageVibrateState = Transformations.map(recipient, Recipient::getMessageVibrate); + this.notificationSound = Transformations.map(recipient, Recipient::getMessageRingtone); + this.showCallingOptions = Transformations.map(recipient, r -> !r.isGroup() && r.isRegistered()); + this.ringtone = Transformations.map(recipient, Recipient::getCallRingtone); + this.messageVibrateToggle = Transformations.map(messageVibrateState, vibrateState -> { + switch (vibrateState) { + case DISABLED: return false; + case ENABLED : return true; + case DEFAULT : return TextSecurePreferences.isNotificationVibrateEnabled(ApplicationDependencies.getApplication()); + default : throw new AssertionError(); + } + }); repository.onLoad(() -> isInitialLoadComplete.postValue(true)); } - public LiveData isInitialLoadComplete() { + LiveData isInitialLoadComplete() { return isInitialLoadComplete; } - public LiveData hasCustomNotifications() { + LiveData hasCustomNotifications() { return hasCustomNotifications; } - public LiveData getVibrateState() { - return isVibrateEnabled; - } - - public LiveData getNotificationSound() { + LiveData getNotificationSound() { return notificationSound; } - public void setHasCustomNotifications(boolean hasCustomNotifications) { + LiveData getMessageVibrateState() { + return messageVibrateState; + } + + LiveData getMessageVibrateToggle() { + return messageVibrateToggle; + } + + void setHasCustomNotifications(boolean hasCustomNotifications) { repository.setHasCustomNotifications(hasCustomNotifications); } - public void setMessageVibrate(@NonNull RecipientDatabase.VibrateState vibrateState) { + void setMessageVibrate(@NonNull RecipientDatabase.VibrateState vibrateState) { repository.setMessageVibrate(vibrateState); } - public void setMessageSound(@Nullable Uri sound) { + void setMessageSound(@Nullable Uri sound) { repository.setMessageSound(sound); } - public void setCallSound(@Nullable Uri sound) { + void setCallSound(@Nullable Uri sound) { repository.setCallSound(sound); } - public LiveData getShowCallingOptions() { + LiveData getShowCallingOptions() { return showCallingOptions; } - public LiveData getRingtone() { + LiveData getRingtone() { return ringtone; } - public LiveData getCallingVibrateState() { - return isCallingVibrateEnabled; + LiveData getCallingVibrateState() { + return callingVibrateState; } - public void setCallingVibrate(@NonNull RecipientDatabase.VibrateState vibrateState) { + void setCallingVibrate(@NonNull RecipientDatabase.VibrateState vibrateState) { repository.setCallingVibrate(vibrateState); } diff --git a/app/src/main/res/layout/custom_notifications_dialog_fragment.xml b/app/src/main/res/layout/custom_notifications_dialog_fragment.xml index 1324ad388c..7c2ea4b6d6 100644 --- a/app/src/main/res/layout/custom_notifications_dialog_fragment.xml +++ b/app/src/main/res/layout/custom_notifications_dialog_fragment.xml @@ -107,7 +107,7 @@ + +