diff options
Diffstat (limited to 'main/src/cgeo/geocaching/settings/SettingsActivity.java')
| -rw-r--r-- | main/src/cgeo/geocaching/settings/SettingsActivity.java | 549 |
1 files changed, 549 insertions, 0 deletions
diff --git a/main/src/cgeo/geocaching/settings/SettingsActivity.java b/main/src/cgeo/geocaching/settings/SettingsActivity.java new file mode 100644 index 0000000..4b1c92b --- /dev/null +++ b/main/src/cgeo/geocaching/settings/SettingsActivity.java @@ -0,0 +1,549 @@ +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.compatibility.Compatibility; +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.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.BaseAdapter; +import android.widget.EditText; +import android.widget.ListAdapter; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +/** + * 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. + * <p> + * See <a href="http://developer.android.com/design/patterns/settings.html"> Android Design: Settings</a> for design + * guidelines and the <a href="http://developer.android.com/guide/topics/ui/settings.html">Settings API Guide</a> for + * more information on developing a Settings UI. + * + * @author koem (initial author) + */ +public class SettingsActivity extends PreferenceActivity { + + private static final String INTENT_GOTO = "GOTO"; + private static final int INTENT_GOTO_SERVICES = 1; + + private static final int DIR_CHOOSER_MAPS_DIRECTORY_REQUEST = 4; + static final int OAUTH_OCDE_REQUEST = 5; + static final int OAUTH_TWITTER_REQUEST = 6; + + private EditText signatureText; + + /** + * Enumeration for directory 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; + + DirChooserType(final int requestCode, final int keyId, final String defaultValue) { + this.requestCode = requestCode; + this.keyId = keyId; + this.defaultValue = defaultValue; + } + } + + @Override + protected void onCreate(final Bundle savedInstanceState) { + setTheme(Settings.isLightSkin() ? R.style.settings_light : R.style.settings); + super.onCreate(savedInstanceState); + + SettingsActivity.addPreferencesFromResource(this, 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) getPreference(R.string.pref_fakekey_main_screen); + int index = getPreference(R.string.pref_fakekey_services_screen).getOrder(); + main.onItemClick(null, null, index, 0); + } + } + + @Override + protected void onPause() { + Compatibility.dataChanged(getPackageName()); + super.onPause(); + } + + private void initPreferences() { + initMapSourcePreference(); + initDirChoosers(); + initDefaultNavigationPreferences(); + initBackupButtons(); + initDbLocationPreference(); + initDebugPreference(); + initBasicMemberPreferences(); + initSend2CgeoPreferences(); + + for (int k : new int[] { R.string.pref_username, R.string.pref_password, + R.string.pref_pass_vote, R.string.pref_signature, + R.string.pref_mapsource, R.string.pref_renderthemepath, + R.string.pref_gpxExportDir, R.string.pref_gpxImportDir, + R.string.pref_mapDirectory, R.string.pref_defaultNavigationTool, + R.string.pref_defaultNavigationTool2, R.string.pref_webDeviceName, + R.string.pref_fakekey_preference_backup_info, }) { + bindSummaryToStringValue(k); + } + } + + private static String getKey(final int prefKeyId) { + return cgeoapplication.getInstance().getString(prefKeyId); + } + + private Preference getPreference(final int keyId) { + return SettingsActivity.findPreference(this, getKey(keyId)); + } + + // workaround, because OnContextItemSelected nor onMenuItemSelected is never called + OnMenuItemClickListener TEMPLATE_CLICK = new OnMenuItemClickListener() { + @Override + public boolean onMenuItemClick(final MenuItem item) { + LogTemplate template = LogTemplateProvider.getTemplate(item.getItemId()); + if (template != null) { + insertSignatureTemplate(template); + return true; + } + return false; + } + }; + + // workaround, because OnContextItemSelected and onMenuItemSelected are never called + void setSignatureTextView(final EditText view) { + this.signatureText = view; + } + + @Override + public void onCreateContextMenu(final ContextMenu menu, final View v, + final ContextMenuInfo menuInfo) { + // context menu for signature templates + if (v.getId() == R.id.signature_templates) { + menu.setHeaderTitle(R.string.init_signature_template_button); + ArrayList<LogTemplate> 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. + */ + private void initMapSourcePreference() { + ListPreference pref = (ListPreference) getPreference(R.string.pref_mapsource); + + List<MapSource> 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. + */ + private void initDefaultNavigationPreferences() { + + final List<NavigationAppsEnum> 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) getPreference(R.string.pref_defaultNavigationTool); + pref.setEntries(entries); + pref.setEntryValues(values); + pref = (ListPreference) getPreference(R.string.pref_defaultNavigationTool2); + pref.setEntries(entries); + pref.setEntryValues(values); + } + + private void initDirChoosers() { + for (final DirChooserType dct : DirChooserType.values()) { + + getPreference(dct.keyId).setOnPreferenceClickListener( + new OnPreferenceClickListener() { + @Override + public boolean onPreferenceClick(final Preference preference) { + startDirChooser(dct); + return false; + } + }); + } + + getPreference(R.string.pref_mapDirectory).setOnPreferenceClickListener( + new OnPreferenceClickListener() { + @Override + public boolean onPreferenceClick(final Preference preference) { + Intent i = new Intent(SettingsActivity.this, + SelectMapfileActivity.class); + startActivityForResult(i, DIR_CHOOSER_MAPS_DIRECTORY_REQUEST); + return false; + } + }); + } + + /** + * Fire up a directory chooser on click on the preference. + * + * @see #onActivityResult() for processing of the selected directory + * + * @param dct + * type of directory to be selected + */ + private void startDirChooser(final DirChooserType dct) { + + final String startDirectory = Settings.getString(dct.keyId, dct.defaultValue); + + 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); + } + } + + private void setChosenDirectory(final DirChooserType dct, final Intent data) { + final String directory = new File(data.getData().getPath()).getAbsolutePath(); + if (StringUtils.isNotBlank(directory)) { + Preference p = getPreference(dct.keyId); + if (p == null) { + return; + } + Settings.putString(dct.keyId, directory); + p.setSummary(directory); + } + } + + public void initBackupButtons() { + Preference backup = getPreference(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(SettingsActivity.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(SettingsActivity.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(SettingsActivity.this.getPreference(R.string.pref_fakekey_preference_backup_info), ""); + } + }); + } + }.start(); + return true; + } + }); + + Preference restore = getPreference(R.string.pref_fakekey_preference_restore); + restore.setOnPreferenceClickListener(new OnPreferenceClickListener() { + @Override + public boolean onPreferenceClick(final Preference preference) { + ((cgeoapplication) SettingsActivity.this.getApplication()) + .restoreDatabase(SettingsActivity.this); + return true; + } + }); + } + + private void initDbLocationPreference() { + Preference p = getPreference(R.string.pref_dbonsdcard); + p.setPersistent(false); + p.setOnPreferenceClickListener(new OnPreferenceClickListener() { + @Override + public boolean onPreferenceClick(final Preference preference) { + boolean oldValue = Settings.isDbOnSDCard(); + ((cgeoapplication) SettingsActivity.this.getApplication()) + .moveDatabase(SettingsActivity.this); + return oldValue != Settings.isDbOnSDCard(); + } + }); + } + + private void initDebugPreference() { + Preference p = getPreference(R.string.pref_debug); + p.setOnPreferenceChangeListener(new OnPreferenceChangeListener() { + @Override + public boolean onPreferenceChange(final Preference preference, final Object newValue) { + Log.setDebug((Boolean) newValue); + return true; + } + }); + } + + void initBasicMemberPreferences() { + getPreference(R.string.pref_fakekey_basicmembers_screen) + .setEnabled(!Settings.isPremiumMember()); + getPreference(R.string.pref_loaddirectionimg) + .setEnabled(!Settings.isPremiumMember()); + getPreference(R.string.pref_showcaptcha) + .setEnabled(!Settings.isPremiumMember()); + + redrawScreen(R.string.pref_fakekey_services_screen); + } + + void redrawScreen(int key) { + PreferenceScreen screen = (PreferenceScreen) getPreference(key); + if (screen == null) { + return; + } + ListAdapter adapter = screen.getRootAdapter(); + if (adapter instanceof BaseAdapter) { + ((BaseAdapter) adapter).notifyDataSetChanged(); + } + } + + private static void initSend2CgeoPreferences() { + Settings.putString(R.string.pref_webDeviceName, Settings.getWebDeviceName()); + } + + void setOCDEAuthTitle() { + getPreference(R.string.pref_fakekey_ocde_authorization) + .setTitle(getString(Settings.hasOCDEAuthorization() + ? R.string.init_reregister_oc_de + : R.string.init_register_oc_de)); + } + + void setTwitterAuthTitle() { + getPreference(R.string.pref_fakekey_twitter_authorization) + .setTitle(getString(Settings.hasTwitterAuthorization() + ? R.string.init_twitter_reauthorize + : R.string.init_twitter_authorize)); + } + + public static void jumpToServicesPage(final Context fromActivity) { + final Intent intent = new Intent(fromActivity, SettingsActivity.class); + intent.putExtra(INTENT_GOTO, INTENT_GOTO_SERVICES); + fromActivity.startActivity(intent); + } + + @Override + protected void onActivityResult(final int requestCode, final 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(); + getPreference(R.string.pref_mapDirectory).setSummary( + Settings.getMapFileDirectory()); + break; + case OAUTH_OCDE_REQUEST: + setOCDEAuthTitle(); + redrawScreen(R.string.pref_fakekey_services_screen); + break; + case OAUTH_TWITTER_REQUEST: + setTwitterAuthTitle(); + redrawScreen(R.string.pref_fakekey_services_screen); + break; + default: + throw new IllegalArgumentException(); + } + } + + /** + * A preference value change listener that updates the preference's summary + * to reflect its new value. + */ + private static final Preference.OnPreferenceChangeListener VALUE_CHANGE_LISTENER = new Preference.OnPreferenceChangeListener() { + @Override + public boolean onPreferenceChange(final Preference preference, final 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(final Preference preference, final 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 void bindSummaryToStringValue(final int key) { + + Preference pref = getPreference(key); + if (pref == null) { + return; + } + + String value = PreferenceManager + .getDefaultSharedPreferences(pref.getContext()) + .getString(pref.getKey(), ""); + + bindSummaryToValue(pref, value); + } + + @SuppressWarnings("deprecation") + public static Preference findPreference(final PreferenceActivity preferenceActivity, final CharSequence key) { + return preferenceActivity.findPreference(key); + } + + @SuppressWarnings("deprecation") + public static void addPreferencesFromResource(final PreferenceActivity preferenceActivity, final int preferencesResId) { + preferenceActivity.addPreferencesFromResource(preferencesResId); + } +} |
