diff options
Diffstat (limited to 'main/src/cgeo/geocaching/settings')
12 files changed, 2258 insertions, 0 deletions
diff --git a/main/src/cgeo/geocaching/settings/AuthorizeOcDePreference.java b/main/src/cgeo/geocaching/settings/AuthorizeOcDePreference.java new file mode 100644 index 0000000..d6768b9 --- /dev/null +++ b/main/src/cgeo/geocaching/settings/AuthorizeOcDePreference.java @@ -0,0 +1,41 @@ +package cgeo.geocaching.settings; + +import cgeo.geocaching.connector.oc.OCAuthorizationActivity; + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.preference.Preference; +import android.util.AttributeSet; +import android.view.View; +import android.view.ViewGroup; + +public class AuthorizeOcDePreference extends Preference { + + public AuthorizeOcDePreference(Context context) { + super(context); + } + + public AuthorizeOcDePreference(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public AuthorizeOcDePreference(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + @Override + protected View onCreateView(ViewGroup parent) { + setOnPreferenceClickListener(new OnPreferenceClickListener() { + @Override + public boolean onPreferenceClick(Preference preference) { + Intent authIntent = new Intent(preference.getContext(), + OCAuthorizationActivity.class); + preference.getContext().startActivity(authIntent); + + return false; // no shared preference has to be changed + } + }); + return super.onCreateView(parent); + } +} diff --git a/main/src/cgeo/geocaching/settings/AuthorizeTwitterPreference.java b/main/src/cgeo/geocaching/settings/AuthorizeTwitterPreference.java new file mode 100644 index 0000000..cfccad3 --- /dev/null +++ b/main/src/cgeo/geocaching/settings/AuthorizeTwitterPreference.java @@ -0,0 +1,41 @@ +package cgeo.geocaching.settings; + +import cgeo.geocaching.twitter.TwitterAuthorizationActivity; + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.preference.Preference; +import android.util.AttributeSet; +import android.view.View; +import android.view.ViewGroup; + +public class AuthorizeTwitterPreference extends Preference { + + public AuthorizeTwitterPreference(Context context) { + super(context); + } + + public AuthorizeTwitterPreference(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public AuthorizeTwitterPreference(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + @Override + protected View onCreateView(ViewGroup parent) { + setOnPreferenceClickListener(new OnPreferenceClickListener() { + @Override + public boolean onPreferenceClick(Preference preference) { + Intent authIntent = new Intent(preference.getContext(), + TwitterAuthorizationActivity.class); + preference.getContext().startActivity(authIntent); + + return false; // no shared preference has to be changed + } + }); + return super.onCreateView(parent); + } +} diff --git a/main/src/cgeo/geocaching/settings/CheckBoxWithPopupPreference.java b/main/src/cgeo/geocaching/settings/CheckBoxWithPopupPreference.java new file mode 100644 index 0000000..4e64b9a --- /dev/null +++ b/main/src/cgeo/geocaching/settings/CheckBoxWithPopupPreference.java @@ -0,0 +1,93 @@ +package cgeo.geocaching.settings; + +import cgeo.geocaching.R; + +import android.app.AlertDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.res.TypedArray; +import android.net.Uri; +import android.preference.CheckBoxPreference; +import android.preference.Preference; +import android.util.AttributeSet; +import android.view.View; +import android.view.ViewGroup; + +public class CheckBoxWithPopupPreference extends CheckBoxPreference { + + // strings for the popup dialog + private String title; + private String text; + private String url; + private String urlButton; + + public CheckBoxWithPopupPreference(Context context) { + super(context); + } + + public CheckBoxWithPopupPreference(Context context, AttributeSet attrs) { + super(context, attrs); + processAttributes(context, attrs, 0); + } + + public CheckBoxWithPopupPreference(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + processAttributes(context, attrs, defStyle); + } + + private void processAttributes(Context context, AttributeSet attrs, int defStyle) { + if (attrs == null) { + return; // coward's retreat + } + + TypedArray types = context.obtainStyledAttributes(attrs, new int[] { + R.attr.title, R.attr.text, R.attr.url, R.attr.urlButton }, + defStyle, 0); + + title = types.getString(0); + text = types.getString(1); + url = types.getString(2); + urlButton = types.getString(3); + + types.recycle(); + } + + @Override + protected View onCreateView(ViewGroup parent) { + + // show dialog when checkbox enabled + setOnPreferenceChangeListener(new OnPreferenceChangeListener() { + @Override + public boolean onPreferenceChange(final Preference preference, Object newValue) { + if (!(Boolean) newValue) { + return true; + } + AlertDialog.Builder builder = new AlertDialog.Builder( + preference.getContext()); + builder.setMessage(text) + .setIcon(android.R.drawable.ic_dialog_info) + .setTitle(title) + .setPositiveButton(R.string.err_none, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int id) { + dialog.cancel(); + } + }) + .setNegativeButton(urlButton, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int id) { + Intent i = new Intent(Intent.ACTION_VIEW); + i.setData(Uri.parse(url)); + preference.getContext().startActivity(i); + } + }); + builder.create().show(); + return true; + } + }); + + return super.onCreateView(parent); + } + +} diff --git a/main/src/cgeo/geocaching/settings/CheckGcCredentialsPreference.java b/main/src/cgeo/geocaching/settings/CheckGcCredentialsPreference.java new file mode 100644 index 0000000..877a6c7 --- /dev/null +++ b/main/src/cgeo/geocaching/settings/CheckGcCredentialsPreference.java @@ -0,0 +1,123 @@ +package cgeo.geocaching.settings; + +import cgeo.geocaching.settings.Settings; +import cgeo.geocaching.R; +import cgeo.geocaching.activity.ActivityMixin; +import cgeo.geocaching.connector.gc.Login; +import cgeo.geocaching.enumerations.StatusCode; +import cgeo.geocaching.network.Cookies; +import cgeo.geocaching.utils.Log; + +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.ImmutablePair; + +import android.annotation.SuppressLint; +import android.app.Activity; +import android.app.ProgressDialog; +import android.content.Context; +import android.content.res.Resources; +import android.graphics.drawable.Drawable; +import android.os.Handler; +import android.os.Message; +import android.preference.Preference; +import android.util.AttributeSet; +import android.view.View; +import android.view.ViewGroup; + +public class CheckGcCredentialsPreference extends Preference { + + public CheckGcCredentialsPreference(Context context) { + super(context); + } + + public CheckGcCredentialsPreference(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public CheckGcCredentialsPreference(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + @Override + protected View onCreateView(ViewGroup parent) { + setOnPreferenceClickListener(GC_LOGIN_CHECK); + return super.onCreateView(parent); + } + + private final GcLoginCheck GC_LOGIN_CHECK = new GcLoginCheck(); + + private class GcLoginCheck implements OnPreferenceClickListener { + private Resources res; + private Activity activity; + + private ProgressDialog loginDialog; + @SuppressLint("HandlerLeak") + private Handler logInHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + try { + if (loginDialog != null && loginDialog.isShowing()) { + loginDialog.dismiss(); + } + + if (msg.obj == null || (msg.obj instanceof Drawable)) { + ActivityMixin.helpDialog(activity, + res.getString(R.string.init_login_popup), + res.getString(R.string.init_login_popup_ok), + (Drawable) msg.obj); + } else { + ActivityMixin.helpDialog(activity, + res.getString(R.string.init_login_popup), + res.getString(R.string.init_login_popup_failed_reason) + + " " + + ((StatusCode) msg.obj).getErrorString(res) + + "."); + } + } catch (Exception e) { + ActivityMixin.showToast(activity, R.string.err_login_failed); + Log.e("SettingsActivity.logInHandler", e); + } + + if (loginDialog != null && loginDialog.isShowing()) { + loginDialog.dismiss(); + } + } + }; + + @Override + public boolean onPreferenceClick(Preference preference) { + this.activity = (Activity) CheckGcCredentialsPreference.this.getContext(); + this.res = activity.getResources(); + + ImmutablePair<String, String> credentials = Settings.getGcLogin(); + + // check credentials for validity + if (credentials == null || StringUtils.isBlank(credentials.getLeft()) + || StringUtils.isBlank(credentials.getRight())) { + ActivityMixin.showToast(activity, R.string.err_missing_auth); + return false; + } + + loginDialog = ProgressDialog.show(activity, + res.getString(R.string.init_login_popup), + res.getString(R.string.init_login_popup_working), true); + loginDialog.setCancelable(false); + Cookies.clearCookies(); + + (new Thread() { + @Override + public void run() { + final StatusCode loginResult = Login.login(); + Object payload = loginResult; + if (loginResult == StatusCode.NO_ERROR) { + Login.detectGcCustomDate(); + payload = Login.downloadAvatarAndGetMemberStatus(); + } + logInHandler.obtainMessage(0, payload).sendToTarget(); + } + }).start(); + + return false; // no shared preference has to be changed + } + } +} diff --git a/main/src/cgeo/geocaching/settings/EditPasswordPreference.java b/main/src/cgeo/geocaching/settings/EditPasswordPreference.java new file mode 100644 index 0000000..d89f128 --- /dev/null +++ b/main/src/cgeo/geocaching/settings/EditPasswordPreference.java @@ -0,0 +1,29 @@ +package cgeo.geocaching.settings; + +import android.content.Context; +import android.preference.EditTextPreference; +import android.util.AttributeSet; + +/** + * This is just a dummy preference, to be able check for the type. + * <p> + * Use it exactly as an EditTextPreference + * + * @see SettingsActivity - search for EditPasswordPreference + * @author koem + */ +public class EditPasswordPreference extends EditTextPreference { + + public EditPasswordPreference(Context context) { + super(context); + } + + public EditPasswordPreference(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public EditPasswordPreference(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + +} diff --git a/main/src/cgeo/geocaching/settings/InfoPreference.java b/main/src/cgeo/geocaching/settings/InfoPreference.java new file mode 100644 index 0000000..465cf12 --- /dev/null +++ b/main/src/cgeo/geocaching/settings/InfoPreference.java @@ -0,0 +1,91 @@ +package cgeo.geocaching.settings; + +import cgeo.geocaching.R; + +import android.app.AlertDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.res.TypedArray; +import android.net.Uri; +import android.preference.Preference; +import android.util.AttributeSet; +import android.view.View; +import android.view.ViewGroup; + +public class InfoPreference extends Preference { + + // strings for the popup dialog + private String text; + private String url; + private String urlButton; + + public InfoPreference(Context context) { + super(context); + init(context, null, 0); + } + + public InfoPreference(Context context, AttributeSet attrs) { + super(context, attrs); + init(context, attrs, 0); + } + + public InfoPreference(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + init(context, attrs, defStyle); + } + + private void init(Context context, AttributeSet attrs, int defStyle) { + setPersistent(false); + + if (attrs == null) { + return; // coward's retreat + } + + TypedArray types = context.obtainStyledAttributes(attrs, new int[] { + android.R.attr.text, R.attr.url, R.attr.urlButton }, + defStyle, 0); + + text = types.getString(0); + url = types.getString(1); + urlButton = types.getString(2); + + types.recycle(); + } + + @Override + protected View onCreateView(ViewGroup parent) { + + // show popup when clicked + setOnPreferenceClickListener(new OnPreferenceClickListener() { + + @Override + public boolean onPreferenceClick(final Preference preference) { + AlertDialog.Builder builder = new AlertDialog.Builder( + preference.getContext()); + builder.setMessage(text) + .setIcon(android.R.drawable.ic_dialog_info) + .setTitle(preference.getTitle()) + .setPositiveButton(R.string.err_none, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int id) { + dialog.cancel(); + } + }) + .setNegativeButton(urlButton, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int id) { + Intent i = new Intent(Intent.ACTION_VIEW); + i.setData(Uri.parse(url)); + preference.getContext().startActivity(i); + } + }); + builder.create().show(); + return false; + } + }); + + return super.onCreateView(parent); + } + +} diff --git a/main/src/cgeo/geocaching/settings/LogSignaturePreference.java b/main/src/cgeo/geocaching/settings/LogSignaturePreference.java new file mode 100644 index 0000000..d0c9739 --- /dev/null +++ b/main/src/cgeo/geocaching/settings/LogSignaturePreference.java @@ -0,0 +1,60 @@ +package cgeo.geocaching.settings; + +import cgeo.geocaching.R; + +import android.content.Context; +import android.preference.DialogPreference; +import android.util.AttributeSet; +import android.view.View; +import android.widget.Button; +import android.widget.EditText; + +public class LogSignaturePreference extends DialogPreference { + + private SettingsActivity settingsActivity; + private EditText editText; + + public LogSignaturePreference(Context context, AttributeSet attrs) { + super(context, attrs); + init(); + } + + public LogSignaturePreference(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + init(); + } + + private void init() { + setDialogLayoutResource(R.layout.log_signature_preference_dialog); + } + + @Override + protected void onBindDialogView(View view) { + settingsActivity = (SettingsActivity) this.getContext(); + + editText = (EditText) view.findViewById(R.id.signature_dialog_text); + editText.setText(getPersistedString("")); + settingsActivity.setSignatureTextView(editText); + + Button templates = (Button) view.findViewById(R.id.signature_templates); + settingsActivity.registerForContextMenu(templates); + templates.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View templates) { + settingsActivity.openContextMenu(templates); + } + }); + + super.onBindDialogView(view); + } + + @Override + protected void onDialogClosed(boolean positiveResult) { + if (positiveResult) { + String text = editText.getText().toString(); + persistString(text); + callChangeListener(text); + } + super.onDialogClosed(positiveResult); + } +} diff --git a/main/src/cgeo/geocaching/settings/RegisterSend2CgeoPreference.java b/main/src/cgeo/geocaching/settings/RegisterSend2CgeoPreference.java new file mode 100644 index 0000000..a019c4a --- /dev/null +++ b/main/src/cgeo/geocaching/settings/RegisterSend2CgeoPreference.java @@ -0,0 +1,122 @@ +package cgeo.geocaching.settings; + +import cgeo.geocaching.R; +import cgeo.geocaching.activity.ActivityMixin; +import cgeo.geocaching.network.Network; +import cgeo.geocaching.network.Parameters; +import cgeo.geocaching.utils.Log; + +import ch.boye.httpclientandroidlib.HttpResponse; + +import org.apache.commons.lang3.StringUtils; + +import android.app.ProgressDialog; +import android.content.Context; +import android.os.Handler; +import android.os.Message; +import android.preference.Preference; +import android.util.AttributeSet; +import android.view.View; +import android.view.ViewGroup; + +public class RegisterSend2CgeoPreference extends Preference { + + ProgressDialog progressDialog; + SettingsActivity activity; + + public RegisterSend2CgeoPreference(Context context) { + super(context); + } + + public RegisterSend2CgeoPreference(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public RegisterSend2CgeoPreference(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + private Handler webAuthHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + try { + if (progressDialog != null && progressDialog.isShowing()) { + progressDialog.dismiss(); + } + + if (msg.what > 0) { + ActivityMixin.helpDialog(activity, + activity.getString(R.string.init_sendToCgeo), + activity.getString(R.string.init_sendToCgeo_register_ok) + .replace("####", String.valueOf(msg.what))); + } else { + ActivityMixin.helpDialog(activity, + activity.getString(R.string.init_sendToCgeo), + activity.getString(R.string.init_sendToCgeo_register_fail)); + } + } catch (Exception e) { + ActivityMixin.showToast(activity, R.string.init_sendToCgeo_register_fail); + Log.e("SettingsActivity.webHandler", e); + } + + if (progressDialog != null && progressDialog.isShowing()) { + progressDialog.dismiss(); + } + } + }; + + @Override + protected View onCreateView(ViewGroup parent) { + activity = (SettingsActivity) getContext(); + + setOnPreferenceClickListener(new OnPreferenceClickListener() { + @Override + public boolean onPreferenceClick(Preference preference) { + final String deviceName = Settings.getWebDeviceName(); + final String deviceCode = Settings.getWebDeviceCode(); + + if (StringUtils.isBlank(deviceName)) { + ActivityMixin.showToast(activity, R.string.err_missing_device_name); + return false; + } + + progressDialog = ProgressDialog.show(activity, + activity.getString(R.string.init_sendToCgeo), + activity.getString(R.string.init_sendToCgeo_registering), true); + progressDialog.setCancelable(false); + + (new Thread() { + + @Override + public void run() { + int pin = 0; + + final String nam = StringUtils.defaultString(deviceName); + final String cod = StringUtils.defaultString(deviceCode); + + final Parameters params = new Parameters("name", nam, "code", cod); + HttpResponse response = Network.getRequest("http://send2.cgeo.org/auth.html", params); + + if (response != null && response.getStatusLine().getStatusCode() == 200) { + //response was OK + String[] strings = Network.getResponseData(response).split(","); + try { + pin = Integer.parseInt(strings[1].trim()); + } catch (Exception e) { + Log.e("webDialog", e); + } + String code = strings[0]; + Settings.setWebNameCode(nam, code); + } + + webAuthHandler.sendEmptyMessage(pin); + } + }).start(); + + return true; + } + }); + return super.onCreateView(parent); + } + +} diff --git a/main/src/cgeo/geocaching/settings/Settings.java b/main/src/cgeo/geocaching/settings/Settings.java new file mode 100644 index 0000000..08f30af --- /dev/null +++ b/main/src/cgeo/geocaching/settings/Settings.java @@ -0,0 +1,967 @@ +package cgeo.geocaching.settings; + +import cgeo.geocaching.R; +import cgeo.geocaching.StoredList; +import cgeo.geocaching.cgeoapplication; +import cgeo.geocaching.apps.cache.navi.NavigationAppFactory.NavigationAppsEnum; +import cgeo.geocaching.connector.gc.GCConstants; +import cgeo.geocaching.connector.gc.Login; +import cgeo.geocaching.enumerations.CacheType; +import cgeo.geocaching.enumerations.LiveMapStrategy.Strategy; +import cgeo.geocaching.enumerations.LogType; +import cgeo.geocaching.geopoint.Geopoint; +import cgeo.geocaching.maps.MapProviderFactory; +import cgeo.geocaching.maps.google.GoogleMapProvider; +import cgeo.geocaching.maps.interfaces.GeoPointImpl; +import cgeo.geocaching.maps.interfaces.MapProvider; +import cgeo.geocaching.maps.interfaces.MapSource; +import cgeo.geocaching.maps.mapsforge.MapsforgeMapProvider; +import cgeo.geocaching.maps.mapsforge.MapsforgeMapProvider.OfflineMapSource; +import cgeo.geocaching.utils.CryptUtils; +import cgeo.geocaching.utils.FileUtils; +import cgeo.geocaching.utils.FileUtils.FileSelector; +import cgeo.geocaching.utils.Log; + +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.ImmutablePair; + +import android.content.Context; +import android.content.SharedPreferences; +import android.content.SharedPreferences.Editor; +import android.content.res.Configuration; +import android.content.res.Resources; +import android.os.Environment; +import android.preference.PreferenceManager; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; + +/** + * General c:geo preferences/settings set by the user + */ +public final class Settings { + + public static final int SHOW_WP_THRESHOLD_DEFAULT = 5; + public static final int SHOW_WP_THRESHOLD_MAX = 50; + private static final int MAP_SOURCE_DEFAULT = GoogleMapProvider.GOOGLE_MAP_ID.hashCode(); + + private final static int unitsMetric = 1; + + // twitter api keys + private final static String keyConsumerPublic = CryptUtils.rot13("ESnsCvAv3kEupF1GCR3jGj"); + private final static String keyConsumerSecret = CryptUtils.rot13("7vQWceACV9umEjJucmlpFe9FCMZSeqIqfkQ2BnhV9x"); + + public enum coordInputFormatEnum { + Plain, + Deg, + Min, + Sec; + + public static coordInputFormatEnum fromInt(int id) { + final coordInputFormatEnum[] values = coordInputFormatEnum.values(); + if (id < 0 || id >= values.length) { + return Min; + } + return values[id]; + } + } + + private static final SharedPreferences sharedPrefs = PreferenceManager + .getDefaultSharedPreferences(cgeoapplication.getInstance().getBaseContext()); + static { + migrateSettings(); + Log.setDebug(sharedPrefs.getBoolean(getKey(R.string.pref_debug), false)); + } + + // maps + private static MapProvider mapProvider = null; + + private Settings() { + // this class is not to be instantiated; + } + + private static void migrateSettings() { + // migrate from non standard file location and integer based boolean types + int oldVersion = getInt(R.string.pref_settingsversion, 0); + if (oldVersion < 1) { + final String oldPreferencesName = "cgeo.pref"; + final SharedPreferences old = cgeoapplication.getInstance().getSharedPreferences(oldPreferencesName, Context.MODE_PRIVATE); + final Editor e = sharedPrefs.edit(); + + e.putString(getKey(R.string.pref_temp_twitter_token_secret), old.getString(getKey(R.string.pref_temp_twitter_token_secret), null)); + e.putString(getKey(R.string.pref_temp_twitter_token_public), old.getString(getKey(R.string.pref_temp_twitter_token_public), null)); + e.putBoolean(getKey(R.string.pref_help_shown), old.getInt(getKey(R.string.pref_help_shown), 0) != 0); + e.putFloat(getKey(R.string.pref_anylongitude), old.getFloat(getKey(R.string.pref_anylongitude), 0)); + e.putFloat(getKey(R.string.pref_anylatitude), old.getFloat(getKey(R.string.pref_anylatitude), 0)); + e.putBoolean(getKey(R.string.pref_offlinemaps), 0 != old.getInt(getKey(R.string.pref_offlinemaps), 1)); + e.putBoolean(getKey(R.string.pref_offlinewpmaps), 0 != old.getInt(getKey(R.string.pref_offlinewpmaps), 0)); + e.putString(getKey(R.string.pref_webDeviceCode), old.getString(getKey(R.string.pref_webDeviceCode), null)); + e.putString(getKey(R.string.pref_webDeviceName), old.getString(getKey(R.string.pref_webDeviceName), null)); + e.putBoolean(getKey(R.string.pref_maplive), old.getInt(getKey(R.string.pref_maplive), 1) != 0); + e.putInt(getKey(R.string.pref_mapsource), old.getInt(getKey(R.string.pref_mapsource), MAP_SOURCE_DEFAULT)); + e.putBoolean(getKey(R.string.pref_twitter), 0 != old.getInt(getKey(R.string.pref_twitter), 0)); + e.putBoolean(getKey(R.string.pref_showaddress), 0 != old.getInt(getKey(R.string.pref_showaddress), 1)); + e.putBoolean(getKey(R.string.pref_showcaptcha), old.getBoolean(getKey(R.string.pref_showcaptcha), false)); + e.putBoolean(getKey(R.string.pref_maptrail), old.getInt(getKey(R.string.pref_maptrail), 1) != 0); + e.putInt(getKey(R.string.pref_lastmapzoom), old.getInt(getKey(R.string.pref_lastmapzoom), 14)); + e.putBoolean(getKey(R.string.pref_livelist), 0 != old.getInt(getKey(R.string.pref_livelist), 1)); + e.putBoolean(getKey(R.string.pref_units), old.getInt(getKey(R.string.pref_units), unitsMetric) == unitsMetric); + e.putBoolean(getKey(R.string.pref_skin), old.getInt(getKey(R.string.pref_skin), 0) != 0); + e.putInt(getKey(R.string.pref_lastusedlist), old.getInt(getKey(R.string.pref_lastusedlist), StoredList.STANDARD_LIST_ID)); + e.putString(getKey(R.string.pref_cachetype), old.getString(getKey(R.string.pref_cachetype), CacheType.ALL.id)); + e.putString(getKey(R.string.pref_twitter_token_secret), old.getString(getKey(R.string.pref_twitter_token_secret), null)); + e.putString(getKey(R.string.pref_twitter_token_public), old.getString(getKey(R.string.pref_twitter_token_public), null)); + e.putInt(getKey(R.string.pref_version), old.getInt(getKey(R.string.pref_version), 0)); + e.putBoolean(getKey(R.string.pref_autoloaddesc), 0 != old.getInt(getKey(R.string.pref_autoloaddesc), 1)); + e.putBoolean(getKey(R.string.pref_ratingwanted), old.getBoolean(getKey(R.string.pref_ratingwanted), true)); + e.putBoolean(getKey(R.string.pref_friendlogswanted), old.getBoolean(getKey(R.string.pref_friendlogswanted), true)); + e.putBoolean(getKey(R.string.pref_useenglish), old.getBoolean(getKey(R.string.pref_useenglish), false)); + e.putBoolean(getKey(R.string.pref_usecompass), 0 != old.getInt(getKey(R.string.pref_usecompass), 1)); + e.putBoolean(getKey(R.string.pref_trackautovisit), old.getBoolean(getKey(R.string.pref_trackautovisit), false)); + e.putBoolean(getKey(R.string.pref_sigautoinsert), old.getBoolean(getKey(R.string.pref_sigautoinsert), false)); + e.putBoolean(getKey(R.string.pref_logimages), old.getBoolean(getKey(R.string.pref_logimages), false)); + e.putBoolean(getKey(R.string.pref_excludedisabled), 0 != old.getInt(getKey(R.string.pref_excludedisabled), 0)); + e.putBoolean(getKey(R.string.pref_excludemine), 0 != old.getInt(getKey(R.string.pref_excludemine), 0)); + e.putString(getKey(R.string.pref_mapfile), old.getString(getKey(R.string.pref_mapfile), null)); + e.putString(getKey(R.string.pref_signature), old.getString(getKey(R.string.pref_signature), null)); + e.putString(getKey(R.string.pref_pass_vote), old.getString(getKey(R.string.pref_pass_vote), null)); + e.putString(getKey(R.string.pref_password), old.getString(getKey(R.string.pref_password), null)); + e.putString(getKey(R.string.pref_username), old.getString(getKey(R.string.pref_username), null)); + e.putString(getKey(R.string.pref_memberstatus), old.getString(getKey(R.string.pref_memberstatus), "")); + e.putInt(getKey(R.string.pref_coordinputformat), old.getInt(getKey(R.string.pref_coordinputformat), 0)); + e.putBoolean(getKey(R.string.pref_log_offline), old.getBoolean(getKey(R.string.pref_log_offline), false)); + e.putBoolean(getKey(R.string.pref_choose_list), old.getBoolean(getKey(R.string.pref_choose_list), false)); + e.putBoolean(getKey(R.string.pref_loaddirectionimg), old.getBoolean(getKey(R.string.pref_loaddirectionimg), true)); + e.putString(getKey(R.string.pref_gccustomdate), old.getString(getKey(R.string.pref_gccustomdate), null)); + e.putInt(getKey(R.string.pref_gcshowwaypointsthreshold), old.getInt(getKey(R.string.pref_gcshowwaypointsthreshold), 0)); + e.putString(getKey(R.string.pref_cookiestore), old.getString(getKey(R.string.pref_cookiestore), null)); + e.putBoolean(getKey(R.string.pref_opendetailslastpage), old.getBoolean(getKey(R.string.pref_opendetailslastpage), false)); + e.putInt(getKey(R.string.pref_lastdetailspage), old.getInt(getKey(R.string.pref_lastdetailspage), 1)); + e.putInt(getKey(R.string.pref_defaultNavigationTool), old.getInt(getKey(R.string.pref_defaultNavigationTool), NavigationAppsEnum.COMPASS.id)); + e.putInt(getKey(R.string.pref_defaultNavigationTool2), old.getInt(getKey(R.string.pref_defaultNavigationTool2), NavigationAppsEnum.INTERNAL_MAP.id)); + e.putInt(getKey(R.string.pref_livemapstrategy), old.getInt(getKey(R.string.pref_livemapstrategy), Strategy.AUTO.id)); + e.putBoolean(getKey(R.string.pref_debug), old.getBoolean(getKey(R.string.pref_debug), false)); + e.putBoolean(getKey(R.string.pref_hidelivemaphint), old.getInt(getKey(R.string.pref_hidelivemaphint), 0) != 0); + e.putInt(getKey(R.string.pref_livemaphintshowcount), old.getInt(getKey(R.string.pref_livemaphintshowcount), 0)); + + e.putInt(getKey(R.string.pref_settingsversion), 1); // mark migrated + e.commit(); + } + + // changes for new settings dialog + if (oldVersion < 2) { + final Editor e = sharedPrefs.edit(); + + e.putBoolean(getKey(R.string.pref_units), !isUseImperialUnits()); + + // show waypoints threshold now as a slider + int wpThreshold = getWayPointsThreshold(); + if (wpThreshold < 0) { + wpThreshold = 0; + } else if (wpThreshold > SHOW_WP_THRESHOLD_MAX) { + wpThreshold = SHOW_WP_THRESHOLD_MAX; + } + e.putInt(getKey(R.string.pref_gcshowwaypointsthreshold), wpThreshold); + + // KEY_MAP_SOURCE must be string, because it is the key for a ListPreference now + int ms = sharedPrefs.getInt(getKey(R.string.pref_mapsource), MAP_SOURCE_DEFAULT); + e.remove(getKey(R.string.pref_mapsource)); + e.putString(getKey(R.string.pref_mapsource), String.valueOf(ms)); + + // navigation tool ids must be string, because ListPreference uses strings as keys + int dnt1 = sharedPrefs.getInt(getKey(R.string.pref_defaultNavigationTool), NavigationAppsEnum.COMPASS.id); + int dnt2 = sharedPrefs.getInt(getKey(R.string.pref_defaultNavigationTool2), NavigationAppsEnum.INTERNAL_MAP.id); + e.remove(getKey(R.string.pref_defaultNavigationTool)); + e.remove(getKey(R.string.pref_defaultNavigationTool2)); + e.putString(getKey(R.string.pref_defaultNavigationTool), String.valueOf(dnt1)); + e.putString(getKey(R.string.pref_defaultNavigationTool2), String.valueOf(dnt2)); + + // defaults for gpx directories + e.putString(getKey(R.string.pref_gpxImportDir), getGpxImportDir()); + e.putString(getKey(R.string.pref_gpxExportDir), getGpxExportDir()); + + e.putInt(getKey(R.string.pref_settingsversion), 2); // mark migrated + e.commit(); + } + } + + private static String getKey(final int prefKeyId) { + return cgeoapplication.getInstance().getString(prefKeyId); + } + + static String getString(final int prefKeyId, final String defaultValue) { + return sharedPrefs.getString(getKey(prefKeyId), defaultValue); + } + + private static int getInt(final int prefKeyId, final int defaultValue) { + return sharedPrefs.getInt(getKey(prefKeyId), defaultValue); + } + + private static boolean getBoolean(final int prefKeyId, final boolean defaultValue) { + return sharedPrefs.getBoolean(getKey(prefKeyId), defaultValue); + } + + private static float getFloat(final int prefKeyId, final float defaultValue) { + return sharedPrefs.getFloat(getKey(prefKeyId), defaultValue); + } + + static boolean putString(final int prefKeyId, final String value) { + final SharedPreferences.Editor edit = sharedPrefs.edit(); + edit.putString(getKey(prefKeyId), value); + return edit.commit(); + } + + private static boolean putBoolean(final int prefKeyId, final boolean value) { + final SharedPreferences.Editor edit = sharedPrefs.edit(); + edit.putBoolean(getKey(prefKeyId), value); + return edit.commit(); + } + + private static boolean putInt(final int prefKeyId, final int value) { + final SharedPreferences.Editor edit = sharedPrefs.edit(); + edit.putInt(getKey(prefKeyId), value); + return edit.commit(); + } + + private static boolean putFloat(final int prefKeyId, final float value) { + final SharedPreferences.Editor edit = sharedPrefs.edit(); + edit.putFloat(getKey(prefKeyId), value); + return edit.commit(); + } + + private static boolean remove(final int prefKeyId) { + final SharedPreferences.Editor edit = sharedPrefs.edit(); + edit.remove(getKey(prefKeyId)); + return edit.commit(); + } + + private static boolean contains(final int prefKeyId) { + return sharedPrefs.contains(getKey(prefKeyId)); + } + + public static void setLanguage(boolean useEnglish) { + final Configuration config = new Configuration(); + config.locale = useEnglish ? Locale.ENGLISH : Locale.getDefault(); + final Resources resources = cgeoapplication.getInstance().getResources(); + resources.updateConfiguration(config, resources.getDisplayMetrics()); + } + + public static boolean isLogin() { + final String preUsername = getString(R.string.pref_username, null); + final String prePassword = getString(R.string.pref_password, null); + + return !StringUtils.isBlank(preUsername) && !StringUtils.isBlank(prePassword); + } + + /** + * Get login and password information. + * + * @return a pair (login, password) or null if no valid information is stored + */ + public static ImmutablePair<String, String> getGcLogin() { + + final String username = getString(R.string.pref_username, null); + final String password = getString(R.string.pref_password, null); + + if (StringUtils.isBlank(username) || StringUtils.isBlank(password)) { + return null; + } + + return new ImmutablePair<String, String>(username, password); + } + + public static String getUsername() { + return getString(R.string.pref_username, null); + } + + public static boolean isGCConnectorActive() { + return getBoolean(R.string.pref_connectorGCActive, true); + } + + public static boolean isPremiumMember() { + // Basic Member, Premium Member, ??? + String memberStatus = Settings.getMemberStatus(); + if (memberStatus == null) { + return false; + } + return GCConstants.MEMBER_STATUS_PM.equalsIgnoreCase(memberStatus); + } + + public static String getMemberStatus() { + return getString(R.string.pref_memberstatus, ""); + } + + public static boolean setMemberStatus(final String memberStatus) { + if (StringUtils.isBlank(memberStatus)) { + return remove(R.string.pref_memberstatus); + } + return putString(R.string.pref_memberstatus, memberStatus); + } + + public static boolean isOCConnectorActive() { + return getBoolean(R.string.pref_connectorOCActive, false); + } + + public static boolean setOCConnectorActive(final boolean isActive) { + return putBoolean(R.string.pref_connectorOCActive, isActive); + } + + public static String getOCDETokenPublic() { + return getString(R.string.pref_ocde_tokenpublic, ""); + } + + public static String getOCDETokenSecret() { + return getString(R.string.pref_ocde_tokensecret, ""); + } + + public static void setOCDETokens(final String tokenPublic, + final String tokenSecret, boolean enableOcDe) { + putString(R.string.pref_ocde_tokenpublic, tokenPublic); + putString(R.string.pref_ocde_tokensecret, tokenSecret); + if (tokenPublic != null) { + remove(R.string.pref_temp_ocde_token_public); + remove(R.string.pref_temp_ocde_token_secret); + } + setOCConnectorActive(enableOcDe); + } + + public static void setOCDETempTokens(final String tokenPublic, final String tokenSecret) { + putString(R.string.pref_temp_ocde_token_public, tokenPublic); + putString(R.string.pref_temp_ocde_token_secret, tokenSecret); + } + + public static ImmutablePair<String, String> getTempOCDEToken() { + String tokenPublic = getString(R.string.pref_temp_ocde_token_public, null); + String tokenSecret = getString(R.string.pref_temp_ocde_token_secret, null); + return new ImmutablePair<String, String>(tokenPublic, tokenSecret); + } + + public static boolean isGCvoteLogin() { + final String preUsername = getString(R.string.pref_username, null); + final String prePassword = getString(R.string.pref_pass_vote, null); + + return !StringUtils.isBlank(preUsername) && !StringUtils.isBlank(prePassword); + } + + public static ImmutablePair<String, String> getGCvoteLogin() { + final String username = getString(R.string.pref_username, null); + final String password = getString(R.string.pref_pass_vote, null); + + if (StringUtils.isBlank(username) || StringUtils.isBlank(password)) { + return null; + } + + return new ImmutablePair<String, String>(username, password); + } + + public static String getSignature() { + return getString(R.string.pref_signature, null); + } + + public static boolean setCookieStore(final String cookies) { + if (StringUtils.isBlank(cookies)) { + // erase cookies + return remove(R.string.pref_cookiestore); + } + // save cookies + return putString(R.string.pref_cookiestore, cookies); + } + + public static String getCookieStore() { + return getString(R.string.pref_cookiestore, null); + } + + /** + * @param cacheType + * The cache type used for future filtering + */ + public static void setCacheType(final CacheType cacheType) { + if (cacheType == null) { + remove(R.string.pref_cachetype); + } else { + putString(R.string.pref_cachetype, cacheType.id); + } + } + + public static int getLastList() { + return getInt(R.string.pref_lastusedlist, StoredList.STANDARD_LIST_ID); + } + + public static void saveLastList(final int listId) { + putInt(R.string.pref_lastusedlist, listId); + } + + public static void setWebNameCode(final String name, final String code) { + putString(R.string.pref_webDeviceName, name); + putString(R.string.pref_webDeviceCode, code); + } + + public static MapProvider getMapProvider() { + if (mapProvider == null) { + mapProvider = getMapSource().getMapProvider(); + } + return mapProvider; + } + + public static String getMapFile() { + return getString(R.string.pref_mapfile, null); + } + + public static boolean setMapFile(final String mapFile) { + boolean result = putString(R.string.pref_mapfile, mapFile); + if (mapFile != null) { + setMapFileDirectory(new File(mapFile).getParent()); + } + return result; + } + + public static String getMapFileDirectory() { + final String mapDir = getString(R.string.pref_mapDirectory, null); + if (mapDir != null) { + return mapDir; + } + final String mapFile = getMapFile(); + if (mapFile != null) { + return new File(mapFile).getParent(); + } + return null; + } + + public static boolean setMapFileDirectory(final String mapFileDirectory) { + boolean result = putString(R.string.pref_mapDirectory, mapFileDirectory); + MapsforgeMapProvider.getInstance().updateOfflineMaps(); + return result; + } + + public static boolean isValidMapFile() { + return isValidMapFile(getMapFile()); + } + + public static boolean isValidMapFile(final String mapFileIn) { + return MapsforgeMapProvider.isValidMapFile(mapFileIn); + } + + public static coordInputFormatEnum getCoordInputFormat() { + return coordInputFormatEnum.fromInt(getInt(R.string.pref_coordinputformat, 0)); + } + + public static void setCoordInputFormat(final coordInputFormatEnum format) { + putInt(R.string.pref_coordinputformat, format.ordinal()); + } + + static void setLogOffline(final boolean offline) { + putBoolean(R.string.pref_log_offline, offline); + } + + public static boolean getLogOffline() { + return getBoolean(R.string.pref_log_offline, false); + } + + public static boolean getChooseList() { + return getBoolean(R.string.pref_choose_list, false); + } + + public static boolean getLoadDirImg() { + return !isPremiumMember() && getBoolean(R.string.pref_loaddirectionimg, true); + } + + public static void setGcCustomDate(final String format) { + putString(R.string.pref_gccustomdate, format); + } + + /** + * @return User selected date format on GC.com + * @see Login#gcCustomDateFormats + */ + public static String getGcCustomDate() { + return getString(R.string.pref_gccustomdate, null); + } + + public static boolean isExcludeMyCaches() { + return getBoolean(R.string.pref_excludemine, false); + } + + public static void setUseEnglish(final boolean english) { + putBoolean(R.string.pref_useenglish, english); + setLanguage(english); + } + + public static boolean isUseEnglish() { + return getBoolean(R.string.pref_useenglish, false); + } + + public static boolean isShowAddress() { + return getBoolean(R.string.pref_showaddress, true); + } + + public static boolean isShowCaptcha() { + return !isPremiumMember() && getBoolean(R.string.pref_showcaptcha, false); + } + + public static boolean isExcludeDisabledCaches() { + return getBoolean(R.string.pref_excludedisabled, false); + } + + public static boolean isStoreOfflineMaps() { + return getBoolean(R.string.pref_offlinemaps, true); + } + + public static boolean isStoreOfflineWpMaps() { + return getBoolean(R.string.pref_offlinewpmaps, false); + } + + public static boolean isStoreLogImages() { + return getBoolean(R.string.pref_logimages, false); + } + + public static boolean isAutoLoadDescription() { + return getBoolean(R.string.pref_autoloaddesc, true); + } + + public static boolean isRatingWanted() { + return getBoolean(R.string.pref_ratingwanted, true); + } + + public static boolean isFriendLogsWanted() { + if (!isLogin()) { + // don't show a friends log if the user is anonymous + return false; + } + return getBoolean(R.string.pref_friendlogswanted, true); + } + + public static boolean isLiveList() { + return getBoolean(R.string.pref_livelist, true); + } + + public static boolean isTrackableAutoVisit() { + return getBoolean(R.string.pref_trackautovisit, false); + } + + public static boolean isAutoInsertSignature() { + return getBoolean(R.string.pref_sigautoinsert, false); + } + + public static boolean isUseImperialUnits() { + return getBoolean(R.string.pref_units, false); + } + + public static boolean isLiveMap() { + return getBoolean(R.string.pref_maplive, true); + } + + public static void setLiveMap(final boolean live) { + putBoolean(R.string.pref_maplive, live); + } + + public static boolean isMapTrail() { + return getBoolean(R.string.pref_maptrail, true); + } + + public static void setMapTrail(final boolean showTrail) { + putBoolean(R.string.pref_maptrail, showTrail); + } + + public static int getMapZoom() { + return getInt(R.string.pref_lastmapzoom, 14); + } + + public static void setMapZoom(final int mapZoomLevel) { + putInt(R.string.pref_lastmapzoom, mapZoomLevel); + } + + public static GeoPointImpl getMapCenter() { + return getMapProvider().getMapItemFactory() + .getGeoPointBase(new Geopoint(getInt(R.string.pref_lastmaplat, 0) / 1e6, + getInt(R.string.pref_lastmaplon, 0) / 1e6)); + } + + public static void setMapCenter(final GeoPointImpl mapViewCenter) { + putInt(R.string.pref_lastmaplat, mapViewCenter.getLatitudeE6()); + putInt(R.string.pref_lastmaplon, mapViewCenter.getLongitudeE6()); + } + + public static MapSource getMapSource() { + final int id = getConvertedMapId(); + final MapSource map = MapProviderFactory.getMapSource(id); + if (map != null) { + // don't use offline maps if the map file is not valid + if ((!(map instanceof OfflineMapSource)) || (isValidMapFile())) { + return map; + } + } + // fallback to first available map + return MapProviderFactory.getDefaultSource(); + } + + private final static int GOOGLEMAP_BASEID = 30; + private final static int MAP = 1; + private final static int SATELLITE = 2; + + private final static int MFMAP_BASEID = 40; + private final static int MAPNIK = 1; + private final static int CYCLEMAP = 3; + private final static int OFFLINE = 4; + + /** + * convert old preference ids for maps (based on constant values) into new hash based ids + * + * @return + */ + private static int getConvertedMapId() { + // what the heck is happening here?? hashCodes of Strings? + // why not strings? + final int id = Integer.parseInt(getString(R.string.pref_mapsource, + String.valueOf(MAP_SOURCE_DEFAULT))); + switch (id) { + case GOOGLEMAP_BASEID + MAP: + return GoogleMapProvider.GOOGLE_MAP_ID.hashCode(); + case GOOGLEMAP_BASEID + SATELLITE: + return GoogleMapProvider.GOOGLE_SATELLITE_ID.hashCode(); + case MFMAP_BASEID + MAPNIK: + return MapsforgeMapProvider.MAPSFORGE_MAPNIK_ID.hashCode(); + case MFMAP_BASEID + CYCLEMAP: + return MapsforgeMapProvider.MAPSFORGE_CYCLEMAP_ID.hashCode(); + case MFMAP_BASEID + OFFLINE: { + final String mapFile = Settings.getMapFile(); + if (StringUtils.isNotEmpty(mapFile)) { + return mapFile.hashCode(); + } + break; + } + default: + break; + } + return id; + } + + public static void setMapSource(final MapSource newMapSource) { + if (!MapProviderFactory.isSameActivity(getMapSource(), newMapSource)) { + mapProvider = null; + } + putString(R.string.pref_mapsource, String.valueOf(newMapSource.getNumericalId())); + if (newMapSource instanceof OfflineMapSource) { + setMapFile(((OfflineMapSource) newMapSource).getFileName()); + } + } + + public static void setAnyCoordinates(final Geopoint coords) { + if (null != coords) { + putFloat(R.string.pref_anylatitude, (float) coords.getLatitude()); + putFloat(R.string.pref_anylatitude, (float) coords.getLongitude()); + } else { + remove(R.string.pref_anylatitude); + remove(R.string.pref_anylongitude); + } + } + + public static Geopoint getAnyCoordinates() { + if (contains(R.string.pref_anylatitude) && contains(R.string.pref_anylongitude)) { + float lat = getFloat(R.string.pref_anylatitude, 0); + float lon = getFloat(R.string.pref_anylongitude, 0); + return new Geopoint(lat, lon); + } + return null; + } + + public static boolean isUseCompass() { + return getBoolean(R.string.pref_usecompass, true); + } + + public static void setUseCompass(final boolean useCompass) { + putBoolean(R.string.pref_usecompass, useCompass); + } + + public static boolean isLightSkin() { + return getBoolean(R.string.pref_skin, false); + } + + public static String getKeyConsumerPublic() { + return keyConsumerPublic; + } + + public static String getKeyConsumerSecret() { + return keyConsumerSecret; + } + + public static String getWebDeviceCode() { + return getString(R.string.pref_webDeviceCode, null); + } + + public static String getWebDeviceName() { + return getString(R.string.pref_webDeviceName, android.os.Build.MODEL); + } + + /** + * @return The cache type used for filtering or ALL if no filter is active. + * Returns never null + */ + public static CacheType getCacheType() { + return CacheType.getById(getString(R.string.pref_cachetype, CacheType.ALL.id)); + } + + /** + * The Threshold for the showing of child waypoints + */ + public static int getWayPointsThreshold() { + return getInt(R.string.pref_gcshowwaypointsthreshold, SHOW_WP_THRESHOLD_DEFAULT); + } + + public static void setShowWaypointsThreshold(final int threshold) { + putInt(R.string.pref_gcshowwaypointsthreshold, threshold); + } + + public static boolean isUseTwitter() { + return getBoolean(R.string.pref_twitter, false); + } + + public static void setUseTwitter(final boolean useTwitter) { + putBoolean(R.string.pref_twitter, useTwitter); + } + + public static boolean isTwitterLoginValid() { + return !StringUtils.isBlank(getTokenPublic()) + && !StringUtils.isBlank(getTokenSecret()); + } + + public static String getTokenPublic() { + return getString(R.string.pref_twitter_token_public, null); + } + + public static String getTokenSecret() { + return getString(R.string.pref_twitter_token_secret, null); + + } + + public static void setTwitterTokens(final String tokenPublic, + final String tokenSecret, boolean enableTwitter) { + putString(R.string.pref_twitter_token_public, tokenPublic); + putString(R.string.pref_twitter_token_secret, tokenSecret); + if (tokenPublic != null) { + remove(R.string.pref_temp_twitter_token_public); + remove(R.string.pref_temp_twitter_token_secret); + } + setUseTwitter(enableTwitter); + } + + public static void setTwitterTempTokens(final String tokenPublic, + final String tokenSecret) { + putString(R.string.pref_temp_twitter_token_public, tokenPublic); + putString(R.string.pref_temp_twitter_token_secret, tokenSecret); + } + + public static ImmutablePair<String, String> getTempToken() { + String tokenPublic = getString(R.string.pref_twitter_token_public, null); + String tokenSecret = getString(R.string.pref_temp_twitter_token_secret, null); + return new ImmutablePair<String, String>(tokenPublic, tokenSecret); + } + + public static int getVersion() { + return getInt(R.string.pref_version, 0); + } + + public static void setVersion(final int version) { + putInt(R.string.pref_version, version); + } + + public static boolean isOpenLastDetailsPage() { + return getBoolean(R.string.pref_opendetailslastpage, false); + } + + public static int getLastDetailsPage() { + return getInt(R.string.pref_lastdetailspage, 1); + } + + public static void setLastDetailsPage(final int index) { + putInt(R.string.pref_lastdetailspage, index); + } + + public static int getDefaultNavigationTool() { + return Integer.parseInt(getString( + R.string.pref_defaultNavigationTool, + String.valueOf(NavigationAppsEnum.COMPASS.id))); + } + + public static void setDefaultNavigationTool(final int defaultNavigationTool) { + putString(R.string.pref_defaultNavigationTool, + String.valueOf(defaultNavigationTool)); + } + + public static int getDefaultNavigationTool2() { + return Integer.parseInt(getString( + R.string.pref_defaultNavigationTool2, + String.valueOf(NavigationAppsEnum.INTERNAL_MAP.id))); + } + + public static void setDefaultNavigationTool2(final int defaultNavigationTool) { + putString(R.string.pref_defaultNavigationTool2, + String.valueOf(defaultNavigationTool)); + } + + public static Strategy getLiveMapStrategy() { + return Strategy.getById(getInt(R.string.pref_livemapstrategy, Strategy.AUTO.id)); + } + + public static void setLiveMapStrategy(final Strategy strategy) { + putInt(R.string.pref_livemapstrategy, strategy.id); + } + + public static boolean isDebug() { + return Log.isDebug(); + } + + public static boolean getHideLiveMapHint() { + return getBoolean(R.string.pref_hidelivemaphint, false); + } + + public static void setHideLiveHint(final boolean hide) { + putBoolean(R.string.pref_hidelivemaphint, hide); + } + + public static int getLiveMapHintShowCount() { + return getInt(R.string.pref_livemaphintshowcount, 0); + } + + public static void setLiveMapHintShowCount(final int showCount) { + putInt(R.string.pref_livemaphintshowcount, showCount); + } + + public static boolean isDbOnSDCard() { + return getBoolean(R.string.pref_dbonsdcard, false); + } + + public static void setDbOnSDCard(final boolean dbOnSDCard) { + putBoolean(R.string.pref_dbonsdcard, dbOnSDCard); + } + + public static String getGpxExportDir() { + return getString(R.string.pref_gpxExportDir, + Environment.getExternalStorageDirectory().getPath() + "/gpx"); + } + + public static String getGpxImportDir() { + return getString(R.string.pref_gpxImportDir, + Environment.getExternalStorageDirectory().getPath() + "/gpx"); + } + + public static boolean getShareAfterExport() { + return getBoolean(R.string.pref_shareafterexport, true); + } + + public static void setShareAfterExport(final boolean shareAfterExport) { + putBoolean(R.string.pref_shareafterexport, shareAfterExport); + } + + public static int getTrackableAction() { + return getInt(R.string.pref_trackableaction, LogType.RETRIEVED_IT.id); + } + + public static void setTrackableAction(final int trackableAction) { + putInt(R.string.pref_trackableaction, trackableAction); + } + + public static String getCustomRenderThemeBaseFolder() { + return getString(R.string.pref_renderthemepath, ""); + } + + public static String getCustomRenderThemeFilePath() { + return getString(R.string.pref_renderthemefile, ""); + } + + public static void setCustomRenderThemeFile(final String customRenderThemeFile) { + putString(R.string.pref_renderthemefile, customRenderThemeFile); + } + + public static File[] getMapThemeFiles() { + File directory = new File(Settings.getCustomRenderThemeBaseFolder()); + List<File> result = new ArrayList<File>(); + FileUtils.listDir(result, directory, new ExtensionsBasedFileSelector(new String[] { "xml" }), null); + + return result.toArray(new File[result.size()]); + } + + private static class ExtensionsBasedFileSelector extends FileSelector { + private final String[] extensions; + public ExtensionsBasedFileSelector(String[] extensions) { + this.extensions = extensions; + } + @Override + public boolean isSelected(File file) { + String filename = file.getName(); + for (String ext : extensions) { + if (StringUtils.endsWithIgnoreCase(filename, ext)) { + return true; + } + } + return false; + } + @Override + public boolean shouldEnd() { + return false; + } + } + + public static boolean getPlainLogs() { + return getBoolean(R.string.pref_plainLogs, false); + } + + public static boolean getUseNativeUa() { + return getBoolean(R.string.pref_nativeUa, false); + } + + public static String getCacheTwitterMessage() { + // TODO make customizable from UI + return "I found [NAME] ([URL])"; + } + + public static String getTrackableTwitterMessage() { + // TODO make customizable from UI + return "I touched [NAME] ([URL])!"; + } + + public static int getLogImageScale() { + return getInt(R.string.pref_logImageScale, -1); + } + + public static void setLogImageScale(final int scale) { + putInt(R.string.pref_logImageScale, scale); + } + + // Only for tests! + static void setExcludeDisabledCaches(final boolean exclude) { + putBoolean(R.string.pref_excludedisabled, exclude); + } + + static void setExcludeMine(final boolean exclude) { + putBoolean(R.string.pref_excludemine, exclude); + } + + static boolean setLogin(final String username, final String password) { + + if (StringUtils.isBlank(username) || StringUtils.isBlank(password)) { + // erase username and password + boolean a = remove(R.string.pref_username); + boolean b = remove(R.string.pref_password); + return a && b; + } + // save username and password + boolean a = putString(R.string.pref_username, username); + boolean b = putString(R.string.pref_password, password); + return a && b; + } + + static void setStoreOfflineMaps(final boolean offlineMaps) { + putBoolean(R.string.pref_offlinemaps, offlineMaps); + } + + static void setStoreOfflineWpMaps(final boolean offlineWpMaps) { + putBoolean(R.string.pref_offlinewpmaps, offlineWpMaps); + } + + static void setUseImperialUnits(final boolean imperial) { + putBoolean(R.string.pref_units, imperial); + } + +} diff --git a/main/src/cgeo/geocaching/settings/SettingsActivity.java b/main/src/cgeo/geocaching/settings/SettingsActivity.java new file mode 100644 index 0000000..b9035ec --- /dev/null +++ b/main/src/cgeo/geocaching/settings/SettingsActivity.java @@ -0,0 +1,532 @@ +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.EditText; + +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; + + 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) { + + if (Settings.isLightSkin()) { + setTheme(R.style.settings_light); + } else { + setTheme(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) SettingsActivity.findPreference(this, getKey(R.string.pref_fakekey_main_screen)); + int index = SettingsActivity.findPreference(this, getKey(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(this, getKey(k)); + } + } + + 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(final 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(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) SettingsActivity.findPreference(this, getKey(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) SettingsActivity.findPreference(this, getKey(R.string.pref_defaultNavigationTool)); + pref.setEntries(entries); + pref.setEntryValues(values); + pref = (ListPreference) SettingsActivity.findPreference(this, getKey(R.string.pref_defaultNavigationTool2)); + pref.setEntries(entries); + pref.setEntryValues(values); + } + + private void initDirChoosers() { + for (final DirChooserType dct : DirChooserType.values()) { + + SettingsActivity.findPreference(this, getKey(dct.keyId)).setOnPreferenceClickListener( + new OnPreferenceClickListener() { + @Override + public boolean onPreferenceClick(final Preference preference) { + startDirChooser(dct); + return false; + } + }); + } + + SettingsActivity.findPreference(this, getKey(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 = SettingsActivity.findPreference(this, getKey(dct.keyId)); + if (p == null) { + return; + } + Settings.putString(dct.keyId, directory); + p.setSummary(directory); + } + } + + public void initBackupButtons() { + Preference backup = SettingsActivity.findPreference(this, 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(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.findPreference(SettingsActivity.this, getKey(R.string.pref_fakekey_preference_backup_info)), ""); + } + }); + } + }.start(); + return true; + } + }); + + Preference restore = SettingsActivity.findPreference(this, getKey(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 = SettingsActivity.findPreference(this, getKey(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 = SettingsActivity.findPreference(this, getKey(R.string.pref_debug)); + p.setOnPreferenceChangeListener(new OnPreferenceChangeListener() { + @Override + public boolean onPreferenceChange(final Preference preference, final Object newValue) { + Log.setDebug((Boolean) newValue); + return true; + } + }); + } + + private void initBasicMemberPreferences() { + SettingsActivity.findPreference(this, getKey(R.string.pref_loaddirectionimg)).setEnabled( + !Settings.isPremiumMember()); + SettingsActivity.findPreference(this, getKey(R.string.pref_showcaptcha)).setEnabled( + !Settings.isPremiumMember()); + } + + private static void initSend2CgeoPreferences() { + Settings.putString(R.string.pref_webDeviceName, Settings.getWebDeviceName()); + } + + public static void startWithServicesPage(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(); + SettingsActivity.findPreference(this, 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 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 static void bindSummaryToStringValue(final PreferenceActivity preferenceActivity, final String key) { + + Preference pref = findPreference(preferenceActivity, key); + + 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(final PreferenceActivity preferenceActivity, final String key) { + + Preference pref = findPreference(preferenceActivity, key); + + if (pref == null) { + return; + } + + int value = PreferenceManager + .getDefaultSharedPreferences(pref.getContext()) + .getInt(pref.getKey(), 0); + + 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); + } +} diff --git a/main/src/cgeo/geocaching/settings/TextPreference.java b/main/src/cgeo/geocaching/settings/TextPreference.java new file mode 100644 index 0000000..bcd03ff --- /dev/null +++ b/main/src/cgeo/geocaching/settings/TextPreference.java @@ -0,0 +1,86 @@ +package cgeo.geocaching.settings; + +import cgeo.geocaching.R; + +import android.content.Context; +import android.content.res.TypedArray; +import android.preference.Preference; +import android.util.AttributeSet; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +/** + * Preference to simply show a text message. + * <p> + * Links are not shown - I tried everything (koem) + * <p> + * example: <cgeo.geocaching.settings.TextPreference android:text="@string/legal_note" + * android:layout="@string/text_preference_default_layout" /> + */ +public class TextPreference extends Preference { + + private String text; + private TextView summaryView; + private CharSequence summaryText; + + public TextPreference(Context context) { + super(context); + } + + public TextPreference(Context context, AttributeSet attrs) { + super(context, attrs); + processAttributes(context, attrs, 0); + } + + public TextPreference(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + processAttributes(context, attrs, defStyle); + } + + private void processAttributes(Context context, AttributeSet attrs, int defStyle) { + if (attrs == null) { + return; + } + + TypedArray types = context.obtainStyledAttributes(attrs, new int[] { + android.R.attr.text }, defStyle, 0); + this.text = types.getString(0); + types.recycle(); + } + + @Override + protected View onCreateView(ViewGroup parent) { + this.setSelectable(false); + + View v = super.onCreateView(parent); + + TextView text = (TextView) v.findViewById(R.id.textPreferenceText); + text.setText(this.text); + + summaryView = (TextView) v.findViewById(R.id.textPreferenceSummary); + setSummary(null); // show saved summary text + + return v; + } + + @Override + public void setSummary(CharSequence summaryText) { + // the layout hasn't been inflated yet, save the summaryText for later use + if (this.summaryView == null) { + this.summaryText = summaryText; + return; + } + + // if summaryText is null, take it from the previous saved summary + if (summaryText == null) { + if (this.summaryText == null) { + return; + } + this.summaryView.setText(this.summaryText); + } else { + this.summaryView.setText(summaryText); + } + this.summaryView.setVisibility(View.VISIBLE); + } +} diff --git a/main/src/cgeo/geocaching/settings/WpThresholdPreference.java b/main/src/cgeo/geocaching/settings/WpThresholdPreference.java new file mode 100644 index 0000000..867714f --- /dev/null +++ b/main/src/cgeo/geocaching/settings/WpThresholdPreference.java @@ -0,0 +1,73 @@ +package cgeo.geocaching.settings; + +import cgeo.geocaching.R; +import cgeo.geocaching.settings.Settings; + +import android.content.Context; +import android.preference.Preference; +import android.util.AttributeSet; +import android.view.View; +import android.view.ViewGroup; +import android.widget.SeekBar; +import android.widget.SeekBar.OnSeekBarChangeListener; +import android.widget.TextView; + +public class WpThresholdPreference extends Preference { + + TextView valueView; + + public WpThresholdPreference(Context context) { + super(context); + init(); + } + + public WpThresholdPreference(Context context, AttributeSet attrs) { + super(context, attrs); + init(); + } + + public WpThresholdPreference(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + init(); + } + + private void init() { + setPersistent(false); + } + + @Override + protected View onCreateView(ViewGroup parent) { + View v = super.onCreateView(parent); + + // get views + SeekBar seekBar = (SeekBar) v.findViewById(R.id.wp_threshold_seekbar); + valueView = (TextView) v.findViewById(R.id.wp_threshold_value_view); + + // init seekbar + seekBar.setMax(Settings.SHOW_WP_THRESHOLD_MAX); + + // set initial value + int threshold = Settings.getWayPointsThreshold(); + valueView.setText(String.valueOf(threshold)); + seekBar.setProgress(threshold); + + seekBar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() { + @Override + public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { + if (fromUser) { + valueView.setText(String.valueOf(progress)); + } + } + @Override + public void onStartTrackingTouch(SeekBar seekBar) { + } + @Override + public void onStopTrackingTouch(SeekBar seekBar) { + Settings.setShowWaypointsThreshold(seekBar.getProgress()); + } + }); + + return v; + } + +} |
