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) { public static VibrateState fromId(int id) {
return values()[id]; return values()[id];
} }
public static VibrateState fromBoolean(boolean enabled) {
return enabled ? ENABLED : DISABLED;
}
} }
public enum RegisteredState { public enum RegisteredState {

View File

@ -509,8 +509,8 @@ public class NotificationChannels {
copy.setGroup(original.getGroup()); copy.setGroup(original.getGroup());
copy.setSound(original.getSound(), original.getAudioAttributes()); copy.setSound(original.getSound(), original.getAudioAttributes());
copy.setBypassDnd(original.canBypassDnd()); copy.setBypassDnd(original.canBypassDnd());
copy.enableVibration(original.shouldVibrate());
copy.setVibrationPattern(original.getVibrationPattern()); copy.setVibrationPattern(original.getVibrationPattern());
copy.enableVibration(original.shouldVibrate());
copy.setLockscreenVisibility(original.getLockscreenVisibility()); copy.setLockscreenVisibility(original.getLockscreenVisibility());
copy.setShowBadge(original.canShowBadge()); copy.setShowBadge(original.canShowBadge());
copy.setLightColor(original.getLightColor()); copy.setLightColor(original.getLightColor());

View File

@ -22,6 +22,8 @@ import androidx.appcompat.widget.Toolbar;
import androidx.fragment.app.DialogFragment; import androidx.fragment.app.DialogFragment;
import androidx.lifecycle.ViewModelProviders; import androidx.lifecycle.ViewModelProviders;
import com.annimon.stream.function.Consumer;
import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.database.RecipientDatabase; import org.thoughtcrime.securesms.database.RecipientDatabase;
import org.thoughtcrime.securesms.notifications.NotificationChannels; import org.thoughtcrime.securesms.notifications.NotificationChannels;
@ -43,9 +45,10 @@ public class CustomNotificationsDialogFragment extends DialogFragment {
private View soundRow; private View soundRow;
private View soundLabel; private View soundLabel;
private TextView soundSelector; private TextView soundSelector;
private View vibrateRow; private View messageVibrateRow;
private View vibrateLabel; private View messageVibrateLabel;
private SwitchCompat vibrateSwitch; private TextView messageVibrateSelector;
private SwitchCompat messageVibrateSwitch;
private View callHeading; private View callHeading;
private View ringtoneRow; private View ringtoneRow;
private TextView ringtoneSelector; private TextView ringtoneSelector;
@ -115,14 +118,15 @@ public class CustomNotificationsDialogFragment extends DialogFragment {
soundRow = view.findViewById(R.id.custom_notifications_sound_row); soundRow = view.findViewById(R.id.custom_notifications_sound_row);
soundLabel = view.findViewById(R.id.custom_notifications_sound_label); soundLabel = view.findViewById(R.id.custom_notifications_sound_label);
soundSelector = view.findViewById(R.id.custom_notifications_sound_selection); soundSelector = view.findViewById(R.id.custom_notifications_sound_selection);
vibrateRow = view.findViewById(R.id.custom_notifications_vibrate_row); messageVibrateSwitch = view.findViewById(R.id.custom_notifications_vibrate_switch);
vibrateLabel = view.findViewById(R.id.custom_notifications_vibrate_label); messageVibrateRow = view.findViewById(R.id.custom_notifications_message_vibrate_row);
vibrateSwitch = view.findViewById(R.id.custom_notifications_vibrate_switch); 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); callHeading = view.findViewById(R.id.custom_notifications_call_settings_section_header);
ringtoneRow = view.findViewById(R.id.custom_notifications_ringtone_row); ringtoneRow = view.findViewById(R.id.custom_notifications_ringtone_row);
ringtoneSelector = view.findViewById(R.id.custom_notifications_ringtone_selection); ringtoneSelector = view.findViewById(R.id.custom_notifications_ringtone_selection);
callVibrateRow = view.findViewById(R.id.custom_notifications_call_vibrate_row); 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); Toolbar toolbar = view.findViewById(R.id.custom_notifications_toolbar);
@ -134,6 +138,7 @@ public class CustomNotificationsDialogFragment extends DialogFragment {
viewModel.isInitialLoadComplete().observe(getViewLifecycleOwner(), customNotificationsSwitch::setEnabled); viewModel.isInitialLoadComplete().observe(getViewLifecycleOwner(), customNotificationsSwitch::setEnabled);
if (NotificationChannels.supported()) {
viewModel.hasCustomNotifications().observe(getViewLifecycleOwner(), hasCustomNotifications -> { viewModel.hasCustomNotifications().observe(getViewLifecycleOwner(), hasCustomNotifications -> {
if (customNotificationsSwitch.isChecked() != hasCustomNotifications) { if (customNotificationsSwitch.isChecked() != hasCustomNotifications) {
customNotificationsSwitch.setOnCheckedChangeListener(null); customNotificationsSwitch.setOnCheckedChangeListener(null);
@ -145,35 +150,44 @@ public class CustomNotificationsDialogFragment extends DialogFragment {
soundRow.setEnabled(hasCustomNotifications); soundRow.setEnabled(hasCustomNotifications);
soundLabel.setEnabled(hasCustomNotifications); soundLabel.setEnabled(hasCustomNotifications);
vibrateRow.setEnabled(hasCustomNotifications); messageVibrateRow.setEnabled(hasCustomNotifications);
vibrateLabel.setEnabled(hasCustomNotifications); messageVibrateLabel.setEnabled(hasCustomNotifications);
soundSelector.setVisibility(hasCustomNotifications ? View.VISIBLE : View.GONE); soundSelector.setVisibility(hasCustomNotifications ? View.VISIBLE : View.GONE);
vibrateSwitch.setVisibility(hasCustomNotifications ? View.VISIBLE : View.GONE); messageVibrateSwitch.setVisibility(hasCustomNotifications ? View.VISIBLE : View.GONE);
}); });
if (!NotificationChannels.supported()) { messageVibrateSelector.setVisibility(View.GONE);
customNotificationsSwitch.setVisibility(View.GONE); messageVibrateSwitch.setVisibility(View.VISIBLE);
view.findViewById(R.id.custom_notifications_enable_label).setVisibility(View.GONE);
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);
} }
CompoundButton.OnCheckedChangeListener onVibrateSwitchCheckChangedListener = (buttonView, isChecked) -> { messageVibrateSwitch.setOnCheckedChangeListener(onVibrateSwitchCheckChangedListener);
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()); } 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)));
}
viewModel.getNotificationSound().observe(getViewLifecycleOwner(), sound -> { viewModel.getNotificationSound().observe(getViewLifecycleOwner(), sound -> {
soundSelector.setText(getRingtoneSummary(requireContext(), sound)); soundSelector.setText(getRingtoneSummary(requireContext(), sound, Settings.System.DEFAULT_NOTIFICATION_URI));
soundSelector.setTag(sound); soundSelector.setTag(sound);
soundRow.setOnClickListener(v -> launchSoundSelector(sound, false)); soundRow.setOnClickListener(v -> launchSoundSelector(sound, false));
}); });
@ -185,26 +199,32 @@ public class CustomNotificationsDialogFragment extends DialogFragment {
}); });
viewModel.getRingtone().observe(getViewLifecycleOwner(), sound -> { viewModel.getRingtone().observe(getViewLifecycleOwner(), sound -> {
ringtoneSelector.setText(getRingtoneSummary(requireContext(), sound)); ringtoneSelector.setText(getRingtoneSummary(requireContext(), sound, Settings.System.DEFAULT_RINGTONE_URI));
ringtoneSelector.setTag(sound); ringtoneSelector.setTag(sound);
ringtoneRow.setOnClickListener(v -> launchSoundSelector(sound, true)); ringtoneRow.setOnClickListener(v -> launchSoundSelector(sound, true));
}); });
viewModel.getCallingVibrateState().observe(getViewLifecycleOwner(), vibrateState -> { viewModel.getCallingVibrateState().observe(getViewLifecycleOwner(), vibrateState -> presentVibrateState(vibrateState, this.callVibrateRow, this.callVibrateSelector, (w) -> viewModel.setCallingVibrate(w)));
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());
});
} }
private @NonNull String getRingtoneSummary(@NonNull Context context, @Nullable Uri ringtone) { private void presentVibrateState(@NonNull RecipientDatabase.VibrateState vibrateState,
if (ringtone == null) { @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); return context.getString(R.string.CustomNotificationsDialogFragment__default);
} else if (ringtone.toString().isEmpty()) { } else if (ringtone.toString().isEmpty()) {
return context.getString(R.string.preferences__silent); return context.getString(R.string.preferences__silent);

View File

@ -30,10 +30,9 @@ class CustomNotificationsRepository {
Recipient recipient = getRecipient(); Recipient recipient = getRecipient();
RecipientDatabase recipientDatabase = DatabaseFactory.getRecipientDatabase(context); RecipientDatabase recipientDatabase = DatabaseFactory.getRecipientDatabase(context);
if (NotificationChannels.supported()) { if (NotificationChannels.supported() && recipient.getNotificationChannel() != null) {
recipientDatabase.setMessageRingtone(recipient.getId(), NotificationChannels.getMessageRingtone(context, recipient)); recipientDatabase.setMessageRingtone(recipient.getId(), NotificationChannels.getMessageRingtone(context, recipient));
recipientDatabase.setMessageVibrate(recipient.getId(), NotificationChannels.getMessageVibrate(context, recipient) ? RecipientDatabase.VibrateState.ENABLED recipientDatabase.setMessageVibrate(recipient.getId(), RecipientDatabase.VibrateState.fromBoolean(NotificationChannels.getMessageVibrate(context, recipient)));
: RecipientDatabase.VibrateState.DISABLED);
NotificationChannels.ensureCustomChannelConsistency(context); NotificationChannels.ensureCustomChannelConsistency(context);
} }

View File

@ -11,80 +11,95 @@ import androidx.lifecycle.ViewModel;
import androidx.lifecycle.ViewModelProvider; import androidx.lifecycle.ViewModelProvider;
import org.thoughtcrime.securesms.database.RecipientDatabase; import org.thoughtcrime.securesms.database.RecipientDatabase;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.notifications.NotificationChannels; import org.thoughtcrime.securesms.notifications.NotificationChannels;
import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId; import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
public final class CustomNotificationsViewModel extends ViewModel { public final class CustomNotificationsViewModel extends ViewModel {
private final LiveData<Boolean> hasCustomNotifications; private final LiveData<Boolean> hasCustomNotifications;
private final LiveData<RecipientDatabase.VibrateState> isVibrateEnabled; private final LiveData<RecipientDatabase.VibrateState> messageVibrateState;
private final LiveData<Uri> notificationSound; private final LiveData<Uri> notificationSound;
private final CustomNotificationsRepository repository; 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<Boolean> showCallingOptions;
private final LiveData<Uri> ringtone; 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) { private CustomNotificationsViewModel(@NonNull RecipientId recipientId, @NonNull CustomNotificationsRepository repository) {
LiveData<Recipient> recipient = Recipient.live(recipientId).getLiveData(); LiveData<Recipient> recipient = Recipient.live(recipientId).getLiveData();
this.repository = repository; this.repository = repository;
this.hasCustomNotifications = Transformations.map(recipient, r -> r.getNotificationChannel() != null || !NotificationChannels.supported()); this.hasCustomNotifications = Transformations.map(recipient, r -> r.getNotificationChannel() != null || !NotificationChannels.supported());
this.isVibrateEnabled = Transformations.map(recipient, Recipient::getMessageVibrate); this.callingVibrateState = Transformations.map(recipient, Recipient::getCallVibrate);
this.messageVibrateState = Transformations.map(recipient, Recipient::getMessageVibrate);
this.notificationSound = Transformations.map(recipient, Recipient::getMessageRingtone); this.notificationSound = Transformations.map(recipient, Recipient::getMessageRingtone);
this.showCallingOptions = Transformations.map(recipient, r -> !r.isGroup() && r.isRegistered()); this.showCallingOptions = Transformations.map(recipient, r -> !r.isGroup() && r.isRegistered());
this.ringtone = Transformations.map(recipient, Recipient::getCallRingtone); this.ringtone = Transformations.map(recipient, Recipient::getCallRingtone);
this.isCallingVibrateEnabled = Transformations.map(recipient, Recipient::getCallVibrate); 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)); repository.onLoad(() -> isInitialLoadComplete.postValue(true));
} }
public LiveData<Boolean> isInitialLoadComplete() { LiveData<Boolean> isInitialLoadComplete() {
return isInitialLoadComplete; return isInitialLoadComplete;
} }
public LiveData<Boolean> hasCustomNotifications() { LiveData<Boolean> hasCustomNotifications() {
return hasCustomNotifications; return hasCustomNotifications;
} }
public LiveData<RecipientDatabase.VibrateState> getVibrateState() { LiveData<Uri> getNotificationSound() {
return isVibrateEnabled;
}
public LiveData<Uri> getNotificationSound() {
return notificationSound; 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); repository.setHasCustomNotifications(hasCustomNotifications);
} }
public void setMessageVibrate(@NonNull RecipientDatabase.VibrateState vibrateState) { void setMessageVibrate(@NonNull RecipientDatabase.VibrateState vibrateState) {
repository.setMessageVibrate(vibrateState); repository.setMessageVibrate(vibrateState);
} }
public void setMessageSound(@Nullable Uri sound) { void setMessageSound(@Nullable Uri sound) {
repository.setMessageSound(sound); repository.setMessageSound(sound);
} }
public void setCallSound(@Nullable Uri sound) { void setCallSound(@Nullable Uri sound) {
repository.setCallSound(sound); repository.setCallSound(sound);
} }
public LiveData<Boolean> getShowCallingOptions() { LiveData<Boolean> getShowCallingOptions() {
return showCallingOptions; return showCallingOptions;
} }
public LiveData<Uri> getRingtone() { LiveData<Uri> getRingtone() {
return ringtone; return ringtone;
} }
public LiveData<RecipientDatabase.VibrateState> getCallingVibrateState() { LiveData<RecipientDatabase.VibrateState> getCallingVibrateState() {
return isCallingVibrateEnabled; return callingVibrateState;
} }
public void setCallingVibrate(@NonNull RecipientDatabase.VibrateState vibrateState) { void setCallingVibrate(@NonNull RecipientDatabase.VibrateState vibrateState) {
repository.setCallingVibrate(vibrateState); repository.setCallingVibrate(vibrateState);
} }

View File

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