Add default option to message vibrate for pre API26.

This commit is contained in:
Alan Evans 2020-06-19 13:08:54 -03:00 committed by GitHub
parent 71f54701d2
commit 841ee18435
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 138 additions and 89 deletions

View File

@ -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 {

View File

@ -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());

View File

@ -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<RecipientDatabase.VibrateState> 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);

View File

@ -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);
}

View File

@ -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<Boolean> hasCustomNotifications;
private final LiveData<RecipientDatabase.VibrateState> isVibrateEnabled;
private final LiveData<RecipientDatabase.VibrateState> messageVibrateState;
private final LiveData<Uri> notificationSound;
private final CustomNotificationsRepository repository;
private final MutableLiveData<Boolean> isInitialLoadComplete = new MutableLiveData<>();
private final MutableLiveData<Boolean> isInitialLoadComplete = new MutableLiveData<>();
private final LiveData<Boolean> showCallingOptions;
private final LiveData<Uri> ringtone;
private final LiveData<RecipientDatabase.VibrateState> isCallingVibrateEnabled;
private final LiveData<RecipientDatabase.VibrateState> callingVibrateState;
private final LiveData<Boolean> messageVibrateToggle;
private CustomNotificationsViewModel(@NonNull RecipientId recipientId, @NonNull CustomNotificationsRepository repository) {
LiveData<Recipient> 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<Boolean> isInitialLoadComplete() {
LiveData<Boolean> isInitialLoadComplete() {
return isInitialLoadComplete;
}
public LiveData<Boolean> hasCustomNotifications() {
LiveData<Boolean> hasCustomNotifications() {
return hasCustomNotifications;
}
public LiveData<RecipientDatabase.VibrateState> getVibrateState() {
return isVibrateEnabled;
}
public LiveData<Uri> getNotificationSound() {
LiveData<Uri> getNotificationSound() {
return notificationSound;
}
public void setHasCustomNotifications(boolean hasCustomNotifications) {
LiveData<RecipientDatabase.VibrateState> getMessageVibrateState() {
return messageVibrateState;
}
LiveData<Boolean> 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<Boolean> getShowCallingOptions() {
LiveData<Boolean> getShowCallingOptions() {
return showCallingOptions;
}
public LiveData<Uri> getRingtone() {
LiveData<Uri> getRingtone() {
return ringtone;
}
public LiveData<RecipientDatabase.VibrateState> getCallingVibrateState() {
return isCallingVibrateEnabled;
LiveData<RecipientDatabase.VibrateState> getCallingVibrateState() {
return callingVibrateState;
}
public void setCallingVibrate(@NonNull RecipientDatabase.VibrateState vibrateState) {
void setCallingVibrate(@NonNull RecipientDatabase.VibrateState vibrateState) {
repository.setCallingVibrate(vibrateState);
}

View File

@ -107,7 +107,7 @@
</LinearLayout>
<LinearLayout
android:id="@+id/custom_notifications_vibrate_row"
android:id="@+id/custom_notifications_message_vibrate_row"
android:layout_width="match_parent"
android:layout_height="48dp"
android:background="?selectableItemBackground"
@ -121,7 +121,7 @@
app:layout_constraintTop_toBottomOf="@id/custom_notifications_sound_row">
<TextView
android:id="@+id/custom_notifications_vibrate_label"
android:id="@+id/custom_notifications_message_vibrate_label"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_gravity="center"
@ -132,6 +132,17 @@
android:textAlignment="viewStart"
android:textAppearance="@style/TextAppearance.Signal.Body2" />
<TextView
android:id="@+id/custom_notifications_message_vibrate_selector"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:clickable="false"
android:textColor="?attr/colorAccent"
android:visibility="gone"
tools:text="Default"
tools:visibility="visible" />
<androidx.appcompat.widget.SwitchCompat
android:id="@+id/custom_notifications_vibrate_switch"
android:layout_width="wrap_content"
@ -154,7 +165,7 @@
android:visibility="gone"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/custom_notifications_vibrate_row"
app:layout_constraintTop_toBottomOf="@id/custom_notifications_message_vibrate_row"
tools:visibility="visible" />
<LinearLayout
@ -221,7 +232,7 @@
android:textAppearance="@style/TextAppearance.Signal.Body2" />
<TextView
android:id="@+id/custom_notifications_call_vibrate_selection"
android:id="@+id/custom_notifications_call_vibrate_selectior"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"