package net.osmand.plus.activities; import android.content.Context; import android.content.DialogInterface; import android.content.DialogInterface.OnMultiChoiceClickListener; import android.os.Bundle; import android.preference.CheckBoxPreference; import android.preference.EditTextPreference; import android.preference.ListPreference; import android.preference.Preference; import android.preference.Preference.OnPreferenceChangeListener; import android.preference.Preference.OnPreferenceClickListener; import android.preference.PreferenceGroup; import android.preference.PreferenceScreen; import android.support.v7.app.AlertDialog; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.TextView; import android.widget.Toast; import net.osmand.plus.ApplicationMode; import net.osmand.plus.OsmandApplication; import net.osmand.plus.OsmandSettings; import net.osmand.plus.OsmandSettings.CommonPreference; import net.osmand.plus.OsmandSettings.OsmandPreference; import net.osmand.plus.R; import net.osmand.plus.activities.actions.AppModeDialog; import net.osmand.plus.views.SeekBarPreference; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; public abstract class SettingsBaseActivity extends ActionBarPreferenceActivity implements OnPreferenceChangeListener, OnPreferenceClickListener { public static final String INTENT_APP_MODE = "INTENT_APP_MODE"; protected OsmandSettings settings; protected final boolean profileSettings; protected List<ApplicationMode> modes = new ArrayList<ApplicationMode>(); private ApplicationMode previousAppMode; private Map<String, Preference> screenPreferences = new LinkedHashMap<String, Preference>(); private Map<String, OsmandPreference<Boolean>> booleanPreferences = new LinkedHashMap<String, OsmandPreference<Boolean>>(); private Map<String, OsmandPreference<?>> listPreferences = new LinkedHashMap<String, OsmandPreference<?>>(); private Map<String, OsmandPreference<String>> editTextPreferences = new LinkedHashMap<String, OsmandPreference<String>>(); private Map<String, OsmandPreference<Integer>> seekBarPreferences = new LinkedHashMap<String, OsmandPreference<Integer>>(); private Map<String, Map<String, ?>> listPrefValues = new LinkedHashMap<String, Map<String, ?>>(); private AlertDialog profileDialog; public SettingsBaseActivity() { this(false); } public SettingsBaseActivity(boolean profile) { profileSettings = profile; } public CheckBoxPreference registerBooleanPreference(OsmandPreference<Boolean> b, PreferenceGroup screen) { CheckBoxPreference p = (CheckBoxPreference) screen.findPreference(b.getId()); p.setOnPreferenceChangeListener(this); screenPreferences.put(b.getId(), p); booleanPreferences.put(b.getId(), b); return p; } public CheckBoxPreference createCheckBoxPreference(OsmandPreference<Boolean> b, int title, int summary) { CheckBoxPreference p = new CheckBoxPreference(this); p.setTitle(title); p.setKey(b.getId()); p.setSummary(summary); p.setOnPreferenceChangeListener(this); screenPreferences.put(b.getId(), p); booleanPreferences.put(b.getId(), b); return p; } public CheckBoxPreference createCheckBoxPreference(OsmandPreference<Boolean> b, String title, String summary) { CheckBoxPreference p = new CheckBoxPreference(this); p.setTitle(title); p.setKey(b.getId()); p.setSummary(summary); p.setOnPreferenceChangeListener(this); screenPreferences.put(b.getId(), p); booleanPreferences.put(b.getId(), b); return p; } public CheckBoxPreference createCheckBoxPreference(OsmandPreference<Boolean> b) { CheckBoxPreference p = new CheckBoxPreference(this); p.setKey(b.getId()); p.setOnPreferenceChangeListener(this); screenPreferences.put(b.getId(), p); booleanPreferences.put(b.getId(), b); return p; } public void registerSeekBarPreference(OsmandPreference<Integer> b, PreferenceScreen screen) { SeekBarPreference p = (SeekBarPreference) screen.findPreference(b.getId()); p.setOnPreferenceChangeListener(this); screenPreferences.put(b.getId(), p); seekBarPreferences.put(b.getId(), b); } public static String getRoutingStringPropertyName(Context ctx, String propertyName, String defValue) { try { Field f = R.string.class.getField("routing_attr_" + propertyName + "_name"); if (f != null) { Integer in = (Integer) f.get(null); return ctx.getString(in); } } catch (Exception e) { System.err.println(e.getMessage()); } return defValue; } public static String getRoutingStringPropertyDescription(Context ctx, String propertyName, String defValue) { try { Field f = R.string.class.getField("routing_attr_" + propertyName + "_description"); if (f != null) { Integer in = (Integer) f.get(null); return ctx.getString(in); } } catch (Exception e) { System.err.println(e.getMessage()); } return defValue; } public static String getStringPropertyName(Context ctx, String propertyName, String defValue) { try { Field f = R.string.class.getField("rendering_attr_" + propertyName + "_name"); if (f != null) { Integer in = (Integer) f.get(null); return ctx.getString(in); } } catch (Exception e) { System.err.println(e.getMessage()); } return defValue; } public static String getStringPropertyDescription(Context ctx, String propertyName, String defValue) { try { Field f = R.string.class.getField("rendering_attr_" + propertyName + "_description"); if (f != null) { Integer in = (Integer) f.get(null); return ctx.getString(in); } } catch (Exception e) { //e.printStackTrace(); System.err.println(e.getMessage()); } return defValue; } public static String getStringPropertyValue(Context ctx, String propertyValue) { try { if(propertyValue == null) { return ""; } final String propertyValueReplaced = propertyValue.replaceAll("\\s+","_"); Field f = R.string.class.getField("rendering_value_" + propertyValueReplaced + "_name"); if (f != null) { Integer in = (Integer) f.get(null); return ctx.getString(in); } } catch (Exception e) { System.err.println(e.getMessage()); } return propertyValue; } public SeekBarPreference createSeekBarPreference(OsmandPreference<Integer> b, int title, int summary, int dialogTextId, int defValue, int maxValue) { SeekBarPreference p = new SeekBarPreference(this, dialogTextId, defValue, maxValue); p.setTitle(title); p.setKey(b.getId()); p.setSummary(summary); p.setOnPreferenceChangeListener(this); screenPreferences.put(b.getId(), p); seekBarPreferences.put(b.getId(), b); return p; } public <T> void registerListPreference(OsmandPreference<T> b, PreferenceGroup screen, String[] names, T[] values) { ListPreference p = (ListPreference) screen.findPreference(b.getId()); prepareListPreference(b, names, values, p); } public <T> ListPreference createListPreference(OsmandPreference<T> b, String[] names, T[] values, int title, int summary) { ListPreference p = new ListPreference(this); p.setTitle(title); p.setKey(b.getId()); p.setDialogTitle(title); p.setSummary(summary); prepareListPreference(b, names, values, p); return p; } public <T> ListPreference createListPreference(OsmandPreference<T> b, String[] names, T[] values, String title, String summary) { ListPreference p = new ListPreference(this); p.setTitle(title); p.setKey(b.getId()); p.setDialogTitle(title); p.setSummary(summary); prepareListPreference(b, names, values, p); return p; } public <T> ListPreference createListPreference(OsmandPreference<T> b, String[] names, T[] values) { ListPreference p = new ListPreference(this); p.setKey(b.getId()); prepareListPreference(b, names, values, p); return p; } private <T> void prepareListPreference(OsmandPreference<T> b, String[] names, T[] values, ListPreference p) { p.setOnPreferenceChangeListener(this); LinkedHashMap<String, Object> vals = new LinkedHashMap<String, Object>(); screenPreferences.put(b.getId(), p); listPreferences.put(b.getId(), b); listPrefValues.put(b.getId(), vals); assert names.length == values.length; for (int i = 0; i < names.length; i++) { vals.put(names[i], values[i]); } } private void registerDisablePreference(OsmandPreference p, String value, OsmandPreference<Boolean> disable) { LinkedHashMap<String, Object> vals = (LinkedHashMap<String, Object>) listPrefValues.get(p.getId()); vals.put(value, disable); } public void registerEditTextPreference(OsmandPreference<String> b, PreferenceScreen screen) { EditTextPreference p = (EditTextPreference) screen.findPreference(b.getId()); p.setOnPreferenceChangeListener(this); screenPreferences.put(b.getId(), p); editTextPreferences.put(b.getId(), b); } public EditTextPreference createEditTextPreference(OsmandPreference<String> b, int title, int summary) { EditTextPreference p = new EditTextPreference(this); p.setTitle(title); p.setKey(b.getId()); p.setDialogTitle(title); p.setSummary(summary); p.setOnPreferenceChangeListener(this); screenPreferences.put(b.getId(), p); editTextPreferences.put(b.getId(), b); return p; } public void registerTimeListPreference(OsmandPreference<Integer> b, PreferenceScreen screen, int[] seconds, int[] minutes, int coeff) { int minutesLength = minutes == null ? 0 : minutes.length; int secondsLength = seconds == null ? 0 : seconds.length; Integer[] ints = new Integer[secondsLength + minutesLength]; String[] intDescriptions = new String[ints.length]; for (int i = 0; i < secondsLength; i++) { ints[i] = seconds[i] * coeff; intDescriptions[i] = seconds[i] + " " + getString(R.string.int_seconds); //$NON-NLS-1$ } for (int i = 0; i < minutesLength; i++) { ints[secondsLength + i] = (minutes[i] * 60) * coeff; intDescriptions[secondsLength + i] = minutes[i] + " " + getString(R.string.int_min); //$NON-NLS-1$ } registerListPreference(b, screen, intDescriptions, ints); } public ListPreference createTimeListPreference(OsmandPreference<Integer> b, int[] seconds, int[] minutes, int coeff, int title, int summary) { return createTimeListPreference(b, seconds, minutes, coeff, null, title, summary); } public ListPreference createTimeListPreference(OsmandPreference<Integer> b, int[] seconds, int[] minutes, int coeff, CommonPreference<Boolean> disable, int title, int summary) { int minutesLength = minutes == null ? 0 : minutes.length; int secondsLength = seconds == null ? 0 : seconds.length; Integer[] ints = new Integer[secondsLength + minutesLength]; String[] intDescriptions = new String[ints.length]; int k = 0; for (int i = 0; i < secondsLength; i++) { ints[k] = seconds[i] * coeff; intDescriptions[k] = seconds[i] + " " + getString(R.string.int_seconds); //$NON-NLS-1$ k++; } for (int i = 0; i < minutesLength; i++) { ints[k] = (minutes[i] * 60) * coeff; intDescriptions[k] = minutes[i] + " " + getString(R.string.int_min); //$NON-NLS-1$ k++; } ListPreference lp = createListPreference(b, intDescriptions, ints, title, summary); if(disable != null) { registerDisablePreference(b, getString(R.string.confirm_every_run), disable); } return lp; } @Override public boolean onOptionsItemSelected(MenuItem item) { int itemId = item.getItemId(); switch (itemId) { case android.R.id.home: finish(); return true; } return false; } @SuppressWarnings("deprecation") @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); settings = getMyApplication().getSettings(); getToolbar().setTitle(R.string.shared_string_settings); if (profileSettings) { modes.clear(); for (ApplicationMode a : ApplicationMode.values(settings)) { if (a != ApplicationMode.DEFAULT) { modes.add(a); } } List<String> s = new ArrayList<String>(); for (ApplicationMode a : modes) { s.add(a.toHumanString(getMyApplication())); } SpinnerAdapter spinnerAdapter = new SpinnerAdapter(this, R.layout.spinner_item, s); // android.R.layout.simple_spinner_dropdown_item spinnerAdapter.setDropDownViewResource(R.layout.spinner_dropdown_item); getSpinner().setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { @Override public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { settings.APPLICATION_MODE.set(modes.get(position)); updateAllSettings(); } @Override public void onNothingSelected(AdapterView<?> parent) { } }); getSpinner().setAdapter(spinnerAdapter); getSpinner().setVisibility(View.VISIBLE); } setPreferenceScreen(getPreferenceManager().createPreferenceScreen(this)); } class SpinnerAdapter extends ArrayAdapter<String>{ public SpinnerAdapter(Context context, int resource, List<String> objects) { super(context, resource, objects); } @Override public View getDropDownView(int position, View convertView, ViewGroup parent) { View view = super.getDropDownView(position, convertView, parent); if (!settings.isLightActionBar()){ TextView textView = (TextView) view.findViewById(android.R.id.text1); textView.setBackgroundColor(getResources().getColor(R.color.actionbar_dark_color)); } return view; } } @Override protected void onResume() { super.onResume(); if (profileSettings) { previousAppMode = settings.getApplicationMode(); boolean found; if (getIntent() != null && getIntent().hasExtra(INTENT_APP_MODE)) { String modeStr = getIntent().getStringExtra(INTENT_APP_MODE); ApplicationMode mode = ApplicationMode.valueOfStringKey(modeStr, previousAppMode); found = setSelectedAppMode(mode); } else { found = setSelectedAppMode(previousAppMode); } if (!found) { getSpinner().setSelection(0); } } else { updateAllSettings(); } } protected void profileDialog() { AlertDialog.Builder b = new AlertDialog.Builder(this); final Set<ApplicationMode> selected = new LinkedHashSet<ApplicationMode>(); View v = AppModeDialog.prepareAppModeView(this, selected, false, null, true, false, new View.OnClickListener() { @Override public void onClick(View v) { if(selected.size() > 0) { // test setSelectedAppMode(selected.iterator().next()); } if(profileDialog != null && profileDialog.isShowing()) { profileDialog.dismiss(); } profileDialog = null; } }); b.setTitle(R.string.profile_settings); b.setView(v); profileDialog = b.show(); } protected boolean setSelectedAppMode(ApplicationMode am) { int ind = 0; boolean found = false; for (ApplicationMode a : modes) { if (am == a) { getSpinner().setSelection(ind); found = true; break; } ind++; } return found; } @Override protected void onPause() { super.onPause(); if(profileSettings) { settings.APPLICATION_MODE.set(previousAppMode); } } public void updateAllSettings() { for (OsmandPreference<Boolean> b : booleanPreferences.values()) { CheckBoxPreference pref = (CheckBoxPreference) screenPreferences.get(b.getId()); pref.setChecked(b.get()); } for (OsmandPreference<Integer> b : seekBarPreferences.values()) { SeekBarPreference pref = (SeekBarPreference) screenPreferences.get(b.getId()); pref.setValue(b.get()); } for (OsmandPreference<?> p : listPreferences.values()) { ListPreference listPref = (ListPreference) screenPreferences.get(p.getId()); Map<String, ?> prefValues = listPrefValues.get(p.getId()); String[] entryValues = new String[prefValues.size()]; String[] entries = new String[prefValues.size()]; int i = 0; for (Entry<String, ?> e : prefValues.entrySet()) { entries[i] = e.getKey(); entryValues[i] = e.getValue() + ""; // case of null i++; } listPref.setEntries(entries); listPref.setEntryValues(entryValues); listPref.setValue(p.get() + ""); } for (OsmandPreference<String> s : editTextPreferences.values()) { EditTextPreference pref = (EditTextPreference) screenPreferences.get(s.getId()); pref.setText(s.get()); } } @SuppressWarnings("unchecked") @Override public boolean onPreferenceChange(Preference preference, Object newValue) { // handle boolean preferences OsmandPreference<Boolean> boolPref = booleanPreferences.get(preference.getKey()); OsmandPreference<Integer> seekPref = seekBarPreferences.get(preference.getKey()); OsmandPreference<Object> listPref = (OsmandPreference<Object>) listPreferences.get(preference.getKey()); OsmandPreference<String> editPref = editTextPreferences.get(preference.getKey()); if (boolPref != null) { boolPref.set((Boolean) newValue); } else if (seekPref != null) { seekPref.set((Integer) newValue); } else if (editPref != null) { editPref.set((String) newValue); } else if (listPref != null) { int ind = ((ListPreference) preference).findIndexOfValue((String) newValue); CharSequence entry = ((ListPreference) preference).getEntries()[ind]; Map<String, ?> map = listPrefValues.get(preference.getKey()); Object obj = map.get(entry); boolean changed ; if(obj instanceof OsmandPreference) { changed = true; ((OsmandPreference<Boolean>) obj).set(false); } else { changed = listPref.set(obj); } return changed; } return true; } protected OsmandApplication getMyApplication() { return (OsmandApplication) getApplication(); } protected void showWarnings(List<String> warnings) { if (!warnings.isEmpty()) { final StringBuilder b = new StringBuilder(); boolean f = true; for (String w : warnings) { if (f) { f = false; } else { b.append('\n'); } b.append(w); } runOnUiThread(new Runnable() { @Override public void run() { Toast.makeText(SettingsBaseActivity.this, b.toString(), Toast.LENGTH_LONG).show(); } }); } } public void showBooleanSettings(String[] vals, final OsmandPreference<Boolean>[] prefs) { AlertDialog.Builder bld = new AlertDialog.Builder(this); boolean[] checkedItems = new boolean[prefs.length]; for (int i = 0; i < prefs.length; i++) { checkedItems[i] = prefs[i].get(); } bld.setMultiChoiceItems(vals, checkedItems, new OnMultiChoiceClickListener() { @Override public void onClick(DialogInterface dialog, int which, boolean isChecked) { prefs[which].set(isChecked); } }); bld.show(); } @Override public boolean onPreferenceClick(Preference preference) { return false; } }