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 || Strings.isNullOrEmpty(Config.CHANNEL_DISCOVERY)) {
177 final PreferenceCategory groupChats =
178 (PreferenceCategory) mSettingsFragment.findPreference("group_chats");
179 final Preference channelDiscoveryMethod =
180 mSettingsFragment.findPreference("channel_discovery_method");
181 if (groupChats != null && channelDiscoveryMethod != null) {
182 groupChats.removePreference(channelDiscoveryMethod);
183 }
184 }
185
186 if (QuickConversationsService.isQuicksy()) {
187 final PreferenceCategory connectionOptions =
188 (PreferenceCategory) mSettingsFragment.findPreference("connection_options");
189 PreferenceScreen expert = (PreferenceScreen) mSettingsFragment.findPreference("expert");
190 if (connectionOptions != null) {
191 expert.removePreference(connectionOptions);
192 }
193 }
194
195 PreferenceScreen mainPreferenceScreen =
196 (PreferenceScreen) mSettingsFragment.findPreference("main_screen");
197
198 PreferenceCategory attachmentsCategory =
199 (PreferenceCategory) mSettingsFragment.findPreference("attachments");
200 CheckBoxPreference locationPlugin =
201 (CheckBoxPreference) mSettingsFragment.findPreference("use_share_location_plugin");
202 if (attachmentsCategory != null && locationPlugin != null) {
203 if (!GeoHelper.isLocationPluginInstalled(this)) {
204 attachmentsCategory.removePreference(locationPlugin);
205 }
206 }
207
208 // this feature is only available on Huawei Android 6.
209 PreferenceScreen huaweiPreferenceScreen =
210 (PreferenceScreen) mSettingsFragment.findPreference("huawei");
211 if (huaweiPreferenceScreen != null) {
212 Intent intent = huaweiPreferenceScreen.getIntent();
213 // remove when Api version is above M (Version 6.0) or if the intent is not callable
214 if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M || !isCallable(intent)) {
215 PreferenceCategory generalCategory =
216 (PreferenceCategory) mSettingsFragment.findPreference("general");
217 generalCategory.removePreference(huaweiPreferenceScreen);
218 if (generalCategory.getPreferenceCount() == 0) {
219 if (mainPreferenceScreen != null) {
220 mainPreferenceScreen.removePreference(generalCategory);
221 }
222 }
223 }
224 }
225
226 ListPreference automaticMessageDeletionList =
227 (ListPreference) mSettingsFragment.findPreference(AUTOMATIC_MESSAGE_DELETION);
228 if (automaticMessageDeletionList != null) {
229 final int[] choices =
230 getResources().getIntArray(R.array.automatic_message_deletion_values);
231 CharSequence[] entries = new CharSequence[choices.length];
232 CharSequence[] entryValues = new CharSequence[choices.length];
233 for (int i = 0; i < choices.length; ++i) {
234 entryValues[i] = String.valueOf(choices[i]);
235 if (choices[i] == 0) {
236 entries[i] = getString(R.string.never);
237 } else {
238 entries[i] = TimeFrameUtils.resolve(this, 1000L * choices[i]);
239 }
240 }
241 automaticMessageDeletionList.setEntries(entries);
242 automaticMessageDeletionList.setEntryValues(entryValues);
243 }
244
245 boolean removeLocation =
246 new Intent("eu.siacs.conversations.location.request")
247 .resolveActivity(getPackageManager())
248 == null;
249 boolean removeVoice =
250 new Intent(MediaStore.Audio.Media.RECORD_SOUND_ACTION)
251 .resolveActivity(getPackageManager())
252 == null;
253
254 ListPreference quickAction =
255 (ListPreference) mSettingsFragment.findPreference("quick_action");
256 if (quickAction != null && (removeLocation || removeVoice)) {
257 ArrayList<CharSequence> entries =
258 new ArrayList<>(Arrays.asList(quickAction.getEntries()));
259 ArrayList<CharSequence> entryValues =
260 new ArrayList<>(Arrays.asList(quickAction.getEntryValues()));
261 int index = entryValues.indexOf("location");
262 if (index > 0 && removeLocation) {
263 entries.remove(index);
264 entryValues.remove(index);
265 }
266 index = entryValues.indexOf("voice");
267 if (index > 0 && removeVoice) {
268 entries.remove(index);
269 entryValues.remove(index);
270 }
271 quickAction.setEntries(entries.toArray(new CharSequence[entries.size()]));
272 quickAction.setEntryValues(entryValues.toArray(new CharSequence[entryValues.size()]));
273 }
274
275 final Preference removeCertsPreference =
276 mSettingsFragment.findPreference("remove_trusted_certificates");
277 if (removeCertsPreference != null) {
278 removeCertsPreference.setOnPreferenceClickListener(
279 preference -> {
280 final MemorizingTrustManager mtm =
281 xmppConnectionService.getMemorizingTrustManager();
282 final ArrayList<String> aliases = Collections.list(mtm.getCertificates());
283 if (aliases.size() == 0) {
284 displayToast(getString(R.string.toast_no_trusted_certs));
285 return true;
286 }
287 final ArrayList<Integer> selectedItems = new ArrayList<>();
288 final AlertDialog.Builder dialogBuilder =
289 new AlertDialog.Builder(SettingsActivity.this);
290 dialogBuilder.setTitle(
291 getResources().getString(R.string.dialog_manage_certs_title));
292 dialogBuilder.setMultiChoiceItems(
293 aliases.toArray(new CharSequence[aliases.size()]),
294 null,
295 (dialog, indexSelected, isChecked) -> {
296 if (isChecked) {
297 selectedItems.add(indexSelected);
298 } else if (selectedItems.contains(indexSelected)) {
299 selectedItems.remove(Integer.valueOf(indexSelected));
300 }
301 ((AlertDialog) dialog)
302 .getButton(DialogInterface.BUTTON_POSITIVE)
303 .setEnabled(selectedItems.size() > 0);
304 });
305
306 dialogBuilder.setPositiveButton(
307 getResources()
308 .getString(R.string.dialog_manage_certs_positivebutton),
309 (dialog, which) -> {
310 int count = selectedItems.size();
311 if (count > 0) {
312 for (int i = 0; i < count; i++) {
313 try {
314 Integer item =
315 Integer.valueOf(
316 selectedItems.get(i).toString());
317 String alias = aliases.get(item);
318 mtm.deleteCertificate(alias);
319 } catch (KeyStoreException e) {
320 e.printStackTrace();
321 displayToast("Error: " + e.getLocalizedMessage());
322 }
323 }
324 if (xmppConnectionServiceBound) {
325 reconnectAccounts();
326 }
327 displayToast(
328 getResources()
329 .getQuantityString(
330 R.plurals.toast_delete_certificates,
331 count,
332 count));
333 }
334 });
335 dialogBuilder.setNegativeButton(
336 getResources()
337 .getString(R.string.dialog_manage_certs_negativebutton),
338 null);
339 AlertDialog removeCertsDialog = dialogBuilder.create();
340 removeCertsDialog.show();
341 removeCertsDialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(false);
342 return true;
343 });
344 }
345
346 final Preference createBackupPreference = mSettingsFragment.findPreference("create_backup");
347 if (createBackupPreference != null) {
348 createBackupPreference.setSummary(
349 getString(
350 R.string.pref_create_backup_summary,
351 FileBackend.getBackupDirectory(this).getAbsolutePath()));
352 createBackupPreference.setOnPreferenceClickListener(
353 preference -> {
354 if (hasStoragePermission(REQUEST_CREATE_BACKUP)) {
355 createBackup();
356 }
357 return true;
358 });
359 }
360
361 if (Config.ONLY_INTERNAL_STORAGE) {
362 final Preference cleanCachePreference = mSettingsFragment.findPreference("clean_cache");
363 if (cleanCachePreference != null) {
364 cleanCachePreference.setOnPreferenceClickListener(preference -> cleanCache());
365 }
366
367 final Preference cleanPrivateStoragePreference =
368 mSettingsFragment.findPreference("clean_private_storage");
369 if (cleanPrivateStoragePreference != null) {
370 cleanPrivateStoragePreference.setOnPreferenceClickListener(
371 preference -> cleanPrivateStorage());
372 }
373 }
374
375 final Preference deleteOmemoPreference =
376 mSettingsFragment.findPreference("delete_omemo_identities");
377 if (deleteOmemoPreference != null) {
378 deleteOmemoPreference.setOnPreferenceClickListener(
379 preference -> deleteOmemoIdentities());
380 }
381 if (Config.omemoOnly()) {
382 final PreferenceCategory privacyCategory =
383 (PreferenceCategory) mSettingsFragment.findPreference("privacy");
384 final Preference omemoPreference =mSettingsFragment.findPreference(OMEMO_SETTING);
385 if (omemoPreference != null) {
386 privacyCategory.removePreference(omemoPreference);
387 }
388 }
389
390 final Preference stickerDir = mSettingsFragment.findPreference("sticker_directory");
391 if (stickerDir != null) {
392 if (Build.VERSION.SDK_INT >= 24) {
393 stickerDir.setOnPreferenceClickListener((p) -> {
394 Intent intent = ((StorageManager) getSystemService(Context.STORAGE_SERVICE)).getPrimaryStorageVolume().createOpenDocumentTreeIntent();
395 startActivityForResult(Intent.createChooser(intent, "Choose sticker location"), 0);
396 return true;
397 });
398 } else {
399 PreferenceCategory expertMedia = (PreferenceCategory) mSettingsFragment.findPreference("expert_media");
400 expertMedia.removePreference(stickerDir);
401 }
402 }
403
404 final Preference downloadDefaultStickers = mSettingsFragment.findPreference("download_default_stickers");
405 if (downloadDefaultStickers != null) {
406 downloadDefaultStickers.setOnPreferenceClickListener(
407 preference -> {
408 if (hasStoragePermission(REQUEST_DOWNLOAD_STICKERS)) {
409 downloadStickers();
410 }
411 return true;
412 });
413 }
414
415 final Preference clearBlockedMedia = mSettingsFragment.findPreference("clear_blocked_media");
416 if (clearBlockedMedia != null) {
417 clearBlockedMedia.setOnPreferenceClickListener((p) -> {
418 xmppConnectionService.clearBlockedMedia();
419 displayToast("Blocked media will be displayed again.");
420 return true;
421 });
422 }
423
424 final String theTheme = PreferenceManager.getDefaultSharedPreferences(this).getString(THEME, "");
425 if (Build.VERSION.SDK_INT < 30 || !theTheme.equals("custom")) {
426 final PreferenceCategory uiCategory = (PreferenceCategory) mSettingsFragment.findPreference("ui");
427 final Preference customTheme = mSettingsFragment.findPreference("custom_theme");
428 if (customTheme != null) uiCategory.removePreference(customTheme);
429 }
430 }
431
432 private void changeOmemoSettingSummary() {
433 final ListPreference omemoPreference =
434 (ListPreference) mSettingsFragment.findPreference(OMEMO_SETTING);
435 if (omemoPreference == null) {
436 return;
437 }
438 final String value = omemoPreference.getValue();
439 switch (value) {
440 case "always":
441 omemoPreference.setSummary(R.string.pref_omemo_setting_summary_always);
442 break;
443 case "default_on":
444 omemoPreference.setSummary(R.string.pref_omemo_setting_summary_default_on);
445 break;
446 case "default_off":
447 omemoPreference.setSummary(R.string.pref_omemo_setting_summary_default_off);
448 break;
449 }
450 }
451
452 private boolean isCallable(final Intent i) {
453 return i != null
454 && getPackageManager()
455 .queryIntentActivities(i, PackageManager.MATCH_DEFAULT_ONLY)
456 .size()
457 > 0;
458 }
459
460 private boolean cleanCache() {
461 Intent intent = new Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
462 intent.setData(Uri.parse("package:" + getPackageName()));
463 startActivity(intent);
464 return true;
465 }
466
467 private boolean cleanPrivateStorage() {
468 for (String type : Arrays.asList("Images", "Videos", "Files", "Recordings")) {
469 cleanPrivateFiles(type);
470 }
471 return true;
472 }
473
474 private void cleanPrivateFiles(final String type) {
475 try {
476 File dir = new File(getFilesDir().getAbsolutePath(), "/" + type + "/");
477 File[] array = dir.listFiles();
478 if (array != null) {
479 for (int b = 0; b < array.length; b++) {
480 String name = array[b].getName().toLowerCase();
481 if (name.equals(".nomedia")) {
482 continue;
483 }
484 if (array[b].isFile()) {
485 array[b].delete();
486 }
487 }
488 }
489 } catch (Throwable e) {
490 Log.e("CleanCache", e.toString());
491 }
492 }
493
494 private boolean deleteOmemoIdentities() {
495 AlertDialog.Builder builder = new AlertDialog.Builder(this);
496 builder.setTitle(R.string.pref_delete_omemo_identities);
497 final List<CharSequence> accounts = new ArrayList<>();
498 for (Account account : xmppConnectionService.getAccounts()) {
499 if (account.isEnabled()) {
500 accounts.add(account.getJid().asBareJid().toString());
501 }
502 }
503 final boolean[] checkedItems = new boolean[accounts.size()];
504 builder.setMultiChoiceItems(
505 accounts.toArray(new CharSequence[accounts.size()]),
506 checkedItems,
507 (dialog, which, isChecked) -> {
508 checkedItems[which] = isChecked;
509 final AlertDialog alertDialog = (AlertDialog) dialog;
510 for (boolean item : checkedItems) {
511 if (item) {
512 alertDialog.getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(true);
513 return;
514 }
515 }
516 alertDialog.getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(false);
517 });
518 builder.setNegativeButton(R.string.cancel, null);
519 builder.setPositiveButton(
520 R.string.delete_selected_keys,
521 (dialog, which) -> {
522 for (int i = 0; i < checkedItems.length; ++i) {
523 if (checkedItems[i]) {
524 try {
525 Jid jid = Jid.of(accounts.get(i).toString());
526 Account account = xmppConnectionService.findAccountByJid(jid);
527 if (account != null) {
528 account.getAxolotlService().regenerateKeys(true);
529 }
530 } catch (IllegalArgumentException e) {
531 //
532 }
533 }
534 }
535 });
536 AlertDialog dialog = builder.create();
537 dialog.show();
538 dialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(false);
539 return true;
540 }
541
542 @Override
543 public void onStop() {
544 super.onStop();
545 PreferenceManager.getDefaultSharedPreferences(this)
546 .unregisterOnSharedPreferenceChangeListener(this);
547 }
548
549 @Override
550 public void onSharedPreferenceChanged(SharedPreferences preferences, String name) {
551 final List<String> resendPresence =
552 Arrays.asList(
553 "confirm_messages",
554 DND_ON_SILENT_MODE,
555 AWAY_WHEN_SCREEN_IS_OFF,
556 "allow_message_correction",
557 TREAT_VIBRATE_AS_SILENT,
558 MANUALLY_CHANGE_PRESENCE,
559 BROADCAST_LAST_ACTIVITY);
560 if (name.equals(OMEMO_SETTING)) {
561 OmemoSetting.load(this, preferences);
562 changeOmemoSettingSummary();
563 } else if (name.equals(KEEP_FOREGROUND_SERVICE)) {
564 xmppConnectionService.toggleForegroundService();
565 } else if (resendPresence.contains(name)) {
566 if (xmppConnectionServiceBound) {
567 if (name.equals(AWAY_WHEN_SCREEN_IS_OFF) || name.equals(MANUALLY_CHANGE_PRESENCE)) {
568 xmppConnectionService.toggleScreenEventReceiver();
569 }
570 xmppConnectionService.refreshAllPresences();
571 }
572 } else if (name.equals("dont_trust_system_cas")) {
573 xmppConnectionService.updateMemorizingTrustmanager();
574 reconnectAccounts();
575 } else if (name.equals("use_tor")) {
576 if (preferences.getBoolean(name, false)) {
577 displayToast(getString(R.string.audio_video_disabled_tor));
578 }
579 reconnectAccounts();
580 xmppConnectionService.reinitializeMuclumbusService();
581 } else if (name.equals(AUTOMATIC_MESSAGE_DELETION)) {
582 xmppConnectionService.expireOldMessages(true);
583 } 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")) {
584 final int theme = findTheme();
585 xmppConnectionService.setTheme(theme);
586 ThemeHelper.applyCustomColors(xmppConnectionService);
587 recreate();
588 } else if (name.equals(PREVENT_SCREENSHOTS)) {
589 SettingsUtils.applyScreenshotPreventionSetting(this);
590 } else if (UnifiedPushDistributor.PREFERENCES.contains(name)) {
591 final String pushServerPreference =
592 Strings.nullToEmpty(preferences.getString(
593 UnifiedPushDistributor.PREFERENCE_PUSH_SERVER,
594 getString(R.string.default_push_server))).trim();
595 if (isJidInvalid(pushServerPreference) || isHttpUri(pushServerPreference)) {
596 Toast.makeText(this,R.string.invalid_jid,Toast.LENGTH_LONG).show();
597 }
598 if (xmppConnectionService.reconfigurePushDistributor()) {
599 xmppConnectionService.renewUnifiedPushEndpoints();
600 }
601 }
602 }
603
604 private static boolean isJidInvalid(final String input) {
605 if (Strings.isNullOrEmpty(input)) {
606 return true;
607 }
608 try {
609 Jid.ofEscaped(input);
610 return false;
611 } catch (final IllegalArgumentException e) {
612 return true;
613 }
614 }
615
616 private static boolean isHttpUri(final String input) {
617 final URI uri;
618 try {
619 uri = new URI(input);
620 } catch (final URISyntaxException e) {
621 return false;
622 }
623 return Arrays.asList("http","https").contains(uri.getScheme());
624 }
625
626 @Override
627 public void onResume() {
628 super.onResume();
629 SettingsUtils.applyScreenshotPreventionSetting(this);
630 }
631
632 @Override
633 public void onRequestPermissionsResult(
634 int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
635 super.onRequestPermissionsResult(requestCode, permissions, grantResults);
636 if (grantResults.length > 0)
637 if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
638 if (requestCode == REQUEST_CREATE_BACKUP) {
639 createBackup();
640 }
641 if (requestCode == REQUEST_DOWNLOAD_STICKERS) {
642 downloadStickers();
643 }
644 } else {
645 Toast.makeText(
646 this,
647 getString(
648 R.string.no_storage_permission,
649 getString(R.string.app_name)),
650 Toast.LENGTH_SHORT)
651 .show();
652 }
653 }
654
655 private void createBackup() {
656 new AlertDialog.Builder(this)
657 .setTitle("Create Backup")
658 .setMessage("Export extra Cheogram-only data (backup will not import into other apps then)?")
659 .setPositiveButton(R.string.yes, (dialog, whichButton) -> {
660 createBackup(true);
661 })
662 .setNegativeButton(R.string.no, (dialog, whichButton) -> {
663 createBackup(false);
664 }).show();
665 }
666
667 private void createBackup(boolean withCheogramDb) {
668 Intent intent = new Intent(this, ExportBackupService.class);
669 intent.putExtra("cheogram_db", withCheogramDb);
670 ContextCompat.startForegroundService(this, intent);
671 final AlertDialog.Builder builder = new AlertDialog.Builder(this);
672 builder.setMessage(R.string.backup_started_message);
673 builder.setPositiveButton(R.string.ok, null);
674 builder.create().show();
675 }
676
677 private void downloadStickers() {
678 Intent intent = new Intent(this, DownloadDefaultStickers.class);
679 intent.putExtra("tor", xmppConnectionService.useTorToConnect());
680 ContextCompat.startForegroundService(this, intent);
681 displayToast("Sticker download started");
682 }
683
684 private void displayToast(final String msg) {
685 runOnUiThread(() -> Toast.makeText(SettingsActivity.this, msg, Toast.LENGTH_LONG).show());
686 }
687
688 private void reconnectAccounts() {
689 for (Account account : xmppConnectionService.getAccounts()) {
690 if (account.isEnabled()) {
691 xmppConnectionService.reconnectAccountInBackground(account);
692 }
693 }
694 }
695
696 public void refreshUiReal() {
697 // nothing to do. This Activity doesn't implement any listeners
698 }
699}