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