1package eu.siacs.conversations.ui.fragment.settings;
2
3import android.app.NotificationChannel;
4import android.media.RingtoneManager;
5import android.net.Uri;
6import android.os.Build;
7import android.os.Bundle;
8import android.util.Log;
9
10import androidx.activity.result.ActivityResultLauncher;
11import androidx.annotation.NonNull;
12import androidx.annotation.Nullable;
13import androidx.preference.Preference;
14
15import com.google.common.base.Optional;
16
17import eu.siacs.conversations.AppSettings;
18import eu.siacs.conversations.Config;
19import eu.siacs.conversations.R;
20import eu.siacs.conversations.services.NotificationService;
21import eu.siacs.conversations.ui.activity.result.PickRingtone;
22import eu.siacs.conversations.utils.Compatibility;
23
24public class NotificationsSettingsFragment extends XmppPreferenceFragment {
25
26 private final ActivityResultLauncher<Uri> pickNotificationToneLauncher =
27 registerForActivityResult(
28 new PickRingtone(RingtoneManager.TYPE_NOTIFICATION),
29 result -> {
30 if (result == null) {
31 // do nothing. user aborted
32 return;
33 }
34 final Uri uri = PickRingtone.noneToNull(result);
35 appSettings().setNotificationTone(uri);
36 Log.i(Config.LOGTAG, "User set notification tone to " + uri);
37 });
38 private final ActivityResultLauncher<Uri> pickRingtoneLauncher =
39 registerForActivityResult(
40 new PickRingtone(RingtoneManager.TYPE_RINGTONE),
41 result -> {
42 if (result == null) {
43 // do nothing. user aborted
44 return;
45 }
46 final Uri uri = PickRingtone.noneToNull(result);
47 appSettings().setRingtone(uri);
48 Log.i(Config.LOGTAG, "User set ringtone to " + uri);
49 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
50 NotificationService.recreateIncomingCallChannel(requireContext(), uri);
51 }
52 });
53
54 @Override
55 public void onCreatePreferences(
56 @Nullable final Bundle savedInstanceState, final @Nullable String rootKey) {
57 setPreferencesFromResource(R.xml.preferences_notifications, rootKey);
58 final var messageNotificationSettings = findPreference("message_notification_settings");
59 final var notificationRingtone = findPreference(AppSettings.NOTIFICATION_RINGTONE);
60 final var notificationHeadsUp = findPreference(AppSettings.NOTIFICATION_HEADS_UP);
61 final var notificationVibrate = findPreference(AppSettings.NOTIFICATION_VIBRATE);
62 final var notificationLed = findPreference(AppSettings.NOTIFICATION_LED);
63 final var foregroundService = findPreference(AppSettings.KEEP_FOREGROUND_SERVICE);
64 if (messageNotificationSettings == null
65 || notificationRingtone == null
66 || notificationHeadsUp == null
67 || notificationVibrate == null
68 || notificationLed == null
69 || foregroundService == null) {
70 throw new IllegalStateException("The preference resource file is missing preferences");
71 }
72 if (Compatibility.runsTwentySix()) {
73 notificationRingtone.setVisible(false);
74 notificationHeadsUp.setVisible(false);
75 notificationVibrate.setVisible(false);
76 notificationLed.setVisible(false);
77 foregroundService.setVisible(false);
78 } else {
79 messageNotificationSettings.setVisible(false);
80 }
81 }
82
83 @Override
84 protected void onSharedPreferenceChanged(@NonNull String key) {
85 super.onSharedPreferenceChanged(key);
86 if (key.equals(AppSettings.KEEP_FOREGROUND_SERVICE)) {
87 requireService().toggleForegroundService();
88 }
89 }
90
91 @Override
92 public void onStart() {
93 super.onStart();
94 requireActivity().setTitle(R.string.notifications);
95 }
96
97 @Override
98 public void onBackendConnected() {
99 boolean diallerIntegrationPossible = false;
100
101 if (Build.VERSION.SDK_INT >= 23) {
102 outer:
103 for (final var account : requireService().getAccounts()) {
104 for (final var contact : account.getRoster().getContacts()) {
105 if (contact.getPresences().anyIdentity("gateway", "pstn")) {
106 diallerIntegrationPossible = true;
107 break outer;
108 }
109 }
110 }
111 }
112 if (!diallerIntegrationPossible) {
113 final var pref = findPreference("dialler_integration_incoming");
114 pref.setVisible(false);
115 }
116 }
117
118 @Override
119 public boolean onPreferenceTreeClick(final Preference preference) {
120 final var key = preference.getKey();
121 if (AppSettings.RINGTONE.equals(key)) {
122 pickRingtone();
123 return true;
124 }
125 if (AppSettings.NOTIFICATION_RINGTONE.equals(key)) {
126 pickNotificationTone();
127 return true;
128 }
129 return super.onPreferenceTreeClick(preference);
130 }
131
132 private void pickNotificationTone() {
133 final Uri uri = appSettings().getNotificationTone();
134 Log.i(Config.LOGTAG, "current notification tone: " + uri);
135 this.pickNotificationToneLauncher.launch(uri);
136 }
137
138 private void pickRingtone() {
139 final Optional<Uri> channelRingtone;
140 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
141 channelRingtone =
142 NotificationService.getCurrentIncomingCallChannel(requireContext())
143 .transform(NotificationChannel::getSound);
144 } else {
145 channelRingtone = Optional.absent();
146 }
147 final Uri uri;
148 if (channelRingtone.isPresent()) {
149 uri = channelRingtone.get();
150 Log.d(Config.LOGTAG, "ringtone came from channel");
151 } else {
152 uri = appSettings().getRingtone();
153 }
154 Log.i(Config.LOGTAG, "current ringtone: " + uri);
155 this.pickRingtoneLauncher.launch(uri);
156 }
157
158 private AppSettings appSettings() {
159 return new AppSettings(requireContext());
160 }
161}