/* This file is part of Subsonic. Subsonic is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Subsonic is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Subsonic. If not, see . Copyright 2014 (C) Scott Jackson */ package net.nullsum.audinaut.fragments; import android.accounts.Account; import android.app.backup.BackupManager; import android.content.ContentResolver; import android.content.Intent; import android.content.SharedPreferences; import android.net.Uri; import android.os.Bundle; import android.preference.CheckBoxPreference; import android.preference.EditTextPreference; import android.preference.ListPreference; import android.preference.Preference; import android.preference.PreferenceCategory; import android.preference.PreferenceScreen; import android.text.InputType; import android.util.Log; import android.view.View; import android.view.ViewGroup; import android.widget.Button; import android.widget.EditText; import net.nullsum.audinaut.R; import net.nullsum.audinaut.service.DownloadService; import net.nullsum.audinaut.service.HeadphoneListenerService; import net.nullsum.audinaut.service.MusicService; import net.nullsum.audinaut.service.MusicServiceFactory; import net.nullsum.audinaut.util.Constants; import net.nullsum.audinaut.util.FileUtil; import net.nullsum.audinaut.util.LoadingTask; import net.nullsum.audinaut.util.SyncUtil; import net.nullsum.audinaut.util.Util; import net.nullsum.audinaut.view.CacheLocationPreference; import net.nullsum.audinaut.view.ErrorDialog; import java.io.File; import java.net.URL; import java.text.DecimalFormat; import java.util.LinkedHashMap; import java.util.Map; public class SettingsFragment extends PreferenceCompatFragment implements SharedPreferences.OnSharedPreferenceChangeListener { private final static String TAG = SettingsFragment.class.getSimpleName(); private final Map serverSettings = new LinkedHashMap<>(); private boolean testingConnection; private ListPreference theme; private ListPreference maxBitrateWifi; private ListPreference maxBitrateMobile; private ListPreference networkTimeout; private CacheLocationPreference cacheLocation; private ListPreference preloadCountWifi; private ListPreference preloadCountMobile; private ListPreference keepPlayedCount; private ListPreference tempLoss; private ListPreference pauseDisconnect; private PreferenceCategory serversCategory; private ListPreference songPressAction; private ListPreference syncInterval; private CheckBoxPreference syncEnabled; private CheckBoxPreference syncWifi; private CheckBoxPreference syncNotification; private CheckBoxPreference syncMostRecent; private CheckBoxPreference replayGain; private ListPreference replayGainType; private Preference replayGainBump; private Preference replayGainUntagged; private String internalSSID; private String internalSSIDDisplay; private EditTextPreference cacheSize; private int serverCount = 3; private SharedPreferences settings; private DecimalFormat megabyteFromat; @Override public void onCreate(Bundle bundle) { super.onCreate(bundle); int instance = this.getArguments().getInt(Constants.PREFERENCES_KEY_SERVER_INSTANCE, -1); if (instance != -1) { PreferenceScreen preferenceScreen = expandServer(instance); setPreferenceScreen(preferenceScreen); serverSettings.put(Integer.toString(instance), new ServerSettings(instance)); onInitPreferences(preferenceScreen); } } @Override public void onDestroy() { super.onDestroy(); SharedPreferences prefs = Util.getPreferences(context); prefs.unregisterOnSharedPreferenceChangeListener(this); } @Override protected void onStartNewFragment(String name) { SettingsFragment newFragment = new SettingsFragment(); Bundle args = new Bundle(); int xml = 0; if ("appearance".equals(name)) { xml = R.xml.settings_appearance; } else if ("cache".equals(name)) { xml = R.xml.settings_cache; } else if ("playback".equals(name)) { xml = R.xml.settings_playback; } else if ("servers".equals(name)) { xml = R.xml.settings_servers; } if (xml != 0) { args.putInt(Constants.INTENT_EXTRA_FRAGMENT_TYPE, xml); newFragment.setArguments(args); replaceFragment(newFragment); } } @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { // Random error I have no idea how to reproduce if (sharedPreferences == null) { return; } update(); if (Constants.PREFERENCES_KEY_HIDE_MEDIA.equals(key)) { setHideMedia(sharedPreferences.getBoolean(key, true)); } else if (Constants.PREFERENCES_KEY_MEDIA_BUTTONS.equals(key)) { setMediaButtonsEnabled(sharedPreferences.getBoolean(key, true)); } else if (Constants.PREFERENCES_KEY_CACHE_LOCATION.equals(key)) { setCacheLocation(sharedPreferences.getString(key, "")); } else if (Constants.PREFERENCES_KEY_SYNC_MOST_RECENT.equals(key)) { SyncUtil.removeMostRecentSyncFiles(context); } else if (Constants.PREFERENCES_KEY_REPLAY_GAIN.equals(key) || Constants.PREFERENCES_KEY_REPLAY_GAIN_BUMP.equals(key) || Constants.PREFERENCES_KEY_REPLAY_GAIN_UNTAGGED.equals(key)) { DownloadService downloadService = DownloadService.getInstance(); if (downloadService != null) { downloadService.reapplyVolume(); } } else if (Constants.PREFERENCES_KEY_START_ON_HEADPHONES.equals(key)) { Intent serviceIntent = new Intent(); serviceIntent.setClassName(context.getPackageName(), HeadphoneListenerService.class.getName()); if (sharedPreferences.getBoolean(key, false)) { context.startService(serviceIntent); } else { context.stopService(serviceIntent); } } scheduleBackup(); } @Override protected void onInitPreferences(PreferenceScreen preferenceScreen) { this.setTitle(preferenceScreen.getTitle()); internalSSID = Util.getSSID(context); if (internalSSID == null) { internalSSID = ""; } internalSSIDDisplay = context.getResources().getString(R.string.settings_server_local_network_ssid_hint, internalSSID); theme = (ListPreference) this.findPreference(Constants.PREFERENCES_KEY_THEME); maxBitrateWifi = (ListPreference) this.findPreference(Constants.PREFERENCES_KEY_MAX_BITRATE_WIFI); maxBitrateMobile = (ListPreference) this.findPreference(Constants.PREFERENCES_KEY_MAX_BITRATE_MOBILE); networkTimeout = (ListPreference) this.findPreference(Constants.PREFERENCES_KEY_NETWORK_TIMEOUT); cacheLocation = (CacheLocationPreference) this.findPreference(Constants.PREFERENCES_KEY_CACHE_LOCATION); preloadCountWifi = (ListPreference) this.findPreference(Constants.PREFERENCES_KEY_PRELOAD_COUNT_WIFI); preloadCountMobile = (ListPreference) this.findPreference(Constants.PREFERENCES_KEY_PRELOAD_COUNT_MOBILE); keepPlayedCount = (ListPreference) this.findPreference(Constants.PREFERENCES_KEY_KEEP_PLAYED_CNT); tempLoss = (ListPreference) this.findPreference(Constants.PREFERENCES_KEY_TEMP_LOSS); pauseDisconnect = (ListPreference) this.findPreference(Constants.PREFERENCES_KEY_PAUSE_DISCONNECT); serversCategory = (PreferenceCategory) this.findPreference(Constants.PREFERENCES_KEY_SERVER_KEY); Preference addServerPreference = this.findPreference(Constants.PREFERENCES_KEY_SERVER_ADD); songPressAction = (ListPreference) this.findPreference(Constants.PREFERENCES_KEY_SONG_PRESS_ACTION); syncInterval = (ListPreference) this.findPreference(Constants.PREFERENCES_KEY_SYNC_INTERVAL); syncEnabled = (CheckBoxPreference) this.findPreference(Constants.PREFERENCES_KEY_SYNC_ENABLED); syncWifi = (CheckBoxPreference) this.findPreference(Constants.PREFERENCES_KEY_SYNC_WIFI); syncNotification = (CheckBoxPreference) this.findPreference(Constants.PREFERENCES_KEY_SYNC_NOTIFICATION); syncMostRecent = (CheckBoxPreference) this.findPreference(Constants.PREFERENCES_KEY_SYNC_MOST_RECENT); replayGain = (CheckBoxPreference) this.findPreference(Constants.PREFERENCES_KEY_REPLAY_GAIN); replayGainType = (ListPreference) this.findPreference(Constants.PREFERENCES_KEY_REPLAY_GAIN_TYPE); replayGainBump = this.findPreference(Constants.PREFERENCES_KEY_REPLAY_GAIN_BUMP); replayGainUntagged = this.findPreference(Constants.PREFERENCES_KEY_REPLAY_GAIN_UNTAGGED); cacheSize = (EditTextPreference) this.findPreference(Constants.PREFERENCES_KEY_CACHE_SIZE); settings = Util.getPreferences(context); serverCount = settings.getInt(Constants.PREFERENCES_KEY_SERVER_COUNT, 1); if (cacheSize != null) { this.findPreference("clearCache").setOnPreferenceClickListener(preference -> { Util.confirmDialog(context, (dialog, which) -> new LoadingTask(context, false) { @Override protected Void doInBackground() throws Throwable { FileUtil.deleteMusicDirectory(context); FileUtil.deleteSerializedCache(context); FileUtil.deleteArtworkCache(context); return null; } @Override protected void done(Void result) { Util.toast(context, R.string.settings_cache_clear_complete); } @Override protected void error(Throwable error) { Util.toast(context, getErrorMessage(error), false); } }.execute()); return false; }); } if (syncEnabled != null) { this.findPreference(Constants.PREFERENCES_KEY_SYNC_ENABLED).setOnPreferenceChangeListener((preference, newValue) -> { Boolean syncEnabled = (Boolean) newValue; Account account = new Account(Constants.SYNC_ACCOUNT_NAME, Constants.SYNC_ACCOUNT_TYPE); ContentResolver.setSyncAutomatically(account, Constants.SYNC_ACCOUNT_PLAYLIST_AUTHORITY, syncEnabled); return true; }); syncInterval.setOnPreferenceChangeListener((preference, newValue) -> { Integer syncInterval = Integer.parseInt(((String) newValue)); Account account = new Account(Constants.SYNC_ACCOUNT_NAME, Constants.SYNC_ACCOUNT_TYPE); ContentResolver.addPeriodicSync(account, Constants.SYNC_ACCOUNT_PLAYLIST_AUTHORITY, new Bundle(), 60L * syncInterval); return true; }); } if (serversCategory != null) { addServerPreference.setOnPreferenceClickListener(preference -> { serverCount++; int instance = serverCount; serversCategory.addPreference(addServer(serverCount)); SharedPreferences.Editor editor = settings.edit(); editor.putInt(Constants.PREFERENCES_KEY_SERVER_COUNT, serverCount); // Reset set folder ID editor.putString(Constants.PREFERENCES_KEY_MUSIC_FOLDER_ID + instance, null); editor.putString(Constants.PREFERENCES_KEY_SERVER_URL + instance, "http://yourhost"); editor.putString(Constants.PREFERENCES_KEY_SERVER_NAME + instance, getResources().getString(R.string.settings_server_unused)); editor.apply(); ServerSettings ss = new ServerSettings(instance); serverSettings.put(String.valueOf(instance), ss); ss.update(); return true; }); serversCategory.setOrderingAsAdded(false); for (int i = 1; i <= serverCount; i++) { serversCategory.addPreference(addServer(i)); serverSettings.put(String.valueOf(i), new ServerSettings(i)); } } SharedPreferences prefs = Util.getPreferences(context); prefs.registerOnSharedPreferenceChangeListener(this); update(); } private void scheduleBackup() { BackupManager backupManager = new BackupManager(context); backupManager.dataChanged(); } private void update() { if (testingConnection) { return; } if (theme != null) { theme.setSummary(theme.getEntry()); } if (cacheSize != null) { maxBitrateWifi.setSummary(maxBitrateWifi.getEntry()); maxBitrateMobile.setSummary(maxBitrateMobile.getEntry()); networkTimeout.setSummary(networkTimeout.getEntry()); cacheLocation.setSummary(cacheLocation.getText()); preloadCountWifi.setSummary(preloadCountWifi.getEntry()); preloadCountMobile.setSummary(preloadCountMobile.getEntry()); try { if (megabyteFromat == null) { megabyteFromat = new DecimalFormat(getResources().getString(R.string.util_bytes_format_megabyte)); } cacheSize.setSummary(megabyteFromat.format((double) Integer.parseInt(cacheSize.getText())).replace(".00", "")); } catch (Exception e) { Log.e(TAG, "Failed to format cache size", e); cacheSize.setSummary(cacheSize.getText()); } } if (keepPlayedCount != null) { keepPlayedCount.setSummary(keepPlayedCount.getEntry()); tempLoss.setSummary(tempLoss.getEntry()); pauseDisconnect.setSummary(pauseDisconnect.getEntry()); songPressAction.setSummary(songPressAction.getEntry()); if (replayGain.isChecked()) { replayGainType.setEnabled(true); replayGainBump.setEnabled(true); replayGainUntagged.setEnabled(true); } else { replayGainType.setEnabled(false); replayGainBump.setEnabled(false); replayGainUntagged.setEnabled(false); } replayGainType.setSummary(replayGainType.getEntry()); } if (syncEnabled != null) { syncInterval.setSummary(syncInterval.getEntry()); if (syncEnabled.isChecked()) { if (!syncInterval.isEnabled()) { syncInterval.setEnabled(true); syncWifi.setEnabled(true); syncNotification.setEnabled(true); syncMostRecent.setEnabled(true); } } else { if (syncInterval.isEnabled()) { syncInterval.setEnabled(false); syncWifi.setEnabled(false); syncNotification.setEnabled(false); syncMostRecent.setEnabled(false); } } } for (ServerSettings ss : serverSettings.values()) { ss.update(); } } private void checkForRemoved() { for (ServerSettings ss : serverSettings.values()) { if (!ss.update()) { serversCategory.removePreference(ss.getScreen()); serverCount--; } } } private PreferenceScreen addServer(final int instance) { final PreferenceScreen screen = this.getPreferenceManager().createPreferenceScreen(context); screen.setKey(Constants.PREFERENCES_KEY_SERVER_KEY + instance); screen.setOrder(instance); screen.setOnPreferenceClickListener(preference -> { SettingsFragment newFragment = new SettingsFragment(); Bundle args = new Bundle(); args.putInt(Constants.PREFERENCES_KEY_SERVER_INSTANCE, instance); newFragment.setArguments(args); replaceFragment(newFragment); return false; }); return screen; } private PreferenceScreen expandServer(final int instance) { final PreferenceScreen screen = this.getPreferenceManager().createPreferenceScreen(context); screen.setTitle(R.string.settings_server_unused); screen.setKey(Constants.PREFERENCES_KEY_SERVER_KEY + instance); final EditTextPreference serverNamePreference = new EditTextPreference(context); serverNamePreference.setKey(Constants.PREFERENCES_KEY_SERVER_NAME + instance); serverNamePreference.setDefaultValue(getResources().getString(R.string.settings_server_unused)); serverNamePreference.setTitle(R.string.settings_server_name); serverNamePreference.setDialogTitle(R.string.settings_server_name); if (serverNamePreference.getText() == null) { serverNamePreference.setText(getResources().getString(R.string.settings_server_unused)); } serverNamePreference.setSummary(serverNamePreference.getText()); final EditTextPreference serverUrlPreference = new EditTextPreference(context); serverUrlPreference.setKey(Constants.PREFERENCES_KEY_SERVER_URL + instance); serverUrlPreference.getEditText().setInputType(InputType.TYPE_TEXT_VARIATION_URI); serverUrlPreference.setDefaultValue("http://yourhost"); serverUrlPreference.setTitle(R.string.settings_server_address); serverUrlPreference.setDialogTitle(R.string.settings_server_address); if (serverUrlPreference.getText() == null) { serverUrlPreference.setText("http://yourhost"); } serverUrlPreference.setSummary(serverUrlPreference.getText()); screen.setSummary(serverUrlPreference.getText()); final EditTextPreference serverLocalNetworkSSIDPreference = new EditTextPreference(context) { @Override protected void onAddEditTextToDialogView(View dialogView, final EditText editText) { super.onAddEditTextToDialogView(dialogView, editText); ViewGroup root = (ViewGroup) ((ViewGroup) dialogView).getChildAt(0); Button defaultButton = new Button(getContext()); defaultButton.setText(internalSSIDDisplay); defaultButton.setOnClickListener(v -> editText.setText(internalSSID)); root.addView(defaultButton); } }; serverLocalNetworkSSIDPreference.setKey(Constants.PREFERENCES_KEY_SERVER_LOCAL_NETWORK_SSID + instance); serverLocalNetworkSSIDPreference.setTitle(R.string.settings_server_local_network_ssid); serverLocalNetworkSSIDPreference.setDialogTitle(R.string.settings_server_local_network_ssid); final EditTextPreference serverInternalUrlPreference = new EditTextPreference(context); serverInternalUrlPreference.setKey(Constants.PREFERENCES_KEY_SERVER_INTERNAL_URL + instance); serverInternalUrlPreference.getEditText().setInputType(InputType.TYPE_TEXT_VARIATION_URI); serverInternalUrlPreference.setDefaultValue(""); serverInternalUrlPreference.setTitle(R.string.settings_server_internal_address); serverInternalUrlPreference.setDialogTitle(R.string.settings_server_internal_address); serverInternalUrlPreference.setSummary(serverInternalUrlPreference.getText()); final EditTextPreference serverUsernamePreference = new EditTextPreference(context); serverUsernamePreference.setKey(Constants.PREFERENCES_KEY_USERNAME + instance); serverUsernamePreference.setTitle(R.string.settings_server_username); serverUsernamePreference.setDialogTitle(R.string.settings_server_username); final EditTextPreference serverPasswordPreference = new EditTextPreference(context); serverPasswordPreference.setKey(Constants.PREFERENCES_KEY_PASSWORD + instance); serverPasswordPreference.getEditText().setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD); serverPasswordPreference.setSummary("***"); serverPasswordPreference.setTitle(R.string.settings_server_password); final Preference serverOpenBrowser = new Preference(context); serverOpenBrowser.setKey(Constants.PREFERENCES_KEY_OPEN_BROWSER); serverOpenBrowser.setPersistent(false); serverOpenBrowser.setTitle(R.string.settings_server_open_browser); serverOpenBrowser.setOnPreferenceClickListener(preference -> { openInBrowser(instance); return true; }); Preference serverRemoveServerPreference = new Preference(context); serverRemoveServerPreference.setKey(Constants.PREFERENCES_KEY_SERVER_REMOVE + instance); serverRemoveServerPreference.setPersistent(false); serverRemoveServerPreference.setTitle(R.string.settings_servers_remove); serverRemoveServerPreference.setOnPreferenceClickListener(preference -> { Util.confirmDialog(context, R.string.common_delete, screen.getTitle().toString(), (dialog, which) -> { // Reset values to null so when we ask for them again they are new serverNamePreference.setText(null); serverUrlPreference.setText(null); serverUsernamePreference.setText(null); serverPasswordPreference.setText(null); // Don't use Util.getActiveServer since it is 0 if offline int activeServer = Util.getPreferences(context).getInt(Constants.PREFERENCES_KEY_SERVER_INSTANCE, 1); for (int i = instance; i <= serverCount; i++) { Util.removeInstanceName(context, i, activeServer); } serverCount--; SharedPreferences.Editor editor = settings.edit(); editor.putInt(Constants.PREFERENCES_KEY_SERVER_COUNT, serverCount); editor.apply(); removeCurrent(); SubsonicFragment parentFragment = context.getCurrentFragment(); if (parentFragment instanceof SettingsFragment) { SettingsFragment serverSelectionFragment = (SettingsFragment) parentFragment; serverSelectionFragment.checkForRemoved(); } }); return true; }); Preference serverTestConnectionPreference = new Preference(context); serverTestConnectionPreference.setKey(Constants.PREFERENCES_KEY_TEST_CONNECTION + instance); serverTestConnectionPreference.setPersistent(false); serverTestConnectionPreference.setTitle(R.string.settings_test_connection_title); serverTestConnectionPreference.setOnPreferenceClickListener(preference -> { testConnection(instance); return false; }); screen.addPreference(serverNamePreference); screen.addPreference(serverUrlPreference); screen.addPreference(serverInternalUrlPreference); screen.addPreference(serverLocalNetworkSSIDPreference); screen.addPreference(serverUsernamePreference); screen.addPreference(serverPasswordPreference); screen.addPreference(serverTestConnectionPreference); screen.addPreference(serverOpenBrowser); screen.addPreference(serverRemoveServerPreference); return screen; } private void setHideMedia(boolean hide) { File nomediaDir = new File(FileUtil.getSubsonicDirectory(context), ".nomedia"); File musicNoMedia = new File(FileUtil.getMusicDirectory(context), ".nomedia"); if (hide && !nomediaDir.exists()) { try { if (!nomediaDir.createNewFile()) { Log.w(TAG, "Failed to create " + nomediaDir); } } catch (Exception e) { Log.w(TAG, "Failed to create " + nomediaDir, e); } try { if (!musicNoMedia.createNewFile()) { Log.w(TAG, "Failed to create " + musicNoMedia); } } catch (Exception e) { Log.w(TAG, "Failed to create " + musicNoMedia, e); } } else if (!hide && nomediaDir.exists()) { if (!nomediaDir.delete()) { Log.w(TAG, "Failed to delete " + nomediaDir); } if (!musicNoMedia.delete()) { Log.w(TAG, "Failed to delete " + musicNoMedia); } } Util.toast(context, R.string.settings_hide_media_toast, false); } private void setMediaButtonsEnabled(boolean enabled) { if (enabled) { Util.registerMediaButtonEventReceiver(context); } else { Util.unregisterMediaButtonEventReceiver(context); } } private void setCacheLocation(String path) { File dir = new File(path); if (!FileUtil.verifyCanWrite(dir)) { Util.toast(context, R.string.settings_cache_location_error, false); // Reset it to the default. String defaultPath = FileUtil.getDefaultMusicDirectory(context).getPath(); if (!defaultPath.equals(path)) { SharedPreferences prefs = Util.getPreferences(context); SharedPreferences.Editor editor = prefs.edit(); editor.putString(Constants.PREFERENCES_KEY_CACHE_LOCATION, defaultPath); editor.apply(); if (cacheLocation != null) { cacheLocation.setSummary(defaultPath); cacheLocation.setText(defaultPath); } } // Clear download queue. DownloadService downloadService = DownloadService.getInstance(); downloadService.clear(); } } private void testConnection(final int instance) { LoadingTask task = new LoadingTask(context) { private int previousInstance; @Override protected Boolean doInBackground() throws Throwable { updateProgress(); previousInstance = Util.getActiveServer(context); testingConnection = true; MusicService musicService = MusicServiceFactory.getOnlineService(); try { musicService.setInstance(instance); musicService.ping(context, this); return true; } finally { musicService.setInstance(null); testingConnection = false; } } @Override protected void done(Boolean licenseValid) { Util.toast(context, R.string.settings_testing_ok); } @Override public void cancel() { super.cancel(); Util.setActiveServer(context, previousInstance); } @Override protected void error(Throwable error) { Log.w(TAG, error.toString(), error); new ErrorDialog(context, getResources().getString(R.string.settings_connection_failure) + " " + getErrorMessage(error), false); } }; task.execute(); } private void openInBrowser(final int instance) { SharedPreferences prefs = Util.getPreferences(context); String url = prefs.getString(Constants.PREFERENCES_KEY_SERVER_URL + instance, null); if (url == null) { new ErrorDialog(context, R.string.settings_invalid_url); return; } Uri uriServer = Uri.parse(url); Intent browserIntent = new Intent(Intent.ACTION_VIEW, uriServer); startActivity(browserIntent); } private class ServerSettings { private final int instance; private final EditTextPreference serverName; private final EditTextPreference serverUrl; private final EditTextPreference serverLocalNetworkSSID; private final EditTextPreference serverInternalUrl; private final EditTextPreference username; private final PreferenceScreen screen; private ServerSettings(int instance) { this.instance = instance; screen = (PreferenceScreen) SettingsFragment.this.findPreference(Constants.PREFERENCES_KEY_SERVER_KEY + instance); serverName = (EditTextPreference) SettingsFragment.this.findPreference(Constants.PREFERENCES_KEY_SERVER_NAME + instance); serverUrl = (EditTextPreference) SettingsFragment.this.findPreference(Constants.PREFERENCES_KEY_SERVER_URL + instance); serverLocalNetworkSSID = (EditTextPreference) SettingsFragment.this.findPreference(Constants.PREFERENCES_KEY_SERVER_LOCAL_NETWORK_SSID + instance); serverInternalUrl = (EditTextPreference) SettingsFragment.this.findPreference(Constants.PREFERENCES_KEY_SERVER_INTERNAL_URL + instance); username = (EditTextPreference) SettingsFragment.this.findPreference(Constants.PREFERENCES_KEY_USERNAME + instance); if (serverName != null) { serverUrl.setOnPreferenceChangeListener((preference, value) -> { try { String url = (String) value; new URL(url); if (url.contains(" ") || url.contains("@") || url.contains("_")) { throw new Exception(); } } catch (Exception x) { new ErrorDialog(context, R.string.settings_invalid_url); return false; } return true; }); serverInternalUrl.setOnPreferenceChangeListener((preference, value) -> { try { String url = (String) value; // Allow blank internal IP address if ("".equals(url) || url == null) { return true; } new URL(url); if (url.contains(" ") || url.contains("@") || url.contains("_")) { throw new Exception(); } } catch (Exception x) { new ErrorDialog(context, R.string.settings_invalid_url); return false; } return true; }); username.setOnPreferenceChangeListener((preference, value) -> { String username = (String) value; if (username == null || !username.equals(username.trim())) { new ErrorDialog(context, R.string.settings_invalid_username); return false; } return true; }); } } public PreferenceScreen getScreen() { return screen; } public boolean update() { SharedPreferences prefs = Util.getPreferences(context); if (prefs.contains(Constants.PREFERENCES_KEY_SERVER_NAME + instance)) { if (serverName != null) { serverName.setSummary(serverName.getText()); serverUrl.setSummary(serverUrl.getText()); serverLocalNetworkSSID.setSummary(serverLocalNetworkSSID.getText()); serverInternalUrl.setSummary(serverInternalUrl.getText()); username.setSummary(username.getText()); setTitle(serverName.getText()); } String title = prefs.getString(Constants.PREFERENCES_KEY_SERVER_NAME + instance, null); String summary = prefs.getString(Constants.PREFERENCES_KEY_SERVER_URL + instance, null); if (title != null) { screen.setTitle(title); } else { screen.setTitle(R.string.settings_server_unused); } if (summary != null) { screen.setSummary(summary); } return true; } else { return false; } } } }