/** Copyright 2015 Tim Engler, Rareventure LLC This file is part of Tiny Travel Tracker. Tiny Travel Tracker is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Tiny Travel Tracker is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Tiny Travel Tracker. If not, see <http://www.gnu.org/licenses/>. */ package com.rareventure.gps2.reviewer; import android.app.Dialog; import android.content.DialogInterface; import android.content.DialogInterface.OnDismissListener; import android.content.Intent; import android.os.Bundle; import android.preference.CheckBoxPreference; import android.preference.Preference; import android.preference.Preference.OnPreferenceChangeListener; import android.preference.Preference.OnPreferenceClickListener; import android.preference.PreferenceCategory; import android.preference.PreferenceScreen; import android.view.Menu; import android.view.MenuItem; import android.view.ViewTreeObserver; import android.view.ViewTreeObserver.OnGlobalLayoutListener; import com.rareventure.android.SeekBarDialogPreference; import com.rareventure.android.widget.SeekBarWithText; import com.rareventure.gps2.GTG; import com.rareventure.gps2.GTG.GTGAction; import com.rareventure.gps2.GTGPreferenceActivity; import com.rareventure.gps2.GpsTrailerCrypt; import com.rareventure.gps2.GpsTrailerGpsStrategy; import com.rareventure.gps2.GpsTrailerService; import com.rareventure.gps2.R; import com.rareventure.gps2.gpx.CreateGpxBackup; import com.rareventure.gps2.gpx.RestoreGpxBackup; import com.rareventure.gps2.reviewer.map.OsmMapGpsTrailerReviewerMapActivity; import java.util.Arrays; public class SettingsActivity extends GTGPreferenceActivity implements OnPreferenceChangeListener, OnPreferenceClickListener, OnDismissListener { private final Runnable SAVE_PREFS_AND_RESTART_COLLECTOR = new Runnable() { public void run() { GTG.savePreferences(SettingsActivity.this); runOnUiThread(new Runnable () { public void run() { //we need to restart the service because its preferences changed stopService(new Intent(SettingsActivity.this, GpsTrailerService.class)); startService(new Intent(SettingsActivity.this, GpsTrailerService.class)); } }); } }; private CheckBoxPreference isCollectData; private CheckBoxPreference enablePassword; private Preference changePassword; private SeekBarDialogPreference percTimeGpsOn; private SeekBarDialogPreference minBatteryLife; private SeekBarDialogPreference passwordTimeout; private CheckBoxPreference useMetricUnits; private CheckBoxPreference enableToolTips; private PreferenceScreen createBackupFilePref; private PreferenceScreen restoreBackupFilePref; private PreferenceScreen aboutPref; private PreferenceScreen colorblindSettings; private CheckBoxPreference allowErrorReporting; private SeekBarDialogPreference mapFontSize; private static final String[] passwordTimeoutStrs = { "Off" , "30 seconds", "1 minute", "3 minutes", "5 minutes", "10 minutes", "15 minutes", "30 minutes", "1 hour"}; private static final long[] passwordTimeoutValues = { 0 , 30*1000, 60*1000, 180*1000, 300 * 1000, 10 * 60 * 1000, 15 * 60 * 1000, 30 * 60 * 1000, 60 * 60 * 1000}; private CheckBoxPreference writeGpsWakeLockDebugFile; @Override public void doOnCreate(Bundle savedInstanceState) { super.doOnCreate(savedInstanceState); //we do this programatically because we have some dialog preferences //that can't easily be created using xml createPreferenceHierarchy(); } private void createPreferenceHierarchy() { PreferenceScreen root = getPreferenceManager().createPreferenceScreen(this); this.setPreferenceScreen(root); isCollectData = new CheckBoxPreference(this); isCollectData.setTitle(R.string.collect_gps_data); isCollectData.setSummary(R.string.collect_gps_data_desc); root.addPreference(isCollectData); isCollectData.setOnPreferenceClickListener(this); percTimeGpsOn = new SeekBarDialogPreference(this, getText(R.string.title_perc_time_gps_on), getText(R.string.desc_perc_time_gps_on), getResources().getInteger(R.dimen.perc_time_gps_on_min_value), getResources().getInteger(R.dimen.perc_time_gps_on_max_value), getResources().getInteger(R.dimen.perc_time_gps_on_steps), getResources().getInteger(R.dimen.perc_time_gps_on_log_scale), getText(R.string.seekbar_perc_printf_format).toString(), null); percTimeGpsOn.setOnPreferenceChangeListener(this); root.addPreference(percTimeGpsOn); minBatteryLife = new SeekBarDialogPreference(this, getText(R.string.title_min_battery_life_perc), getText(R.string.desc_min_battery_life_perc), getResources().getInteger(R.dimen.min_battery_level_min_value), getResources().getInteger(R.dimen.min_battery_level_max_value), getResources().getInteger(R.dimen.min_battery_level_steps), getResources().getInteger(R.dimen.min_battery_level_log_scale), getText(R.string.seekbar_perc_printf_format).toString(), null); minBatteryLife.setOnPreferenceChangeListener(this); root.addPreference(minBatteryLife); enableToolTips = new CheckBoxPreference(this); enableToolTips.setTitle(R.string.enable_tooltips); enableToolTips.setKey("enable_tooltips"); root.addPreference(enableToolTips); enableToolTips.setOnPreferenceClickListener(this); useMetricUnits = new CheckBoxPreference(this); useMetricUnits.setTitle(R.string.use_metric_units); useMetricUnits.setChecked(GTG.prefs.useMetric); root.addPreference(useMetricUnits); //note that we can't use setIntent() for these preferences, since that would // be interpreted as an outside action causing us to lose the password is set flag colorblindSettings = getPreferenceManager().createPreferenceScreen(this); // screenPref.setKey("screen_preference"); // colorblindSettings.setIntent(new Intent(this, ChooseColorsScreen.class)); colorblindSettings.setTitle(R.string.colorblind_title); colorblindSettings.setSummary(R.string.colorblind_summary); colorblindSettings.setOnPreferenceClickListener(this); root.addPreference(colorblindSettings); mapFontSize = new SeekBarDialogPreference(this, getText(R.string.title_map_font_size), getText(R.string.desc_map_font_size), getResources().getInteger(R.dimen.map_font_size_min_value), getResources().getInteger(R.dimen.map_font_size_max_value), getResources().getInteger(R.dimen.map_font_size_steps), getResources().getInteger(R.dimen.map_font_size_log_scale), "%1.0f", null); mapFontSize.setOnPreferenceChangeListener(this); root.addPreference(mapFontSize); enablePassword = new CheckBoxPreference(this); enablePassword.setTitle(R.string.enable_password); enablePassword.setKey("enable_password"); root.addPreference(enablePassword); enablePassword.setOnPreferenceClickListener(this); changePassword = new Preference(this); changePassword.setTitle(R.string.change_password); root.addPreference(changePassword); changePassword.setDependency("enable_password"); changePassword.setOnPreferenceClickListener(this); passwordTimeout = new SeekBarDialogPreference(this, getText(R.string.title_password_timeout), getText(R.string.desc_password_timeout), 0, passwordTimeoutStrs.length-1, passwordTimeoutStrs.length, 0, null, new SeekBarWithText.CustomUpdateTextView() { @Override public String updateText(float value) { return passwordTimeoutStrs[(int)value]; } }); passwordTimeout.setOnPreferenceChangeListener(this); root.addPreference(passwordTimeout); createBackupFilePref = getPreferenceManager().createPreferenceScreen(this); createBackupFilePref.setTitle(R.string.create_backup_pref); root.addPreference(createBackupFilePref); createBackupFilePref.setOnPreferenceClickListener(this); restoreBackupFilePref = getPreferenceManager().createPreferenceScreen(this); restoreBackupFilePref.setTitle(R.string.restore_backup_pref); root.addPreference(restoreBackupFilePref); restoreBackupFilePref.setOnPreferenceClickListener(this); allowErrorReporting = new CheckBoxPreference(this); allowErrorReporting.setTitle(R.string.allow_error_reporting); allowErrorReporting.setSummary(R.string.allow_error_reporting_summary); allowErrorReporting.setChecked(GTG.isAcraEnabled(this)); root.addPreference(allowErrorReporting); aboutPref = getPreferenceManager().createPreferenceScreen(this); aboutPref.setOnPreferenceClickListener(this); aboutPref.setTitle(R.string.about); root.addPreference(aboutPref); PreferenceCategory advancedCategory = new PreferenceCategory(this); advancedCategory.setTitle("Advanced"); root.addPreference(advancedCategory); writeGpsWakeLockDebugFile = new CheckBoxPreference(this); writeGpsWakeLockDebugFile.setTitle(R.string.write_to_gps_wake_lock_log); writeGpsWakeLockDebugFile.setSummary( String.format(getString(R.string.write_to_gps_wake_lock_log_summary), getString(R.string.gps_wake_lock_filename))); writeGpsWakeLockDebugFile.setChecked(GTG.prefs.writeGpsWakeLockDebug); writeGpsWakeLockDebugFile.setOnPreferenceClickListener(this); advancedCategory.addPreference(writeGpsWakeLockDebugFile); } @Override public boolean onPrepareOptionsMenu(Menu menu) { menu.clear(); menu.add(R.string.go_to_main); return super.onPrepareOptionsMenu(menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { GTG.cacheCreatorLock.registerReadingThread(); try { if(item.getTitle().equals(getText(R.string.go_to_main))) { startInternalActivity(new Intent(this, OsmMapGpsTrailerReviewerMapActivity.class)); finish(); return true; } return super.onOptionsItemSelected(item); } finally { GTG.cacheCreatorLock.unregisterReadingThread(); } } @Override public void doOnResume() { super.doOnResume(); enablePassword.setChecked(!GpsTrailerCrypt.prefs.isNoPassword); isCollectData.setChecked(GTG.prefs.isCollectData); percTimeGpsOn.setValue(GpsTrailerGpsStrategy.prefs.batteryGpsOnTimePercentage * 100); minBatteryLife.setValue(GTG.prefs.minBatteryPerc*100); enableToolTips.setChecked(OsmMapGpsTrailerReviewerMapActivity.prefs.enableToolTips); mapFontSize.setValue(OsmMapGpsTrailerReviewerMapActivity.prefs.panelScale); passwordTimeout.setValue(getPasswordTimeoutFromMS(GTG.prefs.passwordTimeoutMS)); passwordTimeout.setEnabled(enablePassword.isChecked()); //co: we no longer allow access to application after expiry (so we can justify not // serving tiles without a valid license) // if(GTG.isTrialPeriodExpired()) // { // isCollectData.setEnabled(false); // isCollectData.setChecked(false); // } if(GTG.lastSuccessfulAction == GTGAction.TOOL_TIP_CLICKED) { GTG.lastSuccessfulAction = null; //scroll done to tool tip option ViewTreeObserver vto = getListView().getViewTreeObserver(); vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() { @Override public void onGlobalLayout() { PreferenceScreen screen = getPreferenceScreen(); int i; for(i = 0; i < screen.getPreferenceCount(); i++) { Preference p = screen.getPreference(i); if(p == enableToolTips) break; } getListView().setSelection(i); getListView().getViewTreeObserver().removeGlobalOnLayoutListener(this); } }); } } private float getPasswordTimeoutFromMS(long passwordTimeoutMS) { int res = Arrays.binarySearch(passwordTimeoutValues, passwordTimeoutMS); if(res >= 0) return res; return 0; } private void savePrefs() { //note, everything else (passwords, is collect gps) is saved immediately if(allowErrorReporting.isChecked() != GTG.isAcraEnabled(this)) { GTG.enableAcra(this, allowErrorReporting.isChecked()); } if(percTimeGpsOn.getValue() != GpsTrailerGpsStrategy.prefs.batteryGpsOnTimePercentage*100 || minBatteryLife.getValue() != GTG.prefs.minBatteryPerc*100) { GTG.prefs.useMetric = useMetricUnits.isChecked(); GTG.runBackgroundTask(SAVE_PREFS_AND_RESTART_COLLECTOR); } else if (GTG.prefs.useMetric != useMetricUnits.isChecked() || OsmMapGpsTrailerReviewerMapActivity.prefs.enableToolTips != enableToolTips.isChecked()) { GTG.prefs.useMetric = useMetricUnits.isChecked(); OsmMapGpsTrailerReviewerMapActivity.prefs.enableToolTips = enableToolTips.isChecked(); GTG.savePreferences(SettingsActivity.this); } } @Override public void doOnPause(boolean doOnResumeCalled) { super.doOnPause(doOnResumeCalled); if(!doOnResumeCalled) return; savePrefs(); } @Override public boolean onPreferenceChange(Preference preference, Object newValue) { if(preference == minBatteryLife) { GTG.prefs.minBatteryPerc = minBatteryLife.getValue()/100; GTG.runBackgroundTask(SAVE_PREFS_AND_RESTART_COLLECTOR); } else if(preference == percTimeGpsOn) { GpsTrailerGpsStrategy.prefs.batteryGpsOnTimePercentage = percTimeGpsOn.getValue()/100; GTG.runBackgroundTask(SAVE_PREFS_AND_RESTART_COLLECTOR); } else if(preference == mapFontSize) { OsmMapGpsTrailerReviewerMapActivity.prefs.panelScale = (int)(mapFontSize.getValue()+.5); GTG.savePreferences(SettingsActivity.this); } else if(preference == passwordTimeout) { GTG.prefs.passwordTimeoutMS = passwordTimeoutValues[(int)(passwordTimeout.getValue())]; GTG.savePreferences(SettingsActivity.this); } return false; } @Override protected Dialog onCreateDialog(int id) { Dialog dialog; if(id == 0 || id == 1) dialog = new PasswordDialog(this, GpsTrailerCrypt.prefs.isNoPassword); else if(id == 2 || id == 3) dialog = new PasswordDialog(this, true); else return super.onCreateDialog(id); dialog.setOnDismissListener(this); return dialog; } @Override public void onDismiss(DialogInterface dialog) { enablePassword.setChecked(!GpsTrailerCrypt.prefs.isNoPassword); passwordTimeout.setEnabled(enablePassword.isChecked()); } @Override public boolean onPreferenceClick(Preference preference) { if(preference == enablePassword) { if(enablePassword.isChecked()) showDialog(0); else showDialog(1); } else if(preference == changePassword) { if(GpsTrailerCrypt.prefs.isNoPassword) showDialog(2); else showDialog(3); } else if(preference == isCollectData) { GTG.prefs.isCollectData = isCollectData.isChecked(); GTG.runBackgroundTask(SAVE_PREFS_AND_RESTART_COLLECTOR); } else if(preference == writeGpsWakeLockDebugFile) { GTG.prefs.writeGpsWakeLockDebug = writeGpsWakeLockDebugFile.isChecked(); GTG.runBackgroundTask(SAVE_PREFS_AND_RESTART_COLLECTOR); } else if(preference == createBackupFilePref) { startInternalActivity(new Intent(this, CreateGpxBackup.class)); } else if(preference == restoreBackupFilePref) { //we don't require the backstack, because NOT_IN_RESTORE Requirement is //required by most pages, except that it can't be required for RestoreGpxBackup startInternalActivity(new Intent(this, RestoreGpxBackup.class), false); } else if(preference == colorblindSettings) startInternalActivity(new Intent(this, ChooseColorsScreen.class)); else if(preference == aboutPref) startInternalActivity(new Intent(this, AboutScreen.class)); else return false; return true; } @Override public int getRequirements() { return GTG.REQUIREMENTS_FULL_PASSWORD_PROTECTED_UI; } }