1package eu.siacs.conversations.ui;
2
3import android.app.FragmentManager;
4import android.content.Context;
5import android.content.DialogInterface;
6import android.content.Intent;
7import android.content.SharedPreferences;
8import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
9import android.content.pm.PackageManager;
10import android.net.Uri;
11import android.os.Build;
12import android.os.Bundle;
13import android.os.storage.StorageManager;
14import android.preference.CheckBoxPreference;
15import android.preference.ListPreference;
16import android.preference.Preference;
17import android.preference.PreferenceCategory;
18import android.preference.PreferenceManager;
19import android.preference.PreferenceScreen;
20import android.provider.MediaStore;
21import android.util.Log;
22import android.widget.Toast;
23
24import androidx.annotation.NonNull;
25import androidx.appcompat.app.AlertDialog;
26import androidx.core.content.ContextCompat;
27
28import com.cheogram.android.DownloadDefaultStickers;
29
30import com.google.common.base.Strings;
31import com.google.common.collect.ImmutableList;
32import com.google.common.collect.Lists;
33
34import java.io.File;
35import java.net.URI;
36import java.net.URISyntaxException;
37import java.security.KeyStoreException;
38import java.util.ArrayList;
39import java.util.Arrays;
40import java.util.Collections;
41import java.util.List;
42
43import eu.siacs.conversations.Config;
44import eu.siacs.conversations.R;
45import eu.siacs.conversations.crypto.OmemoSetting;
46import eu.siacs.conversations.entities.Account;
47import eu.siacs.conversations.entities.Contact;
48import eu.siacs.conversations.persistance.FileBackend;
49import eu.siacs.conversations.services.ExportBackupService;
50import eu.siacs.conversations.services.MemorizingTrustManager;
51import eu.siacs.conversations.services.QuickConversationsService;
52import eu.siacs.conversations.services.UnifiedPushDistributor;
53import eu.siacs.conversations.ui.util.SettingsUtils;
54import eu.siacs.conversations.ui.util.StyledAttributes;
55import eu.siacs.conversations.utils.GeoHelper;
56import eu.siacs.conversations.utils.ThemeHelper;
57import eu.siacs.conversations.utils.TimeFrameUtils;
58import eu.siacs.conversations.xmpp.InvalidJid;
59import eu.siacs.conversations.xmpp.Jid;
60
61public class SettingsActivity extends XmppActivity implements OnSharedPreferenceChangeListener {
62
63 public static final String KEEP_FOREGROUND_SERVICE = "enable_foreground_service";
64 public static final String AWAY_WHEN_SCREEN_IS_OFF = "away_when_screen_off";
65 public static final String TREAT_VIBRATE_AS_SILENT = "treat_vibrate_as_silent";
66 public static final String DND_ON_SILENT_MODE = "dnd_on_silent_mode";
67 public static final String MANUALLY_CHANGE_PRESENCE = "manually_change_presence";
68 public static final String BLIND_TRUST_BEFORE_VERIFICATION = "btbv";
69 public static final String AUTOMATIC_MESSAGE_DELETION = "automatic_message_deletion";
70 public static final String BROADCAST_LAST_ACTIVITY = "last_activity";
71 public static final String THEME = "theme";
72 public static final String SHOW_DYNAMIC_TAGS = "show_dynamic_tags";
73 public static final String OMEMO_SETTING = "omemo";
74 public static final String PREVENT_SCREENSHOTS = "prevent_screenshots";
75
76 public static final int REQUEST_CREATE_BACKUP = 0xbf8701;
77 public static final int REQUEST_DOWNLOAD_STICKERS = 0xbf8702;
78
79 private SettingsFragment mSettingsFragment;
80
81 @Override
82 protected void onCreate(Bundle savedInstanceState) {
83 super.onCreate(savedInstanceState);
84 setContentView(R.layout.activity_settings);
85 FragmentManager fm = getFragmentManager();
86 mSettingsFragment = (SettingsFragment) fm.findFragmentById(R.id.settings_content);
87 if (mSettingsFragment == null
88 || !mSettingsFragment.getClass().equals(SettingsFragment.class)) {
89 mSettingsFragment = new SettingsFragment();
90 fm.beginTransaction().replace(R.id.settings_content, mSettingsFragment).commit();
91 }
92 mSettingsFragment.setActivityIntent(getIntent());
93 this.mTheme = findTheme();
94 setTheme(this.mTheme);
95 ThemeHelper.applyCustomColors(this);
96 getWindow()
97 .getDecorView()
98 .setBackgroundColor(
99 StyledAttributes.getColor(this, R.attr.color_background_primary));
100 setSupportActionBar(findViewById(R.id.toolbar));
101 configureActionBar(getSupportActionBar());
102 }
103
104 @Override
105 protected void onActivityResult(int requestCode, int resultCode, Intent data) {
106 if (data == null || data.getData() == null) return;
107
108 SharedPreferences p = PreferenceManager.getDefaultSharedPreferences(this);
109 p.edit().putString("sticker_directory", data.getData().toString()).commit();
110 }
111
112 @Override
113 void onBackendConnected() {
114 boolean diallerIntegrationPossible = false;
115
116 if (Build.VERSION.SDK_INT >= 23) {
117 outer:
118 for (Account account : xmppConnectionService.getAccounts()) {
119 for (Contact contact : account.getRoster().getContacts()) {
120 if (contact.getPresences().anyIdentity("gateway", "pstn")) {
121 diallerIntegrationPossible = true;
122 break outer;
123 }
124 }
125 }
126 }
127 if (!diallerIntegrationPossible) {
128 PreferenceCategory cat = (PreferenceCategory) mSettingsFragment.findPreference("notification_category");
129 Preference pref = mSettingsFragment.findPreference("dialler_integration_incoming");
130 if (cat != null && pref != null) cat.removePreference(pref);
131 }
132 if (xmppConnectionService.getAccounts().size() > 1) {
133 PreferenceCategory cat = (PreferenceCategory) mSettingsFragment.findPreference("notification_category");
134 Preference pref = mSettingsFragment.findPreference("quiet_hours");
135 if (cat != null && pref != null) cat.removePreference(pref);
136 }
137 final Preference accountPreference =
138 mSettingsFragment.findPreference(UnifiedPushDistributor.PREFERENCE_ACCOUNT);
139 reconfigureUpAccountPreference(accountPreference);
140 }
141
142 private void reconfigureUpAccountPreference(final Preference preference) {
143 final ListPreference listPreference;
144 if (preference instanceof ListPreference) {
145 listPreference = (ListPreference) preference;
146 } else {
147 return;
148 }
149 final List<CharSequence> accounts =
150 ImmutableList.copyOf(
151 Lists.transform(
152 xmppConnectionService.getAccounts(),
153 a -> a.getJid().asBareJid().toEscapedString()));
154 final ImmutableList.Builder<CharSequence> entries = new ImmutableList.Builder<>();
155 final ImmutableList.Builder<CharSequence> entryValues = new ImmutableList.Builder<>();
156 entries.add(getString(R.string.no_account_deactivated));
157 entryValues.add("none");
158 entries.addAll(accounts);
159 entryValues.addAll(accounts);
160 listPreference.setEntries(entries.build().toArray(new CharSequence[0]));
161 listPreference.setEntryValues(entryValues.build().toArray(new CharSequence[0]));
162 if (!accounts.contains(listPreference.getValue())) {
163 listPreference.setValue("none");
164 }
165 }
166
167 @Override
168 public void onStart() {
169 super.onStart();
170 PreferenceManager.getDefaultSharedPreferences(this)
171 .registerOnSharedPreferenceChangeListener(this);
172
173 changeOmemoSettingSummary();
174
175 if (QuickConversationsService.isQuicksy()
176 || QuickConversationsService.isPlayStoreFlavor()
177 || Strings.isNullOrEmpty(Config.CHANNEL_DISCOVERY)) {
178 final PreferenceCategory groupChats =
179 (PreferenceCategory) mSettingsFragment.findPreference("group_chats");
180 final Preference channelDiscoveryMethod =
181 mSettingsFragment.findPreference("channel_discovery_method");
182 if (groupChats != null && channelDiscoveryMethod != null) {
183 groupChats.removePreference(channelDiscoveryMethod);
184 }
185 }
186
187 if (QuickConversationsService.isQuicksy()) {
188 final PreferenceCategory connectionOptions =
189 (PreferenceCategory) mSettingsFragment.findPreference("connection_options");
190 PreferenceScreen expert = (PreferenceScreen) mSettingsFragment.findPreference("expert");
191 if (connectionOptions != null) {
192 expert.removePreference(connectionOptions);
193 }
194 }
195
196 PreferenceScreen mainPreferenceScreen =
197 (PreferenceScreen) mSettingsFragment.findPreference("main_screen");
198
199 PreferenceCategory attachmentsCategory =
200 (PreferenceCategory) mSettingsFragment.findPreference("attachments");
201 CheckBoxPreference locationPlugin =
202 (CheckBoxPreference) mSettingsFragment.findPreference("use_share_location_plugin");
203 if (attachmentsCategory != null && locationPlugin != null) {
204 if (!GeoHelper.isLocationPluginInstalled(this)) {
205 attachmentsCategory.removePreference(locationPlugin);
206 }
207 }
208
209 // this feature is only available on Huawei Android 6.
210 PreferenceScreen huaweiPreferenceScreen =
211 (PreferenceScreen) mSettingsFragment.findPreference("huawei");
212 if (huaweiPreferenceScreen != null) {
213 Intent intent = huaweiPreferenceScreen.getIntent();
214 // remove when Api version is above M (Version 6.0) or if the intent is not callable
215 if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M || !isCallable(intent)) {
216 PreferenceCategory generalCategory =
217 (PreferenceCategory) mSettingsFragment.findPreference("general");
218 generalCategory.removePreference(huaweiPreferenceScreen);
219 if (generalCategory.getPreferenceCount() == 0) {
220 if (mainPreferenceScreen != null) {
221 mainPreferenceScreen.removePreference(generalCategory);
222 }
223 }
224 }
225 }
226
227 ListPreference automaticMessageDeletionList =
228 (ListPreference) mSettingsFragment.findPreference(AUTOMATIC_MESSAGE_DELETION);
229 if (automaticMessageDeletionList != null) {
230 final int[] choices =
231 getResources().getIntArray(R.array.automatic_message_deletion_values);
232 CharSequence[] entries = new CharSequence[choices.length];
233 CharSequence[] entryValues = new CharSequence[choices.length];
234 for (int i = 0; i < choices.length; ++i) {
235 entryValues[i] = String.valueOf(choices[i]);
236 if (choices[i] == 0) {
237 entries[i] = getString(R.string.never);
238 } else {
239 entries[i] = TimeFrameUtils.resolve(this, 1000L * choices[i]);
240 }
241 }
242 automaticMessageDeletionList.setEntries(entries);
243 automaticMessageDeletionList.setEntryValues(entryValues);
244 }
245
246 boolean removeLocation =
247 new Intent("eu.siacs.conversations.location.request")
248 .resolveActivity(getPackageManager())
249 == null;
250 boolean removeVoice =
251 new Intent(MediaStore.Audio.Media.RECORD_SOUND_ACTION)
252 .resolveActivity(getPackageManager())
253 == null;
254
255 ListPreference quickAction =
256 (ListPreference) mSettingsFragment.findPreference("quick_action");
257 if (quickAction != null && (removeLocation || removeVoice)) {
258 ArrayList<CharSequence> entries =
259 new ArrayList<>(Arrays.asList(quickAction.getEntries()));
260 ArrayList<CharSequence> entryValues =
261 new ArrayList<>(Arrays.asList(quickAction.getEntryValues()));
262 int index = entryValues.indexOf("location");
263 if (index > 0 && removeLocation) {
264 entries.remove(index);
265 entryValues.remove(index);
266 }
267 index = entryValues.indexOf("voice");
268 if (index > 0 && removeVoice) {
269 entries.remove(index);
270 entryValues.remove(index);
271 }
272 quickAction.setEntries(entries.toArray(new CharSequence[entries.size()]));
273 quickAction.setEntryValues(entryValues.toArray(new CharSequence[entryValues.size()]));
274 }
275
276 final Preference removeCertsPreference =
277 mSettingsFragment.findPreference("remove_trusted_certificates");
278 if (removeCertsPreference != null) {
279 removeCertsPreference.setOnPreferenceClickListener(
280 preference -> {
281 final MemorizingTrustManager mtm =
282 xmppConnectionService.getMemorizingTrustManager();
283 final ArrayList<String> aliases = Collections.list(mtm.getCertificates());
284 if (aliases.size() == 0) {
285 displayToast(getString(R.string.toast_no_trusted_certs));
286 return true;
287 }
288 final ArrayList<Integer> selectedItems = new ArrayList<>();
289 final AlertDialog.Builder dialogBuilder =
290 new AlertDialog.Builder(SettingsActivity.this);
291 dialogBuilder.setTitle(
292 getResources().getString(R.string.dialog_manage_certs_title));
293 dialogBuilder.setMultiChoiceItems(
294 aliases.toArray(new CharSequence[aliases.size()]),
295 null,
296 (dialog, indexSelected, isChecked) -> {
297 if (isChecked) {
298 selectedItems.add(indexSelected);
299 } else if (selectedItems.contains(indexSelected)) {
300 selectedItems.remove(Integer.valueOf(indexSelected));
301 }
302 ((AlertDialog) dialog)
303 .getButton(DialogInterface.BUTTON_POSITIVE)
304 .setEnabled(selectedItems.size() > 0);
305 });
306
307 dialogBuilder.setPositiveButton(
308 getResources()
309 .getString(R.string.dialog_manage_certs_positivebutton),
310 (dialog, which) -> {
311 int count = selectedItems.size();
312 if (count > 0) {
313 for (int i = 0; i < count; i++) {
314 try {
315 Integer item =
316 Integer.valueOf(
317 selectedItems.get(i).toString());
318 String alias = aliases.get(item);
319 mtm.deleteCertificate(alias);
320 } catch (KeyStoreException e) {
321 e.printStackTrace();
322 displayToast("Error: " + e.getLocalizedMessage());
323 }
324 }
325 if (xmppConnectionServiceBound) {
326 reconnectAccounts();
327 }
328 displayToast(
329 getResources()
330 .getQuantityString(
331 R.plurals.toast_delete_certificates,
332 count,
333 count));
334 }
335 });
336 dialogBuilder.setNegativeButton(
337 getResources()
338 .getString(R.string.dialog_manage_certs_negativebutton),
339 null);
340 AlertDialog removeCertsDialog = dialogBuilder.create();
341 removeCertsDialog.show();
342 removeCertsDialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(false);
343 return true;
344 });
345 }
346
347 final Preference createBackupPreference = mSettingsFragment.findPreference("create_backup");
348 if (createBackupPreference != null) {
349 createBackupPreference.setSummary(
350 getString(
351 R.string.pref_create_backup_summary,
352 FileBackend.getBackupDirectory(this).getAbsolutePath()));
353 createBackupPreference.setOnPreferenceClickListener(
354 preference -> {
355 if (hasStoragePermission(REQUEST_CREATE_BACKUP)) {
356 createBackup();
357 }
358 return true;
359 });
360 }
361
362 if (Config.ONLY_INTERNAL_STORAGE) {
363 final Preference cleanCachePreference = mSettingsFragment.findPreference("clean_cache");
364 if (cleanCachePreference != null) {
365 cleanCachePreference.setOnPreferenceClickListener(preference -> cleanCache());
366 }
367
368 final Preference cleanPrivateStoragePreference =
369 mSettingsFragment.findPreference("clean_private_storage");
370 if (cleanPrivateStoragePreference != null) {
371 cleanPrivateStoragePreference.setOnPreferenceClickListener(
372 preference -> cleanPrivateStorage());
373 }
374 }
375
376 final Preference deleteOmemoPreference =
377 mSettingsFragment.findPreference("delete_omemo_identities");
378 if (deleteOmemoPreference != null) {
379 deleteOmemoPreference.setOnPreferenceClickListener(
380 preference -> deleteOmemoIdentities());
381 }
382 if (Config.omemoOnly()) {
383 final PreferenceCategory privacyCategory =
384 (PreferenceCategory) mSettingsFragment.findPreference("privacy");
385 final Preference omemoPreference =mSettingsFragment.findPreference(OMEMO_SETTING);
386 if (omemoPreference != null) {
387 privacyCategory.removePreference(omemoPreference);
388 }
389 }
390
391 final Preference stickerDir = mSettingsFragment.findPreference("sticker_directory");
392 if (stickerDir != null) {
393 if (Build.VERSION.SDK_INT >= 24) {
394 stickerDir.setOnPreferenceClickListener((p) -> {
395 Intent intent = ((StorageManager) getSystemService(Context.STORAGE_SERVICE)).getPrimaryStorageVolume().createOpenDocumentTreeIntent();
396 startActivityForResult(Intent.createChooser(intent, "Choose sticker location"), 0);
397 return true;
398 });
399 } else {
400 PreferenceCategory expertMedia = (PreferenceCategory) mSettingsFragment.findPreference("expert_media");
401 expertMedia.removePreference(stickerDir);
402 }
403 }
404
405 final Preference downloadDefaultStickers = mSettingsFragment.findPreference("download_default_stickers");
406 if (downloadDefaultStickers != null) {
407 downloadDefaultStickers.setOnPreferenceClickListener(
408 preference -> {
409 if (hasStoragePermission(REQUEST_DOWNLOAD_STICKERS)) {
410 downloadStickers();
411 }
412 return true;
413 });
414 }
415
416 final Preference clearBlockedMedia = mSettingsFragment.findPreference("clear_blocked_media");
417 if (clearBlockedMedia != null) {
418 clearBlockedMedia.setOnPreferenceClickListener((p) -> {
419 xmppConnectionService.clearBlockedMedia();
420 displayToast("Blocked media will be displayed again.");
421 return true;
422 });
423 }
424
425 final String theTheme = PreferenceManager.getDefaultSharedPreferences(this).getString(THEME, "");
426 if (Build.VERSION.SDK_INT < 30 || !theTheme.equals("custom")) {
427 final PreferenceCategory uiCategory = (PreferenceCategory) mSettingsFragment.findPreference("ui");
428 final Preference customTheme = mSettingsFragment.findPreference("custom_theme");
429 if (customTheme != null) uiCategory.removePreference(customTheme);
430 }
431
432 if (Build.VERSION.SDK_INT > 30 && theTheme.equals("custom")) {
433 final boolean customAutomatic = PreferenceManager.getDefaultSharedPreferences(this).getBoolean("custom_theme_automatic", false);
434 final PreferenceScreen customTheme = (PreferenceScreen) mSettingsFragment.findPreference("custom_theme");
435 final Preference customThemeIsDark = mSettingsFragment.findPreference("custom_theme_dark");
436
437 if (customAutomatic) {
438 if (customTheme != null && customThemeIsDark != null) customTheme.removePreference(customThemeIsDark);
439 } else {
440 final boolean isDark = PreferenceManager.getDefaultSharedPreferences(this).getBoolean("custom_theme_dark", false);
441 if (isDark) {
442 final PreferenceCategory customThemeColors = (PreferenceCategory) mSettingsFragment.findPreference("custom_theme_colors");
443 if (customTheme != null && customThemeColors != null) customTheme.removePreference(customThemeColors);
444 } else {
445 final PreferenceCategory customThemeColorsDark = (PreferenceCategory) mSettingsFragment.findPreference("custom_theme_colors_dark");
446 if (customTheme != null && customThemeColorsDark != null) customTheme.removePreference(customThemeColorsDark);
447 }
448 }
449 }
450 }
451
452 private void changeOmemoSettingSummary() {
453 final ListPreference omemoPreference =
454 (ListPreference) mSettingsFragment.findPreference(OMEMO_SETTING);
455 if (omemoPreference == null) {
456 return;
457 }
458 final String value = omemoPreference.getValue();
459 switch (value) {
460 case "always":
461 omemoPreference.setSummary(R.string.pref_omemo_setting_summary_always);
462 break;
463 case "default_on":
464 omemoPreference.setSummary(R.string.pref_omemo_setting_summary_default_on);
465 break;
466 case "default_off":
467 omemoPreference.setSummary(R.string.pref_omemo_setting_summary_default_off);
468 break;
469 }
470 }
471
472 private boolean isCallable(final Intent i) {
473 return i != null
474 && getPackageManager()
475 .queryIntentActivities(i, PackageManager.MATCH_DEFAULT_ONLY)
476 .size()
477 > 0;
478 }
479
480 private boolean cleanCache() {
481 Intent intent = new Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
482 intent.setData(Uri.parse("package:" + getPackageName()));
483 startActivity(intent);
484 return true;
485 }
486
487 private boolean cleanPrivateStorage() {
488 for (String type : Arrays.asList("Images", "Videos", "Files", "Recordings")) {
489 cleanPrivateFiles(type);
490 }
491 return true;
492 }
493
494 private void cleanPrivateFiles(final String type) {
495 try {
496 File dir = new File(getFilesDir().getAbsolutePath(), "/" + type + "/");
497 File[] array = dir.listFiles();
498 if (array != null) {
499 for (int b = 0; b < array.length; b++) {
500 String name = array[b].getName().toLowerCase();
501 if (name.equals(".nomedia")) {
502 continue;
503 }
504 if (array[b].isFile()) {
505 array[b].delete();
506 }
507 }
508 }
509 } catch (Throwable e) {
510 Log.e("CleanCache", e.toString());
511 }
512 }
513
514 private boolean deleteOmemoIdentities() {
515 AlertDialog.Builder builder = new AlertDialog.Builder(this);
516 builder.setTitle(R.string.pref_delete_omemo_identities);
517 final List<CharSequence> accounts = new ArrayList<>();
518 for (Account account : xmppConnectionService.getAccounts()) {
519 if (account.isEnabled()) {
520 accounts.add(account.getJid().asBareJid().toString());
521 }
522 }
523 final boolean[] checkedItems = new boolean[accounts.size()];
524 builder.setMultiChoiceItems(
525 accounts.toArray(new CharSequence[accounts.size()]),
526 checkedItems,
527 (dialog, which, isChecked) -> {
528 checkedItems[which] = isChecked;
529 final AlertDialog alertDialog = (AlertDialog) dialog;
530 for (boolean item : checkedItems) {
531 if (item) {
532 alertDialog.getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(true);
533 return;
534 }
535 }
536 alertDialog.getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(false);
537 });
538 builder.setNegativeButton(R.string.cancel, null);
539 builder.setPositiveButton(
540 R.string.delete_selected_keys,
541 (dialog, which) -> {
542 for (int i = 0; i < checkedItems.length; ++i) {
543 if (checkedItems[i]) {
544 try {
545 Jid jid = Jid.of(accounts.get(i).toString());
546 Account account = xmppConnectionService.findAccountByJid(jid);
547 if (account != null) {
548 account.getAxolotlService().regenerateKeys(true);
549 }
550 } catch (IllegalArgumentException e) {
551 //
552 }
553 }
554 }
555 });
556 AlertDialog dialog = builder.create();
557 dialog.show();
558 dialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(false);
559 return true;
560 }
561
562 @Override
563 public void onStop() {
564 super.onStop();
565 PreferenceManager.getDefaultSharedPreferences(this)
566 .unregisterOnSharedPreferenceChangeListener(this);
567 }
568
569 @Override
570 public void onSharedPreferenceChanged(SharedPreferences preferences, String name) {
571 final List<String> resendPresence =
572 Arrays.asList(
573 "confirm_messages",
574 DND_ON_SILENT_MODE,
575 AWAY_WHEN_SCREEN_IS_OFF,
576 "allow_message_correction",
577 TREAT_VIBRATE_AS_SILENT,
578 MANUALLY_CHANGE_PRESENCE,
579 BROADCAST_LAST_ACTIVITY);
580 if (name.equals(OMEMO_SETTING)) {
581 OmemoSetting.load(this, preferences);
582 changeOmemoSettingSummary();
583 } else if (name.equals(KEEP_FOREGROUND_SERVICE)) {
584 xmppConnectionService.toggleForegroundService();
585 } else if (resendPresence.contains(name)) {
586 if (xmppConnectionServiceBound) {
587 if (name.equals(AWAY_WHEN_SCREEN_IS_OFF) || name.equals(MANUALLY_CHANGE_PRESENCE)) {
588 xmppConnectionService.toggleScreenEventReceiver();
589 }
590 xmppConnectionService.refreshAllPresences();
591 }
592 } else if (name.equals("dont_trust_system_cas")) {
593 xmppConnectionService.updateMemorizingTrustmanager();
594 reconnectAccounts();
595 } else if (name.equals("use_tor")) {
596 if (preferences.getBoolean(name, false)) {
597 displayToast(getString(R.string.audio_video_disabled_tor));
598 }
599 reconnectAccounts();
600 xmppConnectionService.reinitializeMuclumbusService();
601 } else if (name.equals(AUTOMATIC_MESSAGE_DELETION)) {
602 xmppConnectionService.expireOldMessages(true);
603 } else if ( name.equals(THEME) ||
604 name.equals("custom_theme_automatic") ||
605 name.equals("custom_theme_dark") ||
606 name.equals("custom_theme_primary") ||
607 name.equals("custom_theme_primary_dark") ||
608 name.equals("custom_theme_accent") ||
609 name.equals("custom_theme_background_primary") ||
610 name.equals("custom_dark_theme_primary") ||
611 name.equals("custom_dark_theme_primary_dark") ||
612 name.equals("custom_dark_theme_accent") ||
613 name.equals("custom_dark_theme_background_primary"))
614 {
615 final int theme = findTheme();
616 xmppConnectionService.setTheme(theme);
617 ThemeHelper.applyCustomColors(xmppConnectionService);
618 recreate();
619 } else if (name.equals(PREVENT_SCREENSHOTS)) {
620 SettingsUtils.applyScreenshotPreventionSetting(this);
621 } else if (UnifiedPushDistributor.PREFERENCES.contains(name)) {
622 final String pushServerPreference =
623 Strings.nullToEmpty(preferences.getString(
624 UnifiedPushDistributor.PREFERENCE_PUSH_SERVER,
625 getString(R.string.default_push_server))).trim();
626 if (isJidInvalid(pushServerPreference) || isHttpUri(pushServerPreference)) {
627 Toast.makeText(this,R.string.invalid_jid,Toast.LENGTH_LONG).show();
628 }
629 if (xmppConnectionService.reconfigurePushDistributor()) {
630 xmppConnectionService.renewUnifiedPushEndpoints();
631 }
632 }
633 }
634
635 private static boolean isJidInvalid(final String input) {
636 if (Strings.isNullOrEmpty(input)) {
637 return true;
638 }
639 try {
640 Jid.ofEscaped(input);
641 return false;
642 } catch (final IllegalArgumentException e) {
643 return true;
644 }
645 }
646
647 private static boolean isHttpUri(final String input) {
648 final URI uri;
649 try {
650 uri = new URI(input);
651 } catch (final URISyntaxException e) {
652 return false;
653 }
654 return Arrays.asList("http","https").contains(uri.getScheme());
655 }
656
657 @Override
658 public void onResume() {
659 super.onResume();
660 SettingsUtils.applyScreenshotPreventionSetting(this);
661 }
662
663 @Override
664 public void onRequestPermissionsResult(
665 int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
666 super.onRequestPermissionsResult(requestCode, permissions, grantResults);
667 if (grantResults.length > 0)
668 if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
669 if (requestCode == REQUEST_CREATE_BACKUP) {
670 createBackup();
671 }
672 if (requestCode == REQUEST_DOWNLOAD_STICKERS) {
673 downloadStickers();
674 }
675 } else {
676 Toast.makeText(
677 this,
678 getString(
679 R.string.no_storage_permission,
680 getString(R.string.app_name)),
681 Toast.LENGTH_SHORT)
682 .show();
683 }
684 }
685
686 private void createBackup() {
687 new AlertDialog.Builder(this)
688 .setTitle("Create Backup")
689 .setMessage("Export extra Cheogram-only data (backup will not import into other apps then)?")
690 .setPositiveButton(R.string.yes, (dialog, whichButton) -> {
691 createBackup(true);
692 })
693 .setNegativeButton(R.string.no, (dialog, whichButton) -> {
694 createBackup(false);
695 }).show();
696 }
697
698 private void createBackup(boolean withCheogramDb) {
699 Intent intent = new Intent(this, ExportBackupService.class);
700 intent.putExtra("cheogram_db", withCheogramDb);
701 ContextCompat.startForegroundService(this, intent);
702 final AlertDialog.Builder builder = new AlertDialog.Builder(this);
703 builder.setMessage(R.string.backup_started_message);
704 builder.setPositiveButton(R.string.ok, null);
705 builder.create().show();
706 }
707
708 private void downloadStickers() {
709 Intent intent = new Intent(this, DownloadDefaultStickers.class);
710 intent.putExtra("tor", xmppConnectionService.useTorToConnect());
711 ContextCompat.startForegroundService(this, intent);
712 displayToast("Sticker download started");
713 }
714
715 private void displayToast(final String msg) {
716 runOnUiThread(() -> Toast.makeText(SettingsActivity.this, msg, Toast.LENGTH_LONG).show());
717 }
718
719 private void reconnectAccounts() {
720 for (Account account : xmppConnectionService.getAccounts()) {
721 if (account.isEnabled()) {
722 xmppConnectionService.reconnectAccountInBackground(account);
723 }
724 }
725 }
726
727 public void refreshUiReal() {
728 // nothing to do. This Activity doesn't implement any listeners
729 }
730}