mirror of
https://codeberg.org/OpenTracksApp/OpenTracks.git
synced 2026-10-02 17:43:06 +02:00
1e518a4c35
Fixes #98.
305 lines
14 KiB
Java
305 lines
14 KiB
Java
package de.dennisguse.opentracks.settings;
|
|
|
|
import android.content.Intent;
|
|
import android.content.SharedPreferences;
|
|
import android.os.Bundle;
|
|
import android.util.Log;
|
|
import android.view.View;
|
|
import android.widget.Toast;
|
|
|
|
import androidx.appcompat.app.AlertDialog;
|
|
import androidx.appcompat.widget.Toolbar;
|
|
import androidx.documentfile.provider.DocumentFile;
|
|
import androidx.fragment.app.DialogFragment;
|
|
import androidx.preference.EditTextPreference;
|
|
import androidx.preference.ListPreference;
|
|
import androidx.preference.Preference;
|
|
import androidx.preference.PreferenceFragmentCompat;
|
|
|
|
import java.util.Locale;
|
|
|
|
import de.dennisguse.opentracks.AbstractActivity;
|
|
import de.dennisguse.opentracks.R;
|
|
import de.dennisguse.opentracks.content.data.Track;
|
|
import de.dennisguse.opentracks.fragments.ChooseActivityTypeDialogFragment;
|
|
import de.dennisguse.opentracks.io.file.TrackFileFormat;
|
|
import de.dennisguse.opentracks.services.TrackRecordingService;
|
|
import de.dennisguse.opentracks.services.TrackRecordingServiceConnection;
|
|
import de.dennisguse.opentracks.services.TrackRecordingServiceStatus;
|
|
import de.dennisguse.opentracks.settings.bluetooth.BluetoothLeCyclingCadenceAndSpeedPreference;
|
|
import de.dennisguse.opentracks.settings.bluetooth.BluetoothLeCyclingPowerPreference;
|
|
import de.dennisguse.opentracks.settings.bluetooth.BluetoothLeHeartRatePreference;
|
|
import de.dennisguse.opentracks.settings.bluetooth.BluetoothLeSensorPreference;
|
|
import de.dennisguse.opentracks.util.ActivityUtils;
|
|
import de.dennisguse.opentracks.util.BluetoothUtils;
|
|
import de.dennisguse.opentracks.util.HackUtils;
|
|
import de.dennisguse.opentracks.util.PreferencesUtils;
|
|
import de.dennisguse.opentracks.util.StringUtils;
|
|
|
|
public class SettingsActivity extends AbstractActivity implements ChooseActivityTypeDialogFragment.ChooseActivityTypeCaller, ResetDialogPreference.ResetCallback {
|
|
|
|
private static final String TAG = SettingsActivity.class.getSimpleName();
|
|
public static final String EXTRAS_CHECK_EXPORT_DIRECTORY = "Check Export Directory";
|
|
|
|
private PrefsFragment prefsFragment;
|
|
private boolean checkExportDirectory = false;
|
|
|
|
@Override
|
|
protected void onCreate(Bundle savedInstanceState) {
|
|
super.onCreate(savedInstanceState);
|
|
|
|
Intent intent = getIntent();
|
|
if (intent != null && intent.hasExtra(EXTRAS_CHECK_EXPORT_DIRECTORY)) {
|
|
checkExportDirectory = true;
|
|
}
|
|
onReset();
|
|
}
|
|
|
|
@Override
|
|
protected View getRootView() {
|
|
return getLayoutInflater().inflate(R.layout.settings, null);
|
|
}
|
|
|
|
@Override
|
|
protected void setupActionBarBack(Toolbar toolbar) {
|
|
super.setupActionBarBack(toolbar);
|
|
toolbar.setTitle(R.string.menu_settings);
|
|
}
|
|
|
|
@Override
|
|
protected void onResume() {
|
|
if (checkExportDirectory) {
|
|
checkExportDirectory = false;
|
|
new AlertDialog.Builder(this)
|
|
.setIcon(R.drawable.ic_logo_24dp)
|
|
.setTitle(R.string.app_name)
|
|
.setMessage(R.string.export_error_post_workout)
|
|
.setNeutralButton(R.string.generic_ok, null)
|
|
.create()
|
|
.show();
|
|
}
|
|
|
|
super.onResume();
|
|
}
|
|
|
|
@Override
|
|
public void onChooseActivityTypeDone(String iconValue) {
|
|
prefsFragment.setDefaultActivity(iconValue);
|
|
}
|
|
|
|
@Override
|
|
public void onReset() {
|
|
prefsFragment = new PrefsFragment();
|
|
getSupportFragmentManager().beginTransaction().replace(R.id.settings_fragment, prefsFragment).commit();
|
|
}
|
|
|
|
public static class PrefsFragment extends PreferenceFragmentCompat implements TrackRecordingServiceStatus.Listener {
|
|
|
|
private SharedPreferences sharedPreferences;
|
|
|
|
private final SharedPreferences.OnSharedPreferenceChangeListener sharedPreferenceChangeListener = (sharedPreferences, key) -> {
|
|
if (PreferencesUtils.isKey(getActivity(), R.string.stats_units_key, key)) {
|
|
getActivity().runOnUiThread(this::updateUnits);
|
|
}
|
|
if (PreferencesUtils.isKey(getActivity(), R.string.night_mode_key, key)) {
|
|
getActivity().runOnUiThread(() -> ActivityUtils.applyNightMode(sharedPreferences, getContext()));
|
|
}
|
|
};
|
|
|
|
private TrackRecordingServiceConnection trackRecordingServiceConnection;
|
|
private boolean isRecording;
|
|
|
|
private final Runnable bindServiceCallback = new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
TrackRecordingService service = trackRecordingServiceConnection.getServiceIfBound();
|
|
if (service != null) {
|
|
service.addListener(PrefsFragment.this);
|
|
}
|
|
}
|
|
};
|
|
|
|
// Used to forward update from ChooseActivityTypeDialogFragment; TODO Could be replaced with LiveData.
|
|
private ActivityTypePreference.ActivityPreferenceDialog activityPreferenceDialog;
|
|
|
|
@Override
|
|
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
|
|
sharedPreferences = PreferencesUtils.getSharedPreferences(getContext());
|
|
|
|
trackRecordingServiceConnection = new TrackRecordingServiceConnection(bindServiceCallback);
|
|
|
|
try {
|
|
setPreferencesFromResource(R.xml.settings, rootKey);
|
|
} catch (ClassCastException e) {
|
|
// Some sharedPreference is broken: delete all and reset them; it is just a last resort...
|
|
Toast.makeText(getContext(), R.string.settings_error_initial_values_restored, Toast.LENGTH_LONG).show();
|
|
PreferencesUtils.resetPreferences(getContext(), true);
|
|
|
|
setPreferencesFromResource(R.xml.settings, rootKey);
|
|
}
|
|
|
|
setExportTrackFileFormatOptions();
|
|
setWheelCircumferenceInputFilter();
|
|
|
|
Preference instantExportDirectoryPreference = findPreference(getString(R.string.settings_default_export_directory_key));
|
|
instantExportDirectoryPreference.setSummaryProvider(preference -> {
|
|
DocumentFile directory = PreferencesUtils.getDefaultExportDirectoryUri(sharedPreferences, getContext());
|
|
//Use same value for not set as Androidx ListPreference and EditTextPreference
|
|
return directory != null ? directory.getName() : getString(R.string.not_set);
|
|
});
|
|
}
|
|
|
|
@Override
|
|
public void onResume() {
|
|
super.onResume();
|
|
|
|
trackRecordingServiceConnection.bind(getContext());
|
|
|
|
sharedPreferences.registerOnSharedPreferenceChangeListener(sharedPreferenceChangeListener);
|
|
sharedPreferenceChangeListener.onSharedPreferenceChanged(sharedPreferences, null);
|
|
|
|
updateUnits();
|
|
updatePrefsDependOnRecording();
|
|
updateBluetooth();
|
|
updatePostWorkoutExport();
|
|
}
|
|
|
|
private void updatePostWorkoutExport() {
|
|
Preference instantExportEnabledPreference = findPreference(getString(R.string.post_workout_export_enabled_key));
|
|
instantExportEnabledPreference.setEnabled(PreferencesUtils.isDefaultExportDirectoryUri(sharedPreferences, getContext()));
|
|
}
|
|
|
|
@Override
|
|
public void onPause() {
|
|
super.onPause();
|
|
sharedPreferences.unregisterOnSharedPreferenceChangeListener(sharedPreferenceChangeListener);
|
|
}
|
|
|
|
@Override
|
|
public void onDisplayPreferenceDialog(Preference preference) {
|
|
DialogFragment dialogFragment = null;
|
|
if (preference instanceof ResetDialogPreference) {
|
|
dialogFragment = ResetDialogPreference.ResetPreferenceDialog.newInstance(preference.getKey());
|
|
} else if (preference instanceof ActivityTypePreference) {
|
|
activityPreferenceDialog = ActivityTypePreference.ActivityPreferenceDialog.newInstance(preference.getKey());
|
|
dialogFragment = activityPreferenceDialog;
|
|
} else if (preference instanceof BluetoothLeHeartRatePreference) {
|
|
dialogFragment = BluetoothLeSensorPreference.BluetoothLeSensorPreferenceDialog.newInstance(preference.getKey(), BluetoothUtils.HEART_RATE_SUPPORTING_DEVICES);
|
|
} else if (preference instanceof BluetoothLeCyclingCadenceAndSpeedPreference) {
|
|
dialogFragment = BluetoothLeSensorPreference.BluetoothLeSensorPreferenceDialog.newInstance(preference.getKey(), BluetoothUtils.CYCLING_SPEED_CADENCE_SERVICE_UUID);
|
|
} else if (preference instanceof BluetoothLeCyclingPowerPreference) {
|
|
dialogFragment = BluetoothLeSensorPreference.BluetoothLeSensorPreferenceDialog.newInstance(preference.getKey(), BluetoothUtils.CYCLING_POWER_UUID);
|
|
}
|
|
|
|
if (dialogFragment != null) {
|
|
dialogFragment.setTargetFragment(this, 0);
|
|
dialogFragment.show(getParentFragmentManager(), getClass().getSimpleName());
|
|
return;
|
|
}
|
|
|
|
super.onDisplayPreferenceDialog(preference);
|
|
}
|
|
|
|
@Override
|
|
public void onDestroy() {
|
|
super.onDestroy();
|
|
trackRecordingServiceConnection.unbind(getContext());
|
|
sharedPreferences = null;
|
|
}
|
|
|
|
public void setDefaultActivity(String iconValue) {
|
|
if (activityPreferenceDialog != null) {
|
|
activityPreferenceDialog.updateUI(iconValue);
|
|
}
|
|
}
|
|
|
|
private void updatePrefsDependOnRecording() {
|
|
Preference resetPreference = findPreference(getString(R.string.settings_reset_key));
|
|
Preference importPreference = findPreference(getString(R.string.settings_import));
|
|
Preference exportPreference = findPreference(getString(R.string.settings_export));
|
|
|
|
resetPreference.setSummary(isRecording ? getString(R.string.settings_not_while_recording) : "");
|
|
importPreference.setSummary(isRecording ? getString(R.string.settings_not_while_recording) : "");
|
|
exportPreference.setSummary(isRecording ? getString(R.string.settings_not_while_recording) : "");
|
|
|
|
resetPreference.setEnabled(!isRecording);
|
|
importPreference.setEnabled(!isRecording);
|
|
exportPreference.setEnabled(!isRecording);
|
|
}
|
|
|
|
private void updateBluetooth() {
|
|
// Disable Bluetooth preference if device does not have Bluetooth
|
|
BluetoothLeSensorPreference bluetoothPreference = findPreference(getString(R.string.settings_sensor_bluetooth_heart_rate_key));
|
|
bluetoothPreference.setVisible(BluetoothUtils.hasBluetooth(getContext()));
|
|
}
|
|
|
|
private void updateUnits() {
|
|
boolean metricUnits = PreferencesUtils.isMetricUnits(sharedPreferences, getActivity());
|
|
|
|
ListPreference voiceFrequency = findPreference(getString(R.string.voice_frequency_key));
|
|
voiceFrequency.setEntries(StringUtils.getFrequencyOptions(getActivity(), metricUnits));
|
|
|
|
ListPreference minRecordingInterval = findPreference(getString(R.string.min_recording_interval_key));
|
|
minRecordingInterval.setEntries(PreferenceHelper.getMinRecordingIntervalEntries(getActivity()));
|
|
|
|
ListPreference recordingDistanceInterval = findPreference(getString(R.string.recording_distance_interval_key));
|
|
recordingDistanceInterval.setEntries(PreferenceHelper.getRecordingDistanceIntervalEntries(getActivity(), metricUnits));
|
|
|
|
ListPreference maxRecordingDistance = findPreference(getString(R.string.max_recording_distance_key));
|
|
maxRecordingDistance.setEntries(PreferenceHelper.getMaxRecordingDistanceEntries(getActivity(), metricUnits));
|
|
|
|
ListPreference recordingGpsAccuracy = findPreference(getString(R.string.recording_gps_accuracy_key));
|
|
recordingGpsAccuracy.setEntries(PreferenceHelper.getRecordingGpsAccuracyEntries(getActivity(), metricUnits));
|
|
|
|
ListPreference statsRatePreferences = findPreference(getString(R.string.stats_rate_key));
|
|
String[] entries = getResources().getStringArray(metricUnits ? R.array.stats_rate_metric_options : R.array.stats_rate_imperial_options);
|
|
statsRatePreferences.setEntries(entries);
|
|
|
|
HackUtils.invalidatePreference(statsRatePreferences);
|
|
}
|
|
|
|
|
|
private void setExportTrackFileFormatOptions() {
|
|
final TrackFileFormat[] trackFileFormats = {TrackFileFormat.KMZ_WITH_TRACKDETAIL_AND_SENSORDATA_AND_PICTURES, TrackFileFormat.KMZ_WITH_TRACKDETAIL_AND_SENSORDATA, TrackFileFormat.KML_WITH_TRACKDETAIL_AND_SENSORDATA, TrackFileFormat.GPX};
|
|
String[] entries = new String[trackFileFormats.length];
|
|
String[] entryValues = new String[trackFileFormats.length];
|
|
|
|
for (int i = 0; i < entries.length; i++) {
|
|
TrackFileFormat trackFileFormat = trackFileFormats[i];
|
|
String trackFileFormatUpperCase = trackFileFormat.getExtension().toUpperCase(Locale.US); //ASCII upper case
|
|
int photoMessageId = trackFileFormat.includesPhotos() ? R.string.export_with_photos : R.string.export_without_photos;
|
|
entries[i] = String.format("%s (%s)", trackFileFormatUpperCase, getString(photoMessageId));
|
|
entryValues[i] = trackFileFormat.name();
|
|
}
|
|
|
|
ListPreference listPreference = findPreference(getString(R.string.export_trackfileformat_key));
|
|
listPreference.setEntries(entries);
|
|
listPreference.setEntryValues(entryValues);
|
|
}
|
|
|
|
private void setWheelCircumferenceInputFilter() {
|
|
EditTextPreference wheelPreference = findPreference(getString(R.string.settings_sensor_bluetooth_cycling_speed_wheel_circumference_key));
|
|
wheelPreference.setOnPreferenceChangeListener((preference, newValue) -> {
|
|
if (newValue instanceof String) {
|
|
try {
|
|
int newValueInt = Integer.parseInt((String) newValue);
|
|
return newValueInt > 500 && newValueInt < 4000;
|
|
} catch (NumberFormatException e) {
|
|
Log.w(TAG, "Entered string is no number.");
|
|
}
|
|
}
|
|
return false;
|
|
});
|
|
}
|
|
|
|
@Override
|
|
public void onTrackRecordingId(Track.Id trackId) {
|
|
if (trackId != null && !isRecording && isAdded()) {
|
|
isRecording = true;
|
|
updatePrefsDependOnRecording();
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|