SettingsActivity.java

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