package cgeo.geocaching.settings;
import cgeo.geocaching.CgeoApplication;
import cgeo.geocaching.Intents;
import cgeo.geocaching.R;
import cgeo.geocaching.SelectMapfileActivity;
import cgeo.geocaching.activity.ActivityMixin;
import cgeo.geocaching.apps.navi.NavigationAppFactory;
import cgeo.geocaching.apps.navi.NavigationAppFactory.NavigationAppsEnum;
import cgeo.geocaching.connector.ConnectorFactory;
import cgeo.geocaching.connector.capability.ICredentials;
import cgeo.geocaching.connector.ec.ECConnector;
import cgeo.geocaching.connector.gc.GCConnector;
import cgeo.geocaching.connector.su.GeocachingSuConnector;
import cgeo.geocaching.files.SimpleDirChooser;
import cgeo.geocaching.gcvote.GCVote;
import cgeo.geocaching.maps.MapProviderFactory;
import cgeo.geocaching.maps.interfaces.MapSource;
import cgeo.geocaching.network.AndroidBeam;
import cgeo.geocaching.playservices.GooglePlayServices;
import cgeo.geocaching.sensors.OrientationProvider;
import cgeo.geocaching.sensors.RotationProvider;
import cgeo.geocaching.sensors.Sensors;
import cgeo.geocaching.storage.DataStore;
import cgeo.geocaching.storage.LocalStorage;
import cgeo.geocaching.ui.dialog.Dialogs;
import cgeo.geocaching.utils.AndroidRxUtils;
import cgeo.geocaching.utils.DatabaseBackupUtils;
import cgeo.geocaching.utils.DebugUtils;
import cgeo.geocaching.utils.FileUtils;
import cgeo.geocaching.utils.Formatter;
import cgeo.geocaching.utils.Log;
import cgeo.geocaching.utils.ProcessUtils;
import android.R.string;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.app.backup.BackupManager;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.Resources;
import android.net.Uri;
import android.os.Bundle;
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.support.annotation.AnyRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.BaseAdapter;
import android.widget.ListAdapter;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.atomic.AtomicLong;
import io.reactivex.schedulers.Schedulers;
import org.apache.commons.lang3.StringUtils;
import org.openintents.intents.FileManagerIntents;
/**
* 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.
*
*/
public class SettingsActivity extends PreferenceActivity implements Preference.OnPreferenceChangeListener {
private static final String INTENT_OPEN_SCREEN = "OPEN_SCREEN";
public static final int NO_RESTART_NEEDED = 1;
public static final int RESTART_NEEDED = 2;
/**
* 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,
LocalStorage.getGpxImportDirectory().getPath(), false),
GPX_EXPORT_DIR(2, R.string.pref_gpxExportDir,
LocalStorage.getGpxExportDirectory().getPath(), true),
THEMES_DIR(3, R.string.pref_renderthemepath, "", false);
public final int requestCode;
public final int keyId;
public final String defaultValue;
public final boolean writeMode;
DirChooserType(final int requestCode, final int keyId, final String defaultValue, final boolean writeMode) {
this.requestCode = requestCode;
this.keyId = keyId;
this.defaultValue = defaultValue;
this.writeMode = writeMode;
}
}
@Override
protected void onCreate(final Bundle savedInstanceState) {
// Set light skin in preferences only for devices > 2.x, it doesn't work under 2.x
setTheme(Settings.isLightSkin() ? R.style.settings_light : R.style.settings);
super.onCreate(savedInstanceState);
initDeviceSpecificPreferences();
initUnitPreferences();
addPreferencesFromResource(this, R.xml.preferences);
initPreferences();
final Intent intent = getIntent();
openInitialScreen(intent.getIntExtra(INTENT_OPEN_SCREEN, 0));
AndroidBeam.disable(this);
setResult(NO_RESTART_NEEDED);
}
private void openInitialScreen(final int initialScreen) {
if (initialScreen == 0) {
return;
}
final PreferenceScreen screen = (PreferenceScreen) getPreference(initialScreen);
if (screen == null) {
return;
}
try {
setPreferenceScreen(screen);
} catch (final RuntimeException e) {
Log.e("could not open preferences " + initialScreen, e);
}
}
@Override
protected void onPause() {
Log.i("Requesting settings backup with settings manager");
BackupManager.dataChanged(getPackageName());
super.onPause();
}
private void initPreferences() {
initMapSourcePreference();
initExtCgeoDirPreference();
initDirChoosers();
initDefaultNavigationPreferences();
initBackupButtons();
initDbLocationPreference();
initGeoDirPreferences();
initDebugPreference();
initForceOrientationSensorPreference();
initBasicMemberPreferences();
initSend2CgeoPreferences();
initServicePreferences();
initNavigationMenuPreferences();
initLanguagePreferences();
initMaintenanceButtons();
for (final int k : new int[] {
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_fakekey_dataDir,
R.string.pref_mapDirectory, R.string.pref_defaultNavigationTool,
R.string.pref_defaultNavigationTool2, R.string.pref_webDeviceName,
R.string.pref_fakekey_preference_backup_info, R.string.pref_twitter_cache_message, R.string.pref_twitter_trackable_message,
R.string.pref_ec_icons }) {
bindSummaryToStringValue(k);
}
bindGeocachingUserToGCVoteuser();
}
private void initNavigationMenuPreferences() {
for (final NavigationAppsEnum appEnum : NavigationAppsEnum.values()) {
final Preference preference = getPreference(appEnum.preferenceKey);
if (appEnum.app.isInstalled()) {
preference.setEnabled(true);
} else {
preference.setSummary(R.string.settings_navigation_disabled);
}
}
getPreference(R.string.preference_screen_basicmembers)
.setEnabled(!Settings.isGCPremiumMember());
redrawScreen(R.string.preference_screen_navigation_menu);
}
private void initServicePreferences() {
for (final OCPreferenceKeys key : OCPreferenceKeys.values()) {
getPreference(key.isActivePrefId).setOnPreferenceChangeListener(this);
setWebsite(key.websitePrefId, key.authParams.host);
getPreference(key.prefScreenId).setSummary(getServiceSummary(Settings.isOCConnectorActive(key.isActivePrefId)));
}
getPreference(R.string.pref_connectorGCActive).setOnPreferenceChangeListener(this);
setWebsite(R.string.pref_fakekey_gc_website, GCConnector.getInstance().getHost());
getPreference(R.string.preference_screen_gc).setSummary(getServiceSummary(Settings.isGCConnectorActive()));
getPreference(R.string.pref_connectorECActive).setOnPreferenceChangeListener(this);
setWebsite(R.string.pref_fakekey_ec_website, ECConnector.getInstance().getHost());
getPreference(R.string.preference_screen_ec).setSummary(getServiceSummary(Settings.isECConnectorActive()));
getPreference(R.string.pref_connectorSUActive).setOnPreferenceChangeListener(this);
setWebsite(R.string.pref_fakekey_su_website, GeocachingSuConnector.getInstance().getHost());
getPreference(R.string.preference_screen_su).setSummary(getServiceSummary(Settings.isSUConnectorActive()));
getPreference(R.string.pref_ratingwanted).setOnPreferenceChangeListener(this);
setWebsite(R.string.pref_fakekey_gcvote_website, GCVote.getWebsite());
getPreference(R.string.preference_screen_gcvote).setSummary(getServiceSummary(Settings.isRatingWanted()));
getPreference(R.string.pref_connectorGeokretyActive).setOnPreferenceChangeListener(this);
setWebsite(R.string.pref_fakekey_geokrety_website, "https://geokrety.org");
setWebsite(R.string.pref_fakekey_geokretymap_website, "https://geokretymap.org");
getPreference(R.string.preference_screen_geokrety).setSummary(getServiceSummary(Settings.isGeokretyConnectorActive()));
setWebsite(R.string.pref_fakekey_sendtocgeo_website, "send2.cgeo.org");
getPreference(R.string.preference_screen_sendtocgeo).setSummary(getServiceSummary(Settings.isRegisteredForSend2cgeo()));
}
private void setWebsite(final int preferenceKey, final String urlOrHost) {
final Preference preference = getPreference(preferenceKey);
preference.setOnPreferenceClickListener(new OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(final Preference preference) {
final String url = StringUtils.startsWith(urlOrHost, "http") ? urlOrHost : "http://" + urlOrHost;
ProcessUtils.openUri(url, SettingsActivity.this);
return true;
}
});
}
private static String getServiceSummary(final boolean status) {
return status ? CgeoApplication.getInstance().getString(R.string.settings_service_active) : StringUtils.EMPTY;
}
private static String getKey(final int prefKeyId) {
return CgeoApplication.getInstance().getString(prefKeyId);
}
private Preference getPreference(final int keyId) {
return findPreference(this, getKey(keyId));
}
/**
* Fill the choice list for map sources.
*/
private void initMapSourcePreference() {
final ListPreference pref = (ListPreference) getPreference(R.string.pref_mapsource);
final List<MapSource> mapSources = MapProviderFactory.getMapSources();
final CharSequence[] entries = new CharSequence[mapSources.size()];
final 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 external private cgeo directory.
*/
private void initExtCgeoDirPreference() {
final Preference dataDirPref = getPreference(R.string.pref_fakekey_dataDir);
if (LocalStorage.getAvailableExternalPrivateCgeoDirectories().size() < 2) {
dataDirPref.setEnabled(false);
return;
}
final AtomicLong usedBytes = new AtomicLong();
dataDirPref.setOnPreferenceClickListener(new OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(final Preference preference) {
final ProgressDialog progress = ProgressDialog.show(SettingsActivity.this, getString(R.string.calculate_dataDir_title), getString(R.string.calculate_dataDir), true, false);
AndroidRxUtils.andThenOnUi(Schedulers.io(), new Runnable() {
@Override
public void run() {
// calculate disk usage
usedBytes.set(FileUtils.getSize(LocalStorage.getExternalPrivateCgeoDirectory()));
}
}, new Runnable() {
@Override
public void run() {
progress.dismiss();
showExtCgeoDirChooser(usedBytes.get());
}
});
return true;
}
});
}
/**
* Shows a list of available mount points.
*/
private void showExtCgeoDirChooser(final long usedBytes) {
final List<File> extDirs = LocalStorage.getAvailableExternalPrivateCgeoDirectories();
final String currentExtDir = LocalStorage.getExternalPrivateCgeoDirectory().getAbsolutePath();
final List<CharSequence> directories = new ArrayList<>();
final List<Long> freeSpaces = new ArrayList<>();
int selectedDirIndex = -1;
for (final File dir : extDirs) {
if (StringUtils.equals(currentExtDir, dir.getAbsolutePath())) {
selectedDirIndex = directories.size();
}
final long freeSpace = FileUtils.getFreeDiskSpace(dir);
freeSpaces.add(freeSpace);
directories.add(dir.getAbsolutePath());
}
final AlertDialog.Builder builder = new AlertDialog.Builder(SettingsActivity.this);
builder.setTitle(getString(R.string.settings_title_data_dir_usage, Formatter.formatBytes(usedBytes)));
builder.setSingleChoiceItems(new ArrayAdapter<CharSequence>(SettingsActivity.this,
android.R.layout.simple_list_item_single_choice,
formatDirectoryNames(directories, freeSpaces)) {
@Override
public boolean areAllItemsEnabled() {
return false;
}
@NonNull
@Override
public View getView(final int position, @Nullable final View convertView, @NonNull final ViewGroup parent) {
final View view = super.getView(position, convertView, parent);
view.setEnabled(isEnabled(position));
return view;
}
@Override
public boolean isEnabled(final int position) {
return usedBytes < freeSpaces.get(position);
}
}, selectedDirIndex, new DialogInterface.OnClickListener() {
@Override
public void onClick(final DialogInterface dialog, final int itemId) {
Dialogs.confirm(SettingsActivity.this, R.string.confirm_data_dir_move_title, R.string.confirm_data_dir_move, new DialogInterface.OnClickListener() {
@Override
public void onClick(final DialogInterface dialog, final int which) {
final File dir = extDirs.get(itemId);
if (!StringUtils.equals(currentExtDir, dir.getAbsolutePath())) {
LocalStorage.changeExternalPrivateCgeoDir(SettingsActivity.this, dir.getAbsolutePath());
}
Settings.setExternalPrivateCgeoDirectory(dir.getAbsolutePath());
onPreferenceChange(getPreference(R.string.pref_fakekey_dataDir), dir.getAbsolutePath());
}
});
dialog.dismiss();
}
});
builder.setNegativeButton(string.cancel, new DialogInterface.OnClickListener() {
@Override
public void onClick(final DialogInterface dialog, final int which) {
dialog.cancel();
}
});
builder.create().show();
}
private List<CharSequence> formatDirectoryNames(final List<CharSequence> directories, final List<Long> freeSpaces) {
final List<CharSequence> truncated = Formatter.truncateCommonSubdir(directories);
final List<CharSequence> formatted = new ArrayList<>(truncated.size());
for (int i = 0; i < truncated.size(); i++) {
formatted.add(getString(R.string.settings_data_dir_item, truncated.get(i), Formatter.formatBytes(freeSpaces.get(i))));
}
return formatted;
}
/**
* Fill the choice list for default navigation tools.
*/
private void initDefaultNavigationPreferences() {
final List<NavigationAppsEnum> apps = NavigationAppFactory.getInstalledDefaultNavigationApps();
final CharSequence[] entries = new CharSequence[apps.size()];
final 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);
}
final ListPreference defaultNavigationTool = (ListPreference) getPreference(R.string.pref_defaultNavigationTool);
defaultNavigationTool.setEntries(entries);
defaultNavigationTool.setEntryValues(values);
final ListPreference defaultNavigationTool2 = (ListPreference) getPreference(R.string.pref_defaultNavigationTool2);
defaultNavigationTool2.setEntries(entries);
defaultNavigationTool2.setEntryValues(values);
}
private void initDirChoosers() {
for (final DirChooserType dct : DirChooserType.values()) {
getPreference(dct.keyId).setOnPreferenceClickListener(
new OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(final Preference preference) {
startDirChooser(dct);
return false;
}
});
}
getPreference(R.string.pref_mapDirectory).setOnPreferenceClickListener(
new OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(final Preference preference) {
final Intent intent = new Intent(SettingsActivity.this,
SelectMapfileActivity.class);
startActivityForResult(intent, R.string.pref_mapDirectory);
return false;
}
});
}
/**
* Fire up a directory chooser on click on the preference.
*
* The result can be processed using {@link android.app.Activity#onActivityResult}.
*
* @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(string.ok));
startActivityForResult(dirChooser, dct.requestCode);
} catch (final ActivityNotFoundException ignored) {
// OI file manager not available
final Intent dirChooser = new Intent(this, SimpleDirChooser.class);
dirChooser.putExtra(Intents.EXTRA_START_DIR, startDirectory);
dirChooser.putExtra(SimpleDirChooser.EXTRA_CHOOSE_FOR_WRITING, dct.writeMode);
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)) {
final Preference p = getPreference(dct.keyId);
if (p == null) {
return;
}
Settings.putString(dct.keyId, directory);
p.setSummary(directory);
}
}
private void initBackupButtons() {
final Preference backup = getPreference(R.string.pref_fakekey_preference_backup);
backup.setOnPreferenceClickListener(new OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(final Preference preference) {
DatabaseBackupUtils.createBackup(SettingsActivity.this, new Runnable() {
@Override
public void run() {
onPreferenceChange(getPreference(R.string.pref_fakekey_preference_backup_info), "");
}
});
return true;
}
});
final Preference restore = getPreference(R.string.pref_fakekey_preference_restore);
restore.setOnPreferenceClickListener(new OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(final Preference preference) {
DatabaseBackupUtils.restoreDatabase(SettingsActivity.this);
return true;
}
});
}
private void initMaintenanceButtons() {
final Preference dirMaintenance = getPreference(R.string.pref_fakekey_preference_maintenance_directories);
dirMaintenance.setOnPreferenceClickListener(new OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(final Preference preference) {
// disable the button, as the cleanup runs in background and should not be invoked a second time
preference.setEnabled(false);
final Resources res = getResources();
final SettingsActivity activity = SettingsActivity.this;
final ProgressDialog dialog = ProgressDialog.show(activity, res.getString(R.string.init_maintenance), res.getString(R.string.init_maintenance_directories), true, false);
AndroidRxUtils.andThenOnUi(Schedulers.io(), new Runnable() {
@Override
public void run() {
DataStore.removeObsoleteGeocacheDataDirectories();
}
}, new Runnable() {
@Override
public void run() {
dialog.dismiss();
}
});
return true;
}
});
final Preference memoryDumpPref = getPreference(R.string.pref_memory_dump);
memoryDumpPref
.setOnPreferenceClickListener(new OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(
final Preference preference) {
DebugUtils.createMemoryDump(SettingsActivity.this);
return true;
}
});
}
private static void initDeviceSpecificPreferences() {
// We have to ensure that those preferences are initialized so that devices with specific default values
// will get the appropriate ones.
Settings.setUseHardwareAcceleration(Settings.useHardwareAcceleration());
Settings.setUseGooglePlayServices(Settings.useGooglePlayServices());
}
private static void initUnitPreferences() {
Settings.setUseImperialUnits(Settings.useImperialUnits());
}
private void initDbLocationPreference() {
final Preference p = getPreference(R.string.pref_dbonsdcard);
p.setPersistent(false);
p.setOnPreferenceClickListener(new OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(final Preference preference) {
final boolean oldValue = Settings.isDbOnSDCard();
DataStore.moveDatabase(SettingsActivity.this);
return oldValue != Settings.isDbOnSDCard();
}
});
}
private void initDebugPreference() {
final Preference p = getPreference(R.string.pref_debug);
p.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(final Preference preference, final Object newValue) {
Log.setDebug((Boolean) newValue);
return true;
}
});
}
private void initForceOrientationSensorPreference() {
final Preference p = getPreference(R.string.pref_force_orientation_sensor);
p.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(final Preference preference, final Object newValue) {
final boolean useOrientationSensor = (Boolean) newValue;
Settings.setForceOrientationSensor(useOrientationSensor);
Sensors.getInstance().setupDirectionObservable();
return true;
}
});
p.setEnabled(OrientationProvider.hasOrientationSensor(this) && RotationProvider.hasRotationSensor(this));
}
private void initLanguagePreferences() {
final Preference p = getPreference(R.string.pref_useenglish);
p.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(final Preference preference, final Object newValue) {
setResult(RESTART_NEEDED);
return true;
}
});
}
private void initGeoDirPreferences() {
final Sensors sensors = Sensors.getInstance();
final Preference playServices = getPreference(R.string.pref_googleplayservices);
playServices.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(final Preference preference, final Object newValue) {
sensors.setupGeoDataObservables((Boolean) newValue, Settings.useLowPowerMode());
return true;
}
});
playServices.setEnabled(GooglePlayServices.isAvailable());
getPreference(R.string.pref_lowpowermode).setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(final Preference preference, final Object newValue) {
final boolean useLowPower = (Boolean) newValue;
sensors.setupGeoDataObservables(Settings.useGooglePlayServices(), useLowPower);
sensors.setupDirectionObservable();
return true;
}
});
}
void initBasicMemberPreferences() {
getPreference(R.string.preference_screen_basicmembers)
.setEnabled(!Settings.isGCPremiumMember());
getPreference(R.string.pref_loaddirectionimg)
.setEnabled(!Settings.isGCPremiumMember());
redrawScreen(R.string.preference_screen_services);
}
/**
* Refresh a preference screen. Has no effect when called for a preference, that is not actually a preference
* screen.
*
* @param key
* Key of a preference screen.
*/
private void redrawScreen(final int key) {
final Preference preference = getPreference(key);
redrawScreen(preference);
}
private static void redrawScreen(final Preference preference) {
if (!(preference instanceof PreferenceScreen)) {
return;
}
final PreferenceScreen screen = (PreferenceScreen) preference;
final ListAdapter adapter = screen.getRootAdapter();
if (adapter instanceof BaseAdapter) {
((BaseAdapter) adapter).notifyDataSetChanged();
}
}
private static void initSend2CgeoPreferences() {
Settings.putString(R.string.pref_webDeviceName, Settings.getWebDeviceName());
}
public void setAuthTitle(final int prefKeyId) {
switch (prefKeyId) {
case R.string.pref_fakekey_gc_authorization:
setAuthTitle(prefKeyId, GCConnector.getInstance());
setConnectedUsernameTitle(prefKeyId, GCConnector.getInstance());
break;
case R.string.pref_fakekey_ocde_authorization:
case R.string.pref_fakekey_ocpl_authorization:
case R.string.pref_fakekey_ocnl_authorization:
case R.string.pref_fakekey_ocus_authorization:
case R.string.pref_fakekey_ocro_authorization:
case R.string.pref_fakekey_ocuk_authorization:
final OCPreferenceKeys key = OCPreferenceKeys.getByAuthId(prefKeyId);
if (key != null) {
setOCAuthTitle(key);
setConnectedTitle(prefKeyId, Settings.hasOCAuthorization(key.publicTokenPrefId, key.privateTokenPrefId));
} else {
setConnectedTitle(prefKeyId, false);
}
break;
case R.string.pref_fakekey_ec_authorization:
setAuthTitle(prefKeyId, ECConnector.getInstance());
setConnectedUsernameTitle(prefKeyId, ECConnector.getInstance());
break;
case R.string.pref_fakekey_gcvote_authorization:
setAuthTitle(prefKeyId, GCVote.getInstance());
setConnectedUsernameTitle(prefKeyId, GCVote.getInstance());
break;
case R.string.pref_fakekey_twitter_authorization:
setTwitterAuthTitle();
setConnectedTitle(prefKeyId, Settings.hasTwitterAuthorization());
break;
case R.string.pref_fakekey_geokrety_authorization:
setGeokretyAuthTitle();
setConnectedTitle(prefKeyId, Settings.hasGeokretyAuthorization());
break;
default:
Log.e(String.format(Locale.ENGLISH, "Invalid key %d in SettingsActivity.setTitle()", prefKeyId));
}
}
private void setOCAuthTitle(final OCPreferenceKeys key) {
getPreference(key.authPrefId)
.setTitle(getString(Settings.hasOCAuthorization(key.publicTokenPrefId, key.privateTokenPrefId)
? R.string.settings_reauthorize
: R.string.settings_authorize));
}
private void setTwitterAuthTitle() {
getPreference(R.string.pref_fakekey_twitter_authorization)
.setTitle(getString(Settings.hasTwitterAuthorization()
? R.string.settings_reauthorize
: R.string.settings_authorize));
}
private void setGeokretyAuthTitle() {
getPreference(R.string.pref_fakekey_geokrety_authorization)
.setTitle(getString(Settings.hasGeokretyAuthorization()
? R.string.settings_reauthorize
: R.string.settings_authorize));
}
private void setAuthTitle(final int prefKeyId, @NonNull final ICredentials connector) {
final Credentials credentials = Settings.getCredentials(connector);
getPreference(prefKeyId)
.setTitle(getString(StringUtils.isNotBlank(credentials.getUsernameRaw())
? R.string.settings_reauthorize
: R.string.settings_authorize));
}
private void setConnectedUsernameTitle(final int prefKeyId, @NonNull final ICredentials connector) {
final Credentials credentials = Settings.getCredentials(connector);
getPreference(prefKeyId)
.setSummary(credentials.isValid()
? getString(R.string.auth_connected_as, credentials.getUserName())
: getString(R.string.auth_unconnected));
}
private void setConnectedTitle(final int prefKeyId, final boolean hasToken) {
getPreference(prefKeyId)
.setSummary(getString(hasToken
? R.string.auth_connected
: R.string.auth_unconnected));
}
public static void openForScreen(final int preferenceScreenKey, final Context fromActivity) {
final Intent intent = new Intent(fromActivity, SettingsActivity.class);
intent.putExtra(INTENT_OPEN_SCREEN, preferenceScreenKey);
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 (final DirChooserType dct : DirChooserType.values()) {
if (requestCode == dct.requestCode) {
setChosenDirectory(dct, data);
return;
}
}
switch (requestCode) {
case R.string.pref_mapDirectory:
if (data.hasExtra(Intents.EXTRA_MAP_FILE)) {
final String mapFile = data.getStringExtra(Intents.EXTRA_MAP_FILE);
final File file = new File(mapFile);
if (!file.isDirectory()) {
Settings.setMapFile(mapFile);
if (!Settings.isValidMapFile(Settings.getMapFile())) {
ActivityMixin.showToast(this, R.string.warn_invalid_mapfile);
} else {
// Ensure map source preference is updated accordingly.
// TODO: There should be a better way to find and select the map source for a map file
final Integer mapSourceId = mapFile.hashCode();
final ListPreference mapSource = (ListPreference) getPreference(R.string.pref_mapsource);
mapSource.setValue(mapSourceId.toString());
onPreferenceChange(mapSource, mapSourceId);
}
} else {
Settings.setMapFileDirectory(mapFile);
}
}
initMapSourcePreference();
getPreference(R.string.pref_mapDirectory).setSummary(StringUtils.defaultString(Settings.getMapFileDirectory()));
break;
case R.string.pref_fakekey_dataDir:
getPreference(R.string.pref_fakekey_dataDir).setSummary(Settings.getExternalPrivateCgeoDirectory());
break;
case R.string.pref_fakekey_ocde_authorization:
case R.string.pref_fakekey_ocpl_authorization:
case R.string.pref_fakekey_ocnl_authorization:
case R.string.pref_fakekey_ocus_authorization:
case R.string.pref_fakekey_ocro_authorization:
case R.string.pref_fakekey_ocuk_authorization:
final OCPreferenceKeys key = OCPreferenceKeys.getByAuthId(requestCode);
if (key != null) {
setOCAuthTitle(key);
setConnectedTitle(requestCode, Settings.hasOCAuthorization(key.publicTokenPrefId, key.privateTokenPrefId));
redrawScreen(key.prefScreenId);
} else {
setConnectedTitle(requestCode, false);
}
break;
case R.string.pref_fakekey_gc_authorization:
setAuthTitle(requestCode, GCConnector.getInstance());
setConnectedUsernameTitle(requestCode, GCConnector.getInstance());
redrawScreen(R.string.preference_screen_gc);
initBasicMemberPreferences();
break;
case R.string.pref_fakekey_ec_authorization:
setAuthTitle(requestCode, ECConnector.getInstance());
setConnectedUsernameTitle(requestCode, ECConnector.getInstance());
redrawScreen(R.string.preference_screen_ec);
break;
case R.string.pref_fakekey_gcvote_authorization:
setAuthTitle(requestCode, GCVote.getInstance());
setConnectedUsernameTitle(requestCode, GCVote.getInstance());
redrawScreen(R.string.init_gcvote);
break;
case R.string.pref_fakekey_twitter_authorization:
setTwitterAuthTitle();
setConnectedTitle(requestCode, Settings.hasTwitterAuthorization());
redrawScreen(R.string.preference_screen_twitter);
break;
case R.string.pref_fakekey_geokrety_authorization:
setGeokretyAuthTitle();
setConnectedTitle(requestCode, Settings.hasGeokretyAuthorization());
redrawScreen(R.string.preference_screen_geokrety);
break;
default:
throw new IllegalArgumentException();
}
}
@Override
public boolean onPreferenceChange(final Preference preference, final Object value) {
final PreferenceManager preferenceManager = preference.getPreferenceManager();
final String stringValue = value.toString();
if (isPreference(preference, R.string.pref_mapsource)) {
// reset the cached map source
MapSource mapSource;
try {
final int mapSourceId = Integer.parseInt(stringValue);
mapSource = MapProviderFactory.getMapSource(mapSourceId);
} catch (final NumberFormatException e) {
Log.e("SettingsActivity.onPreferenceChange: bad source id '" + stringValue + "'", e);
mapSource = null;
}
// If there is no corresponding map source (because some map sources were
// removed from the device since) then use the first one available.
if (mapSource == null) {
mapSource = MapProviderFactory.getAnyMapSource();
if (mapSource == null) {
// There are no map source. There is little we can do here, except log an error and
// return to avoid triggering a null pointer exception.
Log.e("SettingsActivity.onPreferenceChange: no map source available");
return true;
}
}
Settings.setMapSource(mapSource);
preference.setSummary(mapSource.getName());
} else if (isPreference(preference, R.string.pref_fakekey_dataDir)) {
preference.setSummary(Settings.getExternalPrivateCgeoDirectory());
} else if (isPreference(preference, R.string.pref_connectorOCActive)
|| isPreference(preference, R.string.pref_connectorOCPLActive)
|| isPreference(preference, R.string.pref_connectorOCNLActive)
|| isPreference(preference, R.string.pref_connectorOCUSActive)
|| isPreference(preference, R.string.pref_connectorOCROActive)
|| isPreference(preference, R.string.pref_connectorOCUKActive)
|| isPreference(preference, R.string.pref_connectorGCActive)
|| isPreference(preference, R.string.pref_connectorECActive)
|| isPreference(preference, R.string.pref_connectorSUActive)) {
// update summary
final boolean boolVal = (Boolean) value;
final String summary = getServiceSummary(boolVal);
if (OCPreferenceKeys.isOCPreference(preference.getKey())) {
final OCPreferenceKeys prefKey = OCPreferenceKeys.getByKey(preference.getKey());
preference.getPreferenceManager().findPreference(getKey(prefKey.prefScreenId)).setSummary(summary);
} else if (isPreference(preference, R.string.pref_connectorGCActive)) {
preference.getPreferenceManager().findPreference(getKey(R.string.preference_screen_gc)).setSummary(summary);
} else if (isPreference(preference, R.string.pref_connectorECActive)) {
preference.getPreferenceManager().findPreference(getKey(R.string.preference_screen_ec)).setSummary(summary);
} else if (isPreference(preference, R.string.pref_connectorSUActive)) {
preference.getPreferenceManager().findPreference(getKey(R.string.preference_screen_su)).setSummary(summary);
}
redrawScreen(preference.getPreferenceManager().findPreference(getKey(R.string.preference_screen_services)));
// reset log-in status if connector activation was changed
ConnectorFactory.forceRelog();
} else if (preference instanceof ListPreference) {
// For list preferences, look up the correct display value in
// the preference's 'entries' list.
final ListPreference listPreference = (ListPreference) preference;
final int index = listPreference.findIndexOfValue(stringValue);
// Set the summary to reflect the new value.
preference.setSummary(
index >= 0
? listPreference.getEntries()[index]
: null);
} else if (isPreference(preference, R.string.pref_fakekey_preference_backup_info)) {
final String text;
if (DatabaseBackupUtils.hasBackup()) {
text = preference.getContext().getString(R.string.init_backup_last) + " "
+ DatabaseBackupUtils.getBackupDateTime();
} else {
text = preference.getContext().getString(R.string.init_backup_last_no);
}
preference.setSummary(text);
} else if (isPreference(preference, R.string.pref_ratingwanted)) {
preferenceManager.findPreference(getKey(R.string.preference_screen_gcvote)).setSummary(getServiceSummary((Boolean) value));
redrawScreen(preferenceManager.findPreference(getKey(R.string.preference_screen_services)));
} else if (isPreference(preference, R.string.pref_connectorGeokretyActive)) {
preferenceManager.findPreference(getKey(R.string.preference_screen_geokrety)).setSummary(getServiceSummary((Boolean) value));
redrawScreen(preferenceManager.findPreference(getKey(R.string.preference_screen_services)));
} 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.
*/
private void bindSummaryToValue(final Preference preference, final Object value) {
// Set the listener to watch for value changes.
if (preference == null) {
return;
}
preference.setOnPreferenceChangeListener(this);
// Trigger the listener immediately with the preference's
// current value.
onPreferenceChange(preference, value);
}
/**
* auto-care for the summary of the preference of string type with this key
*/
private void bindSummaryToStringValue(final int key) {
final Preference pref = getPreference(key);
if (pref == null) {
return;
}
final String value = PreferenceManager
.getDefaultSharedPreferences(pref.getContext())
.getString(pref.getKey(), "");
bindSummaryToValue(pref, value);
}
private void bindGeocachingUserToGCVoteuser() {
if (!Settings.hasGCCredentials()) {
return;
}
final String value = Settings.getGcCredentials().getUserName();
getPreference(R.string.pref_fakekey_gcvote_authorization).setSummary(value);
final Preference prefvote = getPreference(R.string.pref_user_vote);
bindSummaryToValue(prefvote, value);
}
@SuppressWarnings("deprecation")
private static Preference findPreference(final PreferenceActivity preferenceActivity, final CharSequence key) {
return preferenceActivity.findPreference(key);
}
@SuppressWarnings("deprecation")
private static void addPreferencesFromResource(final PreferenceActivity preferenceActivity, @AnyRes final int preferencesResId) {
preferenceActivity.addPreferencesFromResource(preferencesResId);
}
@SuppressWarnings("deprecation")
@Override
public void setPreferenceScreen(final PreferenceScreen preferenceScreen) {
// TODO replace with fragment based code
super.setPreferenceScreen(preferenceScreen);
}
@SuppressWarnings("deprecation")
@Override
public PreferenceManager getPreferenceManager() {
// TODO replace with fragment based code
return super.getPreferenceManager();
}
private static boolean isPreference(final Preference preference, final int preferenceKeyId) {
return getKey(preferenceKeyId).equals(preference.getKey());
}
}