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 final boolean customAutomatic = PreferenceManager.getDefaultSharedPreferences(this).getBoolean("custom_theme_automatic", false);
433 if (Build.VERSION.SDK_INT > 30 && theTheme.equals("custom") && !customAutomatic) {
434 final PreferenceScreen customTheme = (PreferenceScreen) mSettingsFragment.findPreference("custom_theme");
435 final boolean isDark = PreferenceManager.getDefaultSharedPreferences(this).getBoolean("custom_theme_dark", false);
436 if (isDark) {
437 final PreferenceCategory customThemeColors = (PreferenceCategory) mSettingsFragment.findPreference("custom_theme_colors");
438 customTheme.removePreference(customThemeColors);
439 } else {
440 final PreferenceCategory customThemeColorsDark = (PreferenceCategory) mSettingsFragment.findPreference("custom_theme_colors_dark");
441 customTheme.removePreference(customThemeColorsDark);
442 }
443 }
444 }
445
446 private void changeOmemoSettingSummary() {
447 final ListPreference omemoPreference =
448 (ListPreference) mSettingsFragment.findPreference(OMEMO_SETTING);
449 if (omemoPreference == null) {
450 return;
451 }
452 final String value = omemoPreference.getValue();
453 switch (value) {
454 case "always":
455 omemoPreference.setSummary(R.string.pref_omemo_setting_summary_always);
456 break;
457 case "default_on":
458 omemoPreference.setSummary(R.string.pref_omemo_setting_summary_default_on);
459 break;
460 case "default_off":
461 omemoPreference.setSummary(R.string.pref_omemo_setting_summary_default_off);
462 break;
463 }
464 }
465
466 private boolean isCallable(final Intent i) {
467 return i != null
468 && getPackageManager()
469 .queryIntentActivities(i, PackageManager.MATCH_DEFAULT_ONLY)
470 .size()
471 > 0;
472 }
473
474 private boolean cleanCache() {
475 Intent intent = new Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
476 intent.setData(Uri.parse("package:" + getPackageName()));
477 startActivity(intent);
478 return true;
479 }
480
481 private boolean cleanPrivateStorage() {
482 for (String type : Arrays.asList("Images", "Videos", "Files", "Recordings")) {
483 cleanPrivateFiles(type);
484 }
485 return true;
486 }
487
488 private void cleanPrivateFiles(final String type) {
489 try {
490 File dir = new File(getFilesDir().getAbsolutePath(), "/" + type + "/");
491 File[] array = dir.listFiles();
492 if (array != null) {
493 for (int b = 0; b < array.length; b++) {
494 String name = array[b].getName().toLowerCase();
495 if (name.equals(".nomedia")) {
496 continue;
497 }
498 if (array[b].isFile()) {
499 array[b].delete();
500 }
501 }
502 }
503 } catch (Throwable e) {
504 Log.e("CleanCache", e.toString());
505 }
506 }
507
508 private boolean deleteOmemoIdentities() {
509 AlertDialog.Builder builder = new AlertDialog.Builder(this);
510 builder.setTitle(R.string.pref_delete_omemo_identities);
511 final List<CharSequence> accounts = new ArrayList<>();
512 for (Account account : xmppConnectionService.getAccounts()) {
513 if (account.isEnabled()) {
514 accounts.add(account.getJid().asBareJid().toString());
515 }
516 }
517 final boolean[] checkedItems = new boolean[accounts.size()];
518 builder.setMultiChoiceItems(
519 accounts.toArray(new CharSequence[accounts.size()]),
520 checkedItems,
521 (dialog, which, isChecked) -> {
522 checkedItems[which] = isChecked;
523 final AlertDialog alertDialog = (AlertDialog) dialog;
524 for (boolean item : checkedItems) {
525 if (item) {
526 alertDialog.getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(true);
527 return;
528 }
529 }
530 alertDialog.getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(false);
531 });
532 builder.setNegativeButton(R.string.cancel, null);
533 builder.setPositiveButton(
534 R.string.delete_selected_keys,
535 (dialog, which) -> {
536 for (int i = 0; i < checkedItems.length; ++i) {
537 if (checkedItems[i]) {
538 try {
539 Jid jid = Jid.of(accounts.get(i).toString());
540 Account account = xmppConnectionService.findAccountByJid(jid);
541 if (account != null) {
542 account.getAxolotlService().regenerateKeys(true);
543 }
544 } catch (IllegalArgumentException e) {
545 //
546 }
547 }
548 }
549 });
550 AlertDialog dialog = builder.create();
551 dialog.show();
552 dialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(false);
553 return true;
554 }
555
556 @Override
557 public void onStop() {
558 super.onStop();
559 PreferenceManager.getDefaultSharedPreferences(this)
560 .unregisterOnSharedPreferenceChangeListener(this);
561 }
562
563 @Override
564 public void onSharedPreferenceChanged(SharedPreferences preferences, String name) {
565 final List<String> resendPresence =
566 Arrays.asList(
567 "confirm_messages",
568 DND_ON_SILENT_MODE,
569 AWAY_WHEN_SCREEN_IS_OFF,
570 "allow_message_correction",
571 TREAT_VIBRATE_AS_SILENT,
572 MANUALLY_CHANGE_PRESENCE,
573 BROADCAST_LAST_ACTIVITY);
574 if (name.equals(OMEMO_SETTING)) {
575 OmemoSetting.load(this, preferences);
576 changeOmemoSettingSummary();
577 } else if (name.equals(KEEP_FOREGROUND_SERVICE)) {
578 xmppConnectionService.toggleForegroundService();
579 } else if (resendPresence.contains(name)) {
580 if (xmppConnectionServiceBound) {
581 if (name.equals(AWAY_WHEN_SCREEN_IS_OFF) || name.equals(MANUALLY_CHANGE_PRESENCE)) {
582 xmppConnectionService.toggleScreenEventReceiver();
583 }
584 xmppConnectionService.refreshAllPresences();
585 }
586 } else if (name.equals("dont_trust_system_cas")) {
587 xmppConnectionService.updateMemorizingTrustmanager();
588 reconnectAccounts();
589 } else if (name.equals("use_tor")) {
590 if (preferences.getBoolean(name, false)) {
591 displayToast(getString(R.string.audio_video_disabled_tor));
592 }
593 reconnectAccounts();
594 xmppConnectionService.reinitializeMuclumbusService();
595 } else if (name.equals(AUTOMATIC_MESSAGE_DELETION)) {
596 xmppConnectionService.expireOldMessages(true);
597 } else if ( name.equals(THEME) ||
598 name.equals("custom_theme_automatic") ||
599 name.equals("custom_theme_dark") ||
600 name.equals("custom_theme_primary") ||
601 name.equals("custom_theme_primary_dark") ||
602 name.equals("custom_theme_accent") ||
603 name.equals("custom_theme_background_primary") ||
604 name.equals("custom_dark_theme_primary") ||
605 name.equals("custom_dark_theme_primary_dark") ||
606 name.equals("custom_dark_theme_accent") ||
607 name.equals("custom_dark_theme_background_primary"))
608 {
609 final int theme = findTheme();
610 xmppConnectionService.setTheme(theme);
611 ThemeHelper.applyCustomColors(xmppConnectionService);
612 recreate();
613 } else if (name.equals(PREVENT_SCREENSHOTS)) {
614 SettingsUtils.applyScreenshotPreventionSetting(this);
615 } else if (UnifiedPushDistributor.PREFERENCES.contains(name)) {
616 final String pushServerPreference =
617 Strings.nullToEmpty(preferences.getString(
618 UnifiedPushDistributor.PREFERENCE_PUSH_SERVER,
619 getString(R.string.default_push_server))).trim();
620 if (isJidInvalid(pushServerPreference) || isHttpUri(pushServerPreference)) {
621 Toast.makeText(this,R.string.invalid_jid,Toast.LENGTH_LONG).show();
622 }
623 if (xmppConnectionService.reconfigurePushDistributor()) {
624 xmppConnectionService.renewUnifiedPushEndpoints();
625 }
626 }
627 }
628
629 private static boolean isJidInvalid(final String input) {
630 if (Strings.isNullOrEmpty(input)) {
631 return true;
632 }
633 try {
634 Jid.ofEscaped(input);
635 return false;
636 } catch (final IllegalArgumentException e) {
637 return true;
638 }
639 }
640
641 private static boolean isHttpUri(final String input) {
642 final URI uri;
643 try {
644 uri = new URI(input);
645 } catch (final URISyntaxException e) {
646 return false;
647 }
648 return Arrays.asList("http","https").contains(uri.getScheme());
649 }
650
651 @Override
652 public void onResume() {
653 super.onResume();
654 SettingsUtils.applyScreenshotPreventionSetting(this);
655 }
656
657 @Override
658 public void onRequestPermissionsResult(
659 int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
660 super.onRequestPermissionsResult(requestCode, permissions, grantResults);
661 if (grantResults.length > 0)
662 if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
663 if (requestCode == REQUEST_CREATE_BACKUP) {
664 createBackup();
665 }
666 if (requestCode == REQUEST_DOWNLOAD_STICKERS) {
667 downloadStickers();
668 }
669 } else {
670 Toast.makeText(
671 this,
672 getString(
673 R.string.no_storage_permission,
674 getString(R.string.app_name)),
675 Toast.LENGTH_SHORT)
676 .show();
677 }
678 }
679
680 private void createBackup() {
681 new AlertDialog.Builder(this)
682 .setTitle("Create Backup")
683 .setMessage("Export extra Cheogram-only data (backup will not import into other apps then)?")
684 .setPositiveButton(R.string.yes, (dialog, whichButton) -> {
685 createBackup(true);
686 })
687 .setNegativeButton(R.string.no, (dialog, whichButton) -> {
688 createBackup(false);
689 }).show();
690 }
691
692 private void createBackup(boolean withCheogramDb) {
693 Intent intent = new Intent(this, ExportBackupService.class);
694 intent.putExtra("cheogram_db", withCheogramDb);
695 ContextCompat.startForegroundService(this, intent);
696 final AlertDialog.Builder builder = new AlertDialog.Builder(this);
697 builder.setMessage(R.string.backup_started_message);
698 builder.setPositiveButton(R.string.ok, null);
699 builder.create().show();
700 }
701
702 private void downloadStickers() {
703 Intent intent = new Intent(this, DownloadDefaultStickers.class);
704 intent.putExtra("tor", xmppConnectionService.useTorToConnect());
705 ContextCompat.startForegroundService(this, intent);
706 displayToast("Sticker download started");
707 }
708
709 private void displayToast(final String msg) {
710 runOnUiThread(() -> Toast.makeText(SettingsActivity.this, msg, Toast.LENGTH_LONG).show());
711 }
712
713 private void reconnectAccounts() {
714 for (Account account : xmppConnectionService.getAccounts()) {
715 if (account.isEnabled()) {
716 xmppConnectionService.reconnectAccountInBackground(account);
717 }
718 }
719 }
720
721 public void refreshUiReal() {
722 // nothing to do. This Activity doesn't implement any listeners
723 }
724}