package cgeo.geocaching.settings; import cgeo.geocaching.Intents; import cgeo.geocaching.R; import cgeo.geocaching.SelectMapfileActivity; import cgeo.geocaching.cgData; import cgeo.geocaching.cgeoapplication; import cgeo.geocaching.activity.ActivityMixin; import cgeo.geocaching.apps.cache.navi.NavigationAppFactory; import cgeo.geocaching.apps.cache.navi.NavigationAppFactory.NavigationAppsEnum; import cgeo.geocaching.files.SimpleDirChooser; import cgeo.geocaching.maps.MapProviderFactory; import cgeo.geocaching.maps.interfaces.MapSource; import cgeo.geocaching.ui.Formatter; import cgeo.geocaching.utils.Log; import cgeo.geocaching.utils.LogTemplateProvider; import cgeo.geocaching.utils.LogTemplateProvider.LogTemplate; import org.apache.commons.lang3.StringUtils; import org.openintents.intents.FileManagerIntents; import android.app.ProgressDialog; import android.content.Context; import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.os.Environment; import android.preference.EditTextPreference; import android.preference.ListPreference; import android.preference.Preference; import android.preference.Preference.OnPreferenceChangeListener; import android.preference.Preference.OnPreferenceClickListener; import android.preference.PreferenceActivity; import android.preference.PreferenceManager; import android.preference.PreferenceScreen; import android.view.ContextMenu; import android.view.ContextMenu.ContextMenuInfo; import android.view.MenuItem; import android.view.MenuItem.OnMenuItemClickListener; import android.view.View; import android.widget.EditText; import java.io.File; import java.util.ArrayList; import java.util.List; import java.util.Map; /** * A {@link PreferenceActivity} that presents a set of application settings. On * handset devices, settings are presented as a single list. On tablets, * settings are split by category, with category headers shown to the left of * the list of settings. *

* See Android Design: Settings for design * guidelines and the Settings API Guide for * more information on developing a Settings UI. * * @author koem (initial author) */ public class NewSettingsActivity extends PreferenceActivity { private static final String INTENT_GOTO = "GOTO"; private static final int INTENT_GOTO_SERVICES = 1; private EditText signatureText; /** * Enum for dir choosers. This is how we can retrieve information about the * directory and preference key in onActivityResult() easily just by knowing * the result code. */ private enum DirChooserType { GPX_IMPORT_DIR(1, R.string.pref_gpxImportDir, Environment.getExternalStorageDirectory().getPath() + "/gpx"), GPX_EXPORT_DIR(2, R.string.pref_gpxExportDir, Environment.getExternalStorageDirectory().getPath() + "/gpx"), THEMES_DIR(3, R.string.pref_renderthemepath, ""); public final int requestCode; public final int keyId; public final String defaultValue; private DirChooserType(int requestCode, int keyId, String defaultValue) { this.requestCode = requestCode; this.keyId = keyId; this.defaultValue = defaultValue; } } private final static int DIR_CHOOSER_MAPS_DIRECTORY_REQUEST = 4; @SuppressWarnings("deprecation") @Override protected void onCreate(Bundle savedInstanceState) { if (Settings.isLightSkin()) { setTheme(R.style.settings_light); } else { setTheme(R.style.settings); } super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.preferences); initPreferences(); Intent intent = getIntent(); int gotoPage = intent.getIntExtra(INTENT_GOTO, 0); if (gotoPage == INTENT_GOTO_SERVICES) { // start with services screen PreferenceScreen main = (PreferenceScreen) findPreference(getKey(R.string.pref_fakekey_main_screen)); int index = findPreference(getKey(R.string.pref_fakekey_services_screen)).getOrder(); main.onItemClick(null, null, index, 0); } } @SuppressWarnings("deprecation") private void initPreferences() { initMapSourcePreference(); initDirChoosers(); initDefaultNavigationPreferences(); initBackupButtons(); initDbLocationPreference(); initDebugPreference(); initBasicMemberPreferences(); initSend2CgeoPreferences(); Map prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()).getAll(); for (String key : prefs.keySet()) { Preference pref = findPreference(key); if (pref instanceof EditTextPreference || pref instanceof EditPasswordPreference) { bindSummaryToStringValue(pref); } else if (pref instanceof NumberPickerPreference) { bindSummaryToIntValue(pref); } } } private static String getKey(final int prefKeyId) { return cgeoapplication.getInstance().getString(prefKeyId); } // workaround, because OnContextItemSelected nor onMenuItemSelected is never called OnMenuItemClickListener TEMPLATE_CLICK = new OnMenuItemClickListener() { @Override public boolean onMenuItemClick(MenuItem item) { LogTemplate template = LogTemplateProvider.getTemplate(item.getItemId()); if (template != null) { insertSignatureTemplate(template); return true; } return false; } }; // workaround, because OnContextItemSelected nor onMenuItemSelected is never called void setSignatureTextView(EditText view) { this.signatureText = view; } @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { // context menu for signature templates if (v.getId() == R.id.signature_templates) { menu.setHeaderTitle(R.string.init_signature_template_button); ArrayList templates = LogTemplateProvider.getTemplates(); for (int i = 0; i < templates.size(); ++i) { menu.add(0, templates.get(i).getItemId(), 0, templates.get(i).getResourceId()); menu.getItem(i).setOnMenuItemClickListener(TEMPLATE_CLICK); } } super.onCreateContextMenu(menu, v, menuInfo); } private void insertSignatureTemplate(final LogTemplate template) { String insertText = "[" + template.getTemplateString() + "]"; ActivityMixin.insertAtPosition(signatureText, insertText, true); } /** * fill the choice list for map sources */ @SuppressWarnings("deprecation") private void initMapSourcePreference() { ListPreference pref = (ListPreference) findPreference(getKey(R.string.pref_mapsource)); List mapSources = MapProviderFactory.getMapSources(); CharSequence[] entries = new CharSequence[mapSources.size()]; CharSequence[] values = new CharSequence[mapSources.size()]; for (int i = 0; i < mapSources.size(); ++i) { entries[i] = mapSources.get(i).getName(); values[i] = String.valueOf(mapSources.get(i).getNumericalId()); } pref.setEntries(entries); pref.setEntryValues(values); } /** * fill the choice list for default navigation tools */ @SuppressWarnings("deprecation") private void initDefaultNavigationPreferences() { final List apps = NavigationAppFactory.getInstalledDefaultNavigationApps(); CharSequence[] entries = new CharSequence[apps.size()]; CharSequence[] values = new CharSequence[apps.size()]; for (int i = 0; i < apps.size(); ++i) { entries[i] = apps.get(i).toString(); values[i] = String.valueOf(apps.get(i).id); } ListPreference pref = (ListPreference) findPreference(getKey(R.string.pref_defaultNavigationTool)); pref.setEntries(entries); pref.setEntryValues(values); pref = (ListPreference) findPreference(getKey(R.string.pref_defaultNavigationTool2)); pref.setEntries(entries); pref.setEntryValues(values); } /** * fire up a dir chooser on click on the preference * * @see #onActivityResult() for processing of the selected directory * * @param key * key of the preference * @param defaultValue * default directory - in case the preference has never been * set yet */ @SuppressWarnings("deprecation") private void initDirChoosers() { for (final DirChooserType dct : DirChooserType.values()) { final String dir = Settings.getString(dct.keyId, dct.defaultValue); findPreference(getKey(dct.keyId)).setOnPreferenceClickListener( new OnPreferenceClickListener() { @Override public boolean onPreferenceClick(Preference preference) { startDirChooser(dct, dir); return false; } }); } findPreference(getKey(R.string.pref_mapDirectory)).setOnPreferenceClickListener( new OnPreferenceClickListener() { @Override public boolean onPreferenceClick(Preference preference) { Intent i = new Intent(NewSettingsActivity.this, SelectMapfileActivity.class); startActivityForResult(i, DIR_CHOOSER_MAPS_DIRECTORY_REQUEST); return false; } }); } private void startDirChooser(DirChooserType dct, String startDirectory) { try { final Intent dirChooser = new Intent(FileManagerIntents.ACTION_PICK_DIRECTORY); if (StringUtils.isNotBlank(startDirectory)) { dirChooser.setData(Uri.fromFile(new File(startDirectory))); } dirChooser.putExtra(FileManagerIntents.EXTRA_TITLE, getString(R.string.simple_dir_chooser_title)); dirChooser.putExtra(FileManagerIntents.EXTRA_BUTTON_TEXT, getString(android.R.string.ok)); startActivityForResult(dirChooser, dct.requestCode); } catch (android.content.ActivityNotFoundException ex) { // OI file manager not available final Intent dirChooser = new Intent(this, SimpleDirChooser.class); dirChooser.putExtra(Intents.EXTRA_START_DIR, startDirectory); startActivityForResult(dirChooser, dct.requestCode); } } @SuppressWarnings("deprecation") private void setChosenDirectory(DirChooserType dct, Intent data) { final String directory = new File(data.getData().getPath()).getAbsolutePath(); if (StringUtils.isNotBlank(directory)) { Preference p = findPreference(getKey(dct.keyId)); if (p == null) { return; } Settings.putString(dct.keyId, directory); p.setSummary(directory); } } @SuppressWarnings("deprecation") public void initBackupButtons() { Preference backup = findPreference(getKey(R.string.pref_fakekey_preference_backup)); backup.setOnPreferenceClickListener(new OnPreferenceClickListener() { @Override public boolean onPreferenceClick(final Preference preference) { final Context context = preference.getContext(); // avoid overwriting an existing backup with an empty database // (can happen directly after reinstalling the app) if (cgData.getAllCachesCount() == 0) { ActivityMixin.helpDialog(NewSettingsActivity.this, context.getString(R.string.init_backup), context.getString(R.string.init_backup_unnecessary)); return false; } final ProgressDialog dialog = ProgressDialog.show(context, context.getString(R.string.init_backup), context.getString(R.string.init_backup_running), true, false); new Thread() { @Override public void run() { final String backupFileName = cgData.backupDatabase(); runOnUiThread(new Runnable() { @Override public void run() { dialog.dismiss(); ActivityMixin.helpDialog(NewSettingsActivity.this, context.getString(R.string.init_backup_backup), backupFileName != null ? context.getString(R.string.init_backup_success) + "\n" + backupFileName : context.getString(R.string.init_backup_failed)); VALUE_CHANGE_LISTENER.onPreferenceChange(findPreference( getKey(R.string.pref_fakekey_preference_backup_info)), ""); } }); } }.start(); return true; } }); Preference restore = findPreference(getKey(R.string.pref_fakekey_preference_restore)); restore.setOnPreferenceClickListener(new OnPreferenceClickListener() { @Override public boolean onPreferenceClick(final Preference preference) { ((cgeoapplication) NewSettingsActivity.this.getApplication()) .restoreDatabase(NewSettingsActivity.this); return true; } }); } @SuppressWarnings("deprecation") private void initDbLocationPreference() { Preference p = findPreference(getKey(R.string.pref_dbonsdcard)); p.setPersistent(false); p.setOnPreferenceClickListener(new OnPreferenceClickListener() { @Override public boolean onPreferenceClick(Preference preference) { boolean oldValue = Settings.isDbOnSDCard(); ((cgeoapplication) NewSettingsActivity.this.getApplication()) .moveDatabase(NewSettingsActivity.this); return oldValue != Settings.isDbOnSDCard(); } }); } @SuppressWarnings("deprecation") private void initDebugPreference() { Preference p = findPreference(getKey(R.string.pref_debug)); p.setOnPreferenceChangeListener(new OnPreferenceChangeListener() { @Override public boolean onPreferenceChange(Preference preference, Object newValue) { Log.setDebug((Boolean) newValue); return true; } }); } @SuppressWarnings("deprecation") private void initBasicMemberPreferences() { findPreference(getKey(R.string.pref_loaddirectionimg)).setEnabled( !Settings.isPremiumMember()); findPreference(getKey(R.string.pref_showcaptcha)).setEnabled( !Settings.isPremiumMember()); } private static void initSend2CgeoPreferences() { Settings.putString(R.string.pref_webDeviceName, Settings.getWebDeviceName()); } public static void startWithServicesPage(Context fromActivity) { final Intent intent = new Intent(fromActivity, NewSettingsActivity.class); intent.putExtra(INTENT_GOTO, INTENT_GOTO_SERVICES); fromActivity.startActivity(intent); } @SuppressWarnings("deprecation") @Override protected void onActivityResult(int requestCode, int resultCode, final Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode != RESULT_OK) { return; } for (DirChooserType dct : DirChooserType.values()) { if (requestCode == dct.requestCode) { setChosenDirectory(dct, data); return; } } switch (requestCode) { case DIR_CHOOSER_MAPS_DIRECTORY_REQUEST: if (data.hasExtra(Intents.EXTRA_MAP_FILE)) { final String mapFile = data.getStringExtra(Intents.EXTRA_MAP_FILE); Settings.setMapFile(mapFile); if (!Settings.isValidMapFile(Settings.getMapFile())) { ActivityMixin.showToast(this, R.string.warn_invalid_mapfile); } } initMapSourcePreference(); findPreference(getKey(R.string.pref_mapDirectory)).setSummary( Settings.getMapFileDirectory()); break; default: throw new IllegalArgumentException(); } } /** * A preference value change listener that updates the preference's summary * to reflect its new value. */ private static Preference.OnPreferenceChangeListener VALUE_CHANGE_LISTENER = new Preference.OnPreferenceChangeListener() { @Override public boolean onPreferenceChange(Preference preference, Object value) { String stringValue = value.toString(); if (preference instanceof EditPasswordPreference) { if (StringUtils.isBlank((String) value)) { preference.setSummary(""); } else { preference.setSummary("\u2022 \u2022 \u2022 \u2022 \u2022 \u2022 \u2022 \u2022 \u2022 \u2022"); } } else if (preference instanceof ListPreference) { // For list preferences, look up the correct display value in // the preference's 'entries' list. ListPreference listPreference = (ListPreference) preference; int index = listPreference.findIndexOfValue(stringValue); // Set the summary to reflect the new value. preference.setSummary( index >= 0 ? listPreference.getEntries()[index] : null); } else if (getKey(R.string.pref_fakekey_preference_backup_info).equals(preference.getKey())) { File lastBackupFile = cgData.getRestoreFile(); String text; if (lastBackupFile != null) { text = preference.getContext().getString(R.string.init_backup_last) + " " + Formatter.formatTime(lastBackupFile.lastModified()) + ", " + Formatter.formatDate(lastBackupFile.lastModified()); } else { text = preference.getContext().getString(R.string.init_backup_last_no); } preference.setSummary(text); } else { // For all other preferences, set the summary to the value's // simple string representation. preference.setSummary(stringValue); } return true; } }; /** * Binds a preference's summary to its value. More specifically, when the * preference's value is changed, its summary (line of text below the * preference title) is updated to reflect the value. The summary is also * immediately updated upon calling this method. The exact display format is * dependent on the type of preference. * * @see #VALUE_CHANGE_LISTENER */ private static void bindSummaryToValue(Preference preference, Object value) { // Set the listener to watch for value changes. if (preference == null) { return; } preference.setOnPreferenceChangeListener(VALUE_CHANGE_LISTENER); // Trigger the listener immediately with the preference's // current value. VALUE_CHANGE_LISTENER.onPreferenceChange(preference, value); } /** * auto-care for the summary of the preference of string type with this key * * @param key */ private static void bindSummaryToStringValue(Preference pref) { if (pref == null) { return; } String value = PreferenceManager .getDefaultSharedPreferences(pref.getContext()) .getString(pref.getKey(), ""); bindSummaryToValue(pref, value); } /** * auto-care for the summary of the preference of int type with this key * * @param key */ private static void bindSummaryToIntValue(Preference pref) { if (pref == null) { return; } int value = PreferenceManager .getDefaultSharedPreferences(pref.getContext()) .getInt(pref.getKey(), 0); bindSummaryToValue(pref, value); } }