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