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 stickerDir.setOnPreferenceClickListener((p) -> {
382 Intent intent = ((StorageManager) getSystemService(Context.STORAGE_SERVICE)).getPrimaryStorageVolume().createOpenDocumentTreeIntent();
383 startActivityForResult(Intent.createChooser(intent, "Choose sticker location"), 0);
384 return true;
385 });
386 }
387
388 final Preference clearBlockedMedia = mSettingsFragment.findPreference("clear_blocked_media");
389 if (clearBlockedMedia != null) {
390 clearBlockedMedia.setOnPreferenceClickListener((p) -> {
391 xmppConnectionService.clearBlockedMedia();
392 displayToast("Blocked media will be displayed again.");
393 return true;
394 });
395 }
396
397 final String theTheme = PreferenceManager.getDefaultSharedPreferences(this).getString(THEME, "");
398 if (Build.VERSION.SDK_INT < 30 || !theTheme.equals("custom")) {
399 final PreferenceCategory uiCategory = (PreferenceCategory) mSettingsFragment.findPreference("ui");
400 final Preference customTheme = mSettingsFragment.findPreference("custom_theme");
401 if (customTheme != null) uiCategory.removePreference(customTheme);
402 }
403 }
404
405 private void changeOmemoSettingSummary() {
406 final ListPreference omemoPreference =
407 (ListPreference) mSettingsFragment.findPreference(OMEMO_SETTING);
408 if (omemoPreference == null) {
409 return;
410 }
411 final String value = omemoPreference.getValue();
412 switch (value) {
413 case "always":
414 omemoPreference.setSummary(R.string.pref_omemo_setting_summary_always);
415 break;
416 case "default_on":
417 omemoPreference.setSummary(R.string.pref_omemo_setting_summary_default_on);
418 break;
419 case "default_off":
420 omemoPreference.setSummary(R.string.pref_omemo_setting_summary_default_off);
421 break;
422 }
423 }
424
425 private boolean isCallable(final Intent i) {
426 return i != null
427 && getPackageManager()
428 .queryIntentActivities(i, PackageManager.MATCH_DEFAULT_ONLY)
429 .size()
430 > 0;
431 }
432
433 private boolean cleanCache() {
434 Intent intent = new Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
435 intent.setData(Uri.parse("package:" + getPackageName()));
436 startActivity(intent);
437 return true;
438 }
439
440 private boolean cleanPrivateStorage() {
441 for (String type : Arrays.asList("Images", "Videos", "Files", "Recordings")) {
442 cleanPrivateFiles(type);
443 }
444 return true;
445 }
446
447 private void cleanPrivateFiles(final String type) {
448 try {
449 File dir = new File(getFilesDir().getAbsolutePath(), "/" + type + "/");
450 File[] array = dir.listFiles();
451 if (array != null) {
452 for (int b = 0; b < array.length; b++) {
453 String name = array[b].getName().toLowerCase();
454 if (name.equals(".nomedia")) {
455 continue;
456 }
457 if (array[b].isFile()) {
458 array[b].delete();
459 }
460 }
461 }
462 } catch (Throwable e) {
463 Log.e("CleanCache", e.toString());
464 }
465 }
466
467 private boolean deleteOmemoIdentities() {
468 AlertDialog.Builder builder = new AlertDialog.Builder(this);
469 builder.setTitle(R.string.pref_delete_omemo_identities);
470 final List<CharSequence> accounts = new ArrayList<>();
471 for (Account account : xmppConnectionService.getAccounts()) {
472 if (account.isEnabled()) {
473 accounts.add(account.getJid().asBareJid().toString());
474 }
475 }
476 final boolean[] checkedItems = new boolean[accounts.size()];
477 builder.setMultiChoiceItems(
478 accounts.toArray(new CharSequence[accounts.size()]),
479 checkedItems,
480 (dialog, which, isChecked) -> {
481 checkedItems[which] = isChecked;
482 final AlertDialog alertDialog = (AlertDialog) dialog;
483 for (boolean item : checkedItems) {
484 if (item) {
485 alertDialog.getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(true);
486 return;
487 }
488 }
489 alertDialog.getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(false);
490 });
491 builder.setNegativeButton(R.string.cancel, null);
492 builder.setPositiveButton(
493 R.string.delete_selected_keys,
494 (dialog, which) -> {
495 for (int i = 0; i < checkedItems.length; ++i) {
496 if (checkedItems[i]) {
497 try {
498 Jid jid = Jid.of(accounts.get(i).toString());
499 Account account = xmppConnectionService.findAccountByJid(jid);
500 if (account != null) {
501 account.getAxolotlService().regenerateKeys(true);
502 }
503 } catch (IllegalArgumentException e) {
504 //
505 }
506 }
507 }
508 });
509 AlertDialog dialog = builder.create();
510 dialog.show();
511 dialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(false);
512 return true;
513 }
514
515 @Override
516 public void onStop() {
517 super.onStop();
518 PreferenceManager.getDefaultSharedPreferences(this)
519 .unregisterOnSharedPreferenceChangeListener(this);
520 }
521
522 @Override
523 public void onSharedPreferenceChanged(SharedPreferences preferences, String name) {
524 final List<String> resendPresence =
525 Arrays.asList(
526 "confirm_messages",
527 DND_ON_SILENT_MODE,
528 AWAY_WHEN_SCREEN_IS_OFF,
529 "allow_message_correction",
530 TREAT_VIBRATE_AS_SILENT,
531 MANUALLY_CHANGE_PRESENCE,
532 BROADCAST_LAST_ACTIVITY);
533 if (name.equals(OMEMO_SETTING)) {
534 OmemoSetting.load(this, preferences);
535 changeOmemoSettingSummary();
536 } else if (name.equals(KEEP_FOREGROUND_SERVICE)) {
537 xmppConnectionService.toggleForegroundService();
538 } else if (resendPresence.contains(name)) {
539 if (xmppConnectionServiceBound) {
540 if (name.equals(AWAY_WHEN_SCREEN_IS_OFF) || name.equals(MANUALLY_CHANGE_PRESENCE)) {
541 xmppConnectionService.toggleScreenEventReceiver();
542 }
543 xmppConnectionService.refreshAllPresences();
544 }
545 } else if (name.equals("dont_trust_system_cas")) {
546 xmppConnectionService.updateMemorizingTrustmanager();
547 reconnectAccounts();
548 } else if (name.equals("use_tor")) {
549 if (preferences.getBoolean(name, false)) {
550 displayToast(getString(R.string.audio_video_disabled_tor));
551 }
552 reconnectAccounts();
553 xmppConnectionService.reinitializeMuclumbusService();
554 } else if (name.equals(AUTOMATIC_MESSAGE_DELETION)) {
555 xmppConnectionService.expireOldMessages(true);
556 } 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")) {
557 final int theme = findTheme();
558 xmppConnectionService.setTheme(theme);
559 ThemeHelper.applyCustomColors(xmppConnectionService);
560 recreate();
561 } else if (name.equals(PREVENT_SCREENSHOTS)) {
562 SettingsUtils.applyScreenshotPreventionSetting(this);
563 } else if (UnifiedPushDistributor.PREFERENCES.contains(name)) {
564 if (xmppConnectionService.reconfigurePushDistributor()) {
565 xmppConnectionService.renewUnifiedPushEndpoints();
566 }
567 }
568 }
569
570 @Override
571 public void onResume() {
572 super.onResume();
573 SettingsUtils.applyScreenshotPreventionSetting(this);
574 }
575
576 @Override
577 public void onRequestPermissionsResult(
578 int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
579 super.onRequestPermissionsResult(requestCode, permissions, grantResults);
580 if (grantResults.length > 0)
581 if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
582 if (requestCode == REQUEST_CREATE_BACKUP) {
583 createBackup();
584 }
585 } else {
586 Toast.makeText(
587 this,
588 getString(
589 R.string.no_storage_permission,
590 getString(R.string.app_name)),
591 Toast.LENGTH_SHORT)
592 .show();
593 }
594 }
595
596 private void createBackup() {
597 new AlertDialog.Builder(this)
598 .setTitle("Create Backup")
599 .setMessage("Export extra Cheogram-only data (backup will not import into other apps then)?")
600 .setPositiveButton(R.string.yes, (dialog, whichButton) -> {
601 createBackup(true);
602 })
603 .setNegativeButton(R.string.no, (dialog, whichButton) -> {
604 createBackup(false);
605 }).show();
606 }
607
608 private void createBackup(boolean withCheogramDb) {
609 Intent intent = new Intent(this, ExportBackupService.class);
610 intent.putExtra("cheogram_db", withCheogramDb);
611 ContextCompat.startForegroundService(this, intent);
612 final AlertDialog.Builder builder = new AlertDialog.Builder(this);
613 builder.setMessage(R.string.backup_started_message);
614 builder.setPositiveButton(R.string.ok, null);
615 builder.create().show();
616 }
617
618 private void displayToast(final String msg) {
619 runOnUiThread(() -> Toast.makeText(SettingsActivity.this, msg, Toast.LENGTH_LONG).show());
620 }
621
622 private void reconnectAccounts() {
623 for (Account account : xmppConnectionService.getAccounts()) {
624 if (account.isEnabled()) {
625 xmppConnectionService.reconnectAccountInBackground(account);
626 }
627 }
628 }
629
630 public void refreshUiReal() {
631 // nothing to do. This Activity doesn't implement any listeners
632 }
633}