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