From c93e5ca1a6ab793ef2c625cca4ca6b58c801c5fd Mon Sep 17 00:00:00 2001 From: Dennis Guse Date: Thu, 19 Sep 2019 18:37:26 +0200 Subject: [PATCH] Settings: moved to Androidx Compat and use one screen only. --- build.gradle | 1 + .../en-US/changelogs/next_release.txt | 4 +- .../opentracks/util/StringUtilsTest.java | 5 +- src/main/AndroidManifest.xml | 5 - .../opentracks/SearchListActivity.java | 2 +- .../opentracks/TrackDetailActivity.java | 3 +- .../opentracks/TrackEditActivity.java | 3 +- .../opentracks/TrackListActivity.java | 11 +- .../opentracks/content/TrackDataHub.java | 2 +- .../ChooseActivityTypeDialogFragment.java | 90 +++---- .../io/file/exporter/ExportAsyncTask.java | 2 +- .../io/file/importer/ImportAsyncTask.java | 2 +- .../services/TrackRecordingService.java | 7 +- .../TrackRecordingServiceConnection.java | 75 +++--- .../settings/ActivityTypePreference.java | 190 +++++++------- .../opentracks/settings/PreferenceHelper.java | 5 +- .../settings/RecordingSettingsActivity.java | 136 ---------- .../settings/ResetDialogPreference.java | 29 ++- .../opentracks/settings/SettingsActivity.java | 240 ++++++++++-------- .../settings/StatsSettingsActivity.java | 78 ------ .../opentracks/util/PreferencesUtils.java | 14 +- .../opentracks/util/TrackIconUtils.java | 2 +- ...rence.xml => preference_activity_type.xml} | 0 src/main/res/values/themes_custom.xml | 1 + src/main/res/xml/settings.xml | 170 +++++++++---- src/main/res/xml/settings_recording.xml | 11 +- 26 files changed, 498 insertions(+), 590 deletions(-) delete mode 100644 src/main/java/de/dennisguse/opentracks/settings/RecordingSettingsActivity.java delete mode 100644 src/main/java/de/dennisguse/opentracks/settings/StatsSettingsActivity.java rename src/main/res/layout/{activity_type_preference.xml => preference_activity_type.xml} (100%) diff --git a/build.gradle b/build.gradle index 423220fc8..962f055d5 100644 --- a/build.gradle +++ b/build.gradle @@ -83,6 +83,7 @@ android { dependencies { implementation 'androidx.appcompat:appcompat:1.1.0' + implementation 'androidx.preference:preference:1.1.0' androidTestImplementation 'androidx.test:core:1.2.0' androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' diff --git a/fastlane/metadata/en-US/changelogs/next_release.txt b/fastlane/metadata/en-US/changelogs/next_release.txt index 203fabbb0..a0e984830 100644 --- a/fastlane/metadata/en-US/changelogs/next_release.txt +++ b/fastlane/metadata/en-US/changelogs/next_release.txt @@ -1,10 +1,10 @@ (tbd): OpenTracks Changes: -- +- Settings are now on a single page Bugfix: - Developer: -- \ No newline at end of file +- Settings moved to Androidx compat (uses fragments) \ No newline at end of file diff --git a/src/androidTest/java/de/dennisguse/opentracks/util/StringUtilsTest.java b/src/androidTest/java/de/dennisguse/opentracks/util/StringUtilsTest.java index dc4693486..03b8da532 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/util/StringUtilsTest.java +++ b/src/androidTest/java/de/dennisguse/opentracks/util/StringUtilsTest.java @@ -149,8 +149,7 @@ public class StringUtilsTest { } /** - * Tests {@link StringUtils#getTime(String)} with fractional seconds and time - * zone. + * Tests {@link StringUtils#getTime(String)} with fractional seconds and time zone. */ @Test public void testGetTime_fractionalAndTimezone() { @@ -183,7 +182,7 @@ public class StringUtilsTest { * Tests {@link StringUtils#getTimeParts(long)} with a positive number. */ @Test - public void testGetTimeParts_postive() { + public void testGetTimeParts_positive() { int[] parts = StringUtils.getTimeParts(61000); Assert.assertEquals(1, parts[0]); Assert.assertEquals(1, parts[1]); diff --git a/src/main/AndroidManifest.xml b/src/main/AndroidManifest.xml index b5e5d10a6..e05429108 100644 --- a/src/main/AndroidManifest.xml +++ b/src/main/AndroidManifest.xml @@ -97,12 +97,8 @@ limitations under the License. android:name=".io.file.exporter.ExportActivity" android:theme="@style/ThemeCustomTransparent" /> - - - - - parent, View v, int position, long id) { - caller.onChooseActivityTypeDone(TrackIconUtils.getAllIconValues().get(position)); - dismiss(); - } - }); + gridView.setOnItemClickListener(this); return view; } /** - * Interface for caller of this dialog fragment. - * - * @author apoorvn + * TODO: Only used by obsolete Androidx preferences. Remove when onAttach(Context) is called. + */ + @Override + public void onAttach(@NonNull Activity activity) { + super.onAttach(activity); + try { + chooseActivityTypeCaller = (ChooseActivityTypeCaller) activity; + } catch (ClassCastException e) { + throw new ClassCastException(activity + " must implement " + ChooseActivityTypeCaller.class.getSimpleName()); + } + } + + public void onAttach(@NonNull Context context) { + super.onAttach(context); + try { + chooseActivityTypeCaller = (ChooseActivityTypeCaller) context; + } catch (ClassCastException e) { + throw new ClassCastException(context + " must implement " + ChooseActivityTypeCaller.class.getSimpleName()); + } + } + + + @Override + public void onItemClick(AdapterView adapterView, View view, int position, long id) { + chooseActivityTypeCaller.onChooseActivityTypeDone(TrackIconUtils.getAllIconValues().get(position)); + dismiss(); + } + + /** + * Interface for chooseActivityTypeCaller of this dialog fragment. */ public interface ChooseActivityTypeCaller { - /** - * Called when choose activity type is done. - */ void onChooseActivityTypeDone(String iconValue); - } - } diff --git a/src/main/java/de/dennisguse/opentracks/io/file/exporter/ExportAsyncTask.java b/src/main/java/de/dennisguse/opentracks/io/file/exporter/ExportAsyncTask.java index f1199399c..9474c155b 100644 --- a/src/main/java/de/dennisguse/opentracks/io/file/exporter/ExportAsyncTask.java +++ b/src/main/java/de/dennisguse/opentracks/io/file/exporter/ExportAsyncTask.java @@ -99,7 +99,7 @@ public class ExportAsyncTask extends AsyncTask { protected Boolean doInBackground(Void... params) { try { Thread.currentThread().setPriority(Thread.MAX_PRIORITY); - boolean isRecording = PreferencesUtils.getLong(exportActivity, R.string.recording_track_id_key) != PreferencesUtils.RECORDING_TRACK_ID_DEFAULT; + boolean isRecording = PreferencesUtils.isRecording(exportActivity); boolean isPaused = PreferencesUtils.getBoolean(exportActivity, R.string.recording_track_paused_key, PreferencesUtils.RECORDING_TRACK_PAUSED_DEFAULT); // Get the wake lock if not recording or paused if (!isRecording || isPaused) { diff --git a/src/main/java/de/dennisguse/opentracks/io/file/importer/ImportAsyncTask.java b/src/main/java/de/dennisguse/opentracks/io/file/importer/ImportAsyncTask.java index bd3d75524..75bcd323e 100644 --- a/src/main/java/de/dennisguse/opentracks/io/file/importer/ImportAsyncTask.java +++ b/src/main/java/de/dennisguse/opentracks/io/file/importer/ImportAsyncTask.java @@ -103,7 +103,7 @@ public class ImportAsyncTask extends AsyncTask { try { Thread.currentThread().setPriority(Thread.MAX_PRIORITY); // Get the wake lock if not recording or paused - boolean isRecording = PreferencesUtils.getLong(importActivity, R.string.recording_track_id_key) != PreferencesUtils.RECORDING_TRACK_ID_DEFAULT; + boolean isRecording = PreferencesUtils.isRecording(importActivity); boolean isPaused = PreferencesUtils.getBoolean(importActivity, R.string.recording_track_paused_key, PreferencesUtils.RECORDING_TRACK_PAUSED_DEFAULT); if (!isRecording || isPaused) { wakeLock = SystemUtils.acquireWakeLock(importActivity, wakeLock); diff --git a/src/main/java/de/dennisguse/opentracks/services/TrackRecordingService.java b/src/main/java/de/dennisguse/opentracks/services/TrackRecordingService.java index 412910329..7d7680e97 100644 --- a/src/main/java/de/dennisguse/opentracks/services/TrackRecordingService.java +++ b/src/main/java/de/dennisguse/opentracks/services/TrackRecordingService.java @@ -119,10 +119,9 @@ public class TrackRecordingService extends Service { @Override public void onSharedPreferenceChanged(SharedPreferences preferences, String key) { if (key == null || key.equals(PreferencesUtils.getKey(context, R.string.recording_track_id_key))) { - long trackId = PreferencesUtils.getLong(context, R.string.recording_track_id_key); // Only through the TrackRecordingService can one stop a recording and set the recordingTrackId to -1L. - if (trackId != PreferencesUtils.RECORDING_TRACK_ID_DEFAULT) { - recordingTrackId = trackId; + if (PreferencesUtils.isRecording(context)) { + recordingTrackId = PreferencesUtils.getLong(context, R.string.recording_track_id_key); } } if (key == null || key.equals(PreferencesUtils.getKey(context, R.string.recording_track_paused_key))) { @@ -310,7 +309,7 @@ public class TrackRecordingService extends Service { * Returns true if the service is recording. */ public boolean isRecording() { - return recordingTrackId != PreferencesUtils.RECORDING_TRACK_ID_DEFAULT; + return PreferencesUtils.isRecording(recordingTrackId); } /** diff --git a/src/main/java/de/dennisguse/opentracks/services/TrackRecordingServiceConnection.java b/src/main/java/de/dennisguse/opentracks/services/TrackRecordingServiceConnection.java index 24b482ebf..832ec14e1 100644 --- a/src/main/java/de/dennisguse/opentracks/services/TrackRecordingServiceConnection.java +++ b/src/main/java/de/dennisguse/opentracks/services/TrackRecordingServiceConnection.java @@ -226,37 +226,14 @@ public class TrackRecordingServiceConnection implements ServiceConnection, Death } } - /** - * Stops the recording. - * - * @param context the context - * @param showEditor true to show the editor - */ - public void stopRecording(@NonNull Context context, boolean showEditor) { - ITrackRecordingService trackRecordingService = getServiceIfBound(); - if (trackRecordingService == null) { - resetRecordingState(context); - } else { - try { - if (showEditor) { - // Need to remember the recordingTrackId before calling endCurrentTrack() as endCurrentTrack() sets the value to -1L. - long recordingTrackId = PreferencesUtils.getLong(context, R.string.recording_track_id_key); - trackRecordingService.endCurrentTrack(); - if (recordingTrackId != PreferencesUtils.RECORDING_TRACK_ID_DEFAULT) { - Intent intent = IntentUtils.newIntent(context, TrackEditActivity.class) - .putExtra(TrackEditActivity.EXTRA_TRACK_ID, recordingTrackId) - .putExtra(TrackEditActivity.EXTRA_NEW_TRACK, true); - context.startActivity(intent); - } - } else { - trackRecordingService.endCurrentTrack(); - } - } catch (Exception e) { - //TODO What exception are we catching here? Should be removed... - Log.e(TAG, "Unable to stop recording.", e); - } + private static void resetRecordingState(Context context) { + if (PreferencesUtils.isRecording(context)) { + PreferencesUtils.setLong(context, R.string.recording_track_id_key, PreferencesUtils.RECORDING_TRACK_ID_DEFAULT); + } + boolean recordingTrackPaused = PreferencesUtils.getBoolean(context, R.string.recording_track_paused_key, PreferencesUtils.RECORDING_TRACK_PAUSED_DEFAULT); + if (!recordingTrackPaused) { + PreferencesUtils.setBoolean(context, R.string.recording_track_paused_key, PreferencesUtils.RECORDING_TRACK_PAUSED_DEFAULT); } - unbindAndStop(); } /** @@ -284,14 +261,36 @@ public class TrackRecordingServiceConnection implements ServiceConnection, Death return -1L; } - private static void resetRecordingState(Context context) { - long recordingTrackId = PreferencesUtils.getLong(context, R.string.recording_track_id_key); - if (recordingTrackId != PreferencesUtils.RECORDING_TRACK_ID_DEFAULT) { - PreferencesUtils.setLong(context, R.string.recording_track_id_key, PreferencesUtils.RECORDING_TRACK_ID_DEFAULT); - } - boolean recordingTrackPaused = PreferencesUtils.getBoolean(context, R.string.recording_track_paused_key, PreferencesUtils.RECORDING_TRACK_PAUSED_DEFAULT); - if (!recordingTrackPaused) { - PreferencesUtils.setBoolean(context, R.string.recording_track_paused_key, PreferencesUtils.RECORDING_TRACK_PAUSED_DEFAULT); + /** + * Stops the recording. + * + * @param context the context + * @param showEditor true to show the editor + */ + public void stopRecording(@NonNull Context context, boolean showEditor) { + ITrackRecordingService trackRecordingService = getServiceIfBound(); + if (trackRecordingService == null) { + resetRecordingState(context); + } else { + try { + if (showEditor) { + // Need to remember the recordingTrackId before calling endCurrentTrack() as endCurrentTrack() sets the value to -1L. + long recordingTrackId = PreferencesUtils.getLong(context, R.string.recording_track_id_key); + trackRecordingService.endCurrentTrack(); + if (PreferencesUtils.isRecording(context)) { + Intent intent = IntentUtils.newIntent(context, TrackEditActivity.class) + .putExtra(TrackEditActivity.EXTRA_TRACK_ID, recordingTrackId) + .putExtra(TrackEditActivity.EXTRA_NEW_TRACK, true); + context.startActivity(intent); + } + } else { + trackRecordingService.endCurrentTrack(); + } + } catch (Exception e) { + //TODO What exception are we catching here? Should be removed... + Log.e(TAG, "Unable to stop recording.", e); + } } + unbindAndStop(); } } diff --git a/src/main/java/de/dennisguse/opentracks/settings/ActivityTypePreference.java b/src/main/java/de/dennisguse/opentracks/settings/ActivityTypePreference.java index 510ea7951..cded911fa 100644 --- a/src/main/java/de/dennisguse/opentracks/settings/ActivityTypePreference.java +++ b/src/main/java/de/dennisguse/opentracks/settings/ActivityTypePreference.java @@ -17,8 +17,7 @@ package de.dennisguse.opentracks.settings; import android.content.Context; -import android.os.Parcelable; -import android.preference.DialogPreference; +import android.os.Bundle; import android.util.AttributeSet; import android.view.KeyEvent; import android.view.MotionEvent; @@ -28,7 +27,12 @@ import android.widget.ArrayAdapter; import android.widget.AutoCompleteTextView; import android.widget.Spinner; +import androidx.fragment.app.FragmentActivity; +import androidx.preference.DialogPreference; +import androidx.preference.PreferenceDialogFragment; + import de.dennisguse.opentracks.R; +import de.dennisguse.opentracks.fragments.ChooseActivityTypeDialogFragment; import de.dennisguse.opentracks.util.PreferencesUtils; import de.dennisguse.opentracks.util.TrackIconUtils; @@ -39,106 +43,122 @@ import de.dennisguse.opentracks.util.TrackIconUtils; */ public class ActivityTypePreference extends DialogPreference { - private RecordingSettingsActivity recordingSettingsActivity; - private AutoCompleteTextView textView; - private Spinner spinner; + private SummaryProvider summaryProvider = new SummaryProvider() { + @Override + public CharSequence provideSummary(DialogPreference preference) { + String defaultActivity = PreferencesUtils.getString(ActivityTypePreference.this.getContext(), R.string.default_activity_key, PreferencesUtils.DEFAULT_ACTIVITY_DEFAULT); + return defaultActivity != null && !defaultActivity.equals(PreferencesUtils.DEFAULT_ACTIVITY_DEFAULT) ? defaultActivity : getContext().getString(R.string.value_unknown); + } + }; public ActivityTypePreference(Context context, AttributeSet attrs) { super(context, attrs); - setDialogLayoutResource(R.layout.activity_type_preference); + setDialogLayoutResource(R.layout.preference_activity_type); setPositiveButtonText(android.R.string.ok); setNegativeButtonText(android.R.string.cancel); setDialogIcon(null); - setPersistent(false); + setPersistent(true); + //TODO: for some reason the summary is not updated; after changing it. Enable summaryprovider, when fixed. +// setSummaryProvider(summaryProvider); } @Override - protected View onCreateDialogView() { - View view = super.onCreateDialogView(); - textView = view.findViewById(R.id.activity_type_preference_text_view); - spinner = view.findViewById(R.id.activity_type_preference_spinner); + public int getDialogLayoutResource() { + return R.layout.preference_activity_type; + } - String category = PreferencesUtils.getString( - getContext(), R.string.default_activity_key, PreferencesUtils.DEFAULT_ACTIVITY_DEFAULT); - textView.setText(category); + public static class ActivityPreferenceDialog extends PreferenceDialogFragment { - ArrayAdapter adapter = ArrayAdapter.createFromResource(getContext(), R.array.activity_types, android.R.layout.simple_dropdown_item_1line); - textView.setAdapter(adapter); - textView.setOnItemClickListener(new AdapterView.OnItemClickListener() { - @Override - public void onItemClick(AdapterView parent, View v, int position, long id) { - String iconValue = TrackIconUtils.getIconValue(getContext(), (String) textView.getAdapter().getItem(position)); - TrackIconUtils.setIconSpinner(spinner, iconValue); - } - }); - textView.setOnFocusChangeListener(new View.OnFocusChangeListener() { - @Override - public void onFocusChange(View v, boolean hasFocus) { - if (!hasFocus) { - String iconValue = TrackIconUtils.getIconValue(getContext(), textView.getText().toString()); + private AutoCompleteTextView textView; + private Spinner spinner; + + static ActivityPreferenceDialog newInstance(String preferenceKey) { + ActivityTypePreference.ActivityPreferenceDialog dialog = new ActivityTypePreference.ActivityPreferenceDialog(); + final Bundle bundle = new Bundle(1); + bundle.putString(PreferenceDialogFragment.ARG_KEY, preferenceKey); + dialog.setArguments(bundle); + + return dialog; + } + + @Override + protected void onBindDialogView(View view) { + super.onBindDialogView(view); + + final Context context = getActivity(); + + textView = view.findViewById(R.id.activity_type_preference_text_view); + String category = PreferencesUtils.getString(context, R.string.default_activity_key, PreferencesUtils.DEFAULT_ACTIVITY_DEFAULT); + textView.setText(category); + ArrayAdapter adapter = ArrayAdapter.createFromResource(context, R.array.activity_types, android.R.layout.simple_dropdown_item_1line); + textView.setAdapter(adapter); + textView.setOnItemClickListener(new AdapterView.OnItemClickListener() { + @Override + public void onItemClick(AdapterView parent, View v, int position, long id) { + String iconValue = TrackIconUtils.getIconValue(context, (String) textView.getAdapter().getItem(position)); TrackIconUtils.setIconSpinner(spinner, iconValue); } - } - }); - - String iconValue = TrackIconUtils.getIconValue(getContext(), category); - spinner.setAdapter(TrackIconUtils.getIconSpinnerAdapter(getContext(), iconValue)); - spinner.setOnTouchListener(new View.OnTouchListener() { - @Override - public boolean onTouch(View v, MotionEvent event) { - if (event.getAction() == MotionEvent.ACTION_UP) { - recordingSettingsActivity.showChooseActivityTypeDialog(); + }); + textView.setOnFocusChangeListener(new View.OnFocusChangeListener() { + @Override + public void onFocusChange(View v, boolean hasFocus) { + if (!hasFocus) { + String iconValue = TrackIconUtils.getIconValue(context, textView.getText().toString()); + TrackIconUtils.setIconSpinner(spinner, iconValue); + } } - return true; - } - }); - spinner.setOnKeyListener(new View.OnKeyListener() { - @Override - public boolean onKey(View v, int keyCode, KeyEvent event) { - if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) { - recordingSettingsActivity.showChooseActivityTypeDialog(); - } - return true; - } - }); - return view; - } + }); - @Override - protected void onDialogClosed(boolean positiveResult) { - if (positiveResult) { - String value = textView.getText().toString(); - if (callChangeListener(value)) { - PreferencesUtils.setString(getContext(), R.string.default_activity_key, value); + String iconValue = TrackIconUtils.getIconValue(context, category); + spinner = view.findViewById(R.id.activity_type_preference_spinner); + spinner.setAdapter(TrackIconUtils.getIconSpinnerAdapter(context, iconValue)); + spinner.setOnTouchListener(new View.OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + if (event.getAction() == MotionEvent.ACTION_UP) { + showIconSelectDialog(); + } + return true; + } + }); + spinner.setOnKeyListener(new View.OnKeyListener() { + @Override + public boolean onKey(View v, int keyCode, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) { + showIconSelectDialog(); + } + return true; + } + }); + } + + private void showIconSelectDialog() { + String category = PreferencesUtils.getString(getActivity(), R.string.default_activity_key, PreferencesUtils.DEFAULT_ACTIVITY_DEFAULT); + + // TODO Remove casting when upgrading to new Androidx compat. + FragmentActivity fragmentActivity = (androidx.fragment.app.FragmentActivity) getActivity(); + ChooseActivityTypeDialogFragment.showDialog(fragmentActivity.getSupportFragmentManager(), category); + } + + @Override + public void onDialogClosed(boolean positiveResult) { + if (positiveResult) { + String newDefaultActivity = textView.getText().toString(); + if (getPreference().callChangeListener(newDefaultActivity)) { + PreferencesUtils.setString(getActivity(), R.string.default_activity_key, newDefaultActivity); + } } } - } - @Override - protected void onRestoreInstanceState(Parcelable state) { - super.onRestoreInstanceState(state); - String iconValue = TrackIconUtils.getIconValue(getContext(), textView.getText().toString()); - TrackIconUtils.setIconSpinner(spinner, iconValue); - textView.clearFocus(); - } - - /** - * Sets the recording settings activity. - * - * @param activity the activity - */ - void setRecordingSettingsActivity(RecordingSettingsActivity activity) { - recordingSettingsActivity = activity; - } - - /** - * Updates the value of the dialog. - * - * @param iconValue the icon value - */ - void updateValue(String iconValue) { - TrackIconUtils.setIconSpinner(spinner, iconValue); - textView.setText(recordingSettingsActivity.getString(TrackIconUtils.getIconActivityType(iconValue))); - textView.clearFocus(); + /** + * Updates the value of the dialog. + * + * @param iconValue the icon value + */ + public void updateUI(String iconValue) { + TrackIconUtils.setIconSpinner(spinner, iconValue); + textView.setText(getActivity().getString(TrackIconUtils.getIconActivityType(iconValue))); + textView.clearFocus(); + } } } diff --git a/src/main/java/de/dennisguse/opentracks/settings/PreferenceHelper.java b/src/main/java/de/dennisguse/opentracks/settings/PreferenceHelper.java index ec6de3c35..ab7ed0ef8 100644 --- a/src/main/java/de/dennisguse/opentracks/settings/PreferenceHelper.java +++ b/src/main/java/de/dennisguse/opentracks/settings/PreferenceHelper.java @@ -2,7 +2,8 @@ package de.dennisguse.opentracks.settings; import android.bluetooth.BluetoothAdapter; import android.content.Context; -import android.preference.ListPreference; + +import androidx.preference.ListPreference; import java.util.ArrayList; import java.util.List; @@ -183,7 +184,7 @@ final class PreferenceHelper { /** * Configures the bluetooth sensor. */ - static void configBluetoothSensor(ListPreference preference) { + static void configureBluetoothSensorList(ListPreference preference) { Context context = preference.getContext(); String value = PreferencesUtils.getString(context, R.string.bluetooth_sensor_key, PreferencesUtils.BLUETOOTH_SENSOR_DEFAULT); diff --git a/src/main/java/de/dennisguse/opentracks/settings/RecordingSettingsActivity.java b/src/main/java/de/dennisguse/opentracks/settings/RecordingSettingsActivity.java deleted file mode 100644 index 494caa523..000000000 --- a/src/main/java/de/dennisguse/opentracks/settings/RecordingSettingsActivity.java +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright 2012 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ - -package de.dennisguse.opentracks.settings; - -import android.app.Dialog; -import android.os.Bundle; -import android.preference.ListPreference; -import android.preference.Preference; -import android.preference.PreferenceActivity; - -import de.dennisguse.opentracks.R; -import de.dennisguse.opentracks.fragments.ChooseActivityTypeDialogFragment.ChooseActivityTypeCaller; -import de.dennisguse.opentracks.util.PreferencesUtils; -import de.dennisguse.opentracks.util.StringUtils; - -/** - * An activity for accessing recording settings. - * - * @author Jimmy Shih - */ -public class RecordingSettingsActivity extends PreferenceActivity implements ChooseActivityTypeCaller { - - private static final int DIALOG_CHOOSE_ACTIVITY = 0; - - private ActivityTypePreference activityTypePreference; - - @Override - protected void onCreate(Bundle bundle) { - super.onCreate(bundle); - addPreferencesFromResource(R.xml.settings_recording); - - boolean metricUnits = PreferencesUtils.isMetricUnits(this); - - configFrequencyPreference(R.string.voice_frequency_key, metricUnits); - configFrequencyPreference(R.string.split_frequency_key, metricUnits); - configDefaultActivity(); - configListPreference(R.string.min_recording_interval_key, R.array.min_recording_interval_values, metricUnits); - configListPreference(R.string.recording_distance_interval_key, R.array.recording_distance_interval_values, metricUnits); - configListPreference(R.string.max_recording_distance_key, R.array.max_recording_distance_values, metricUnits); - configListPreference(R.string.recording_gps_accuracy_key, R.array.recording_gps_accuracy_values, metricUnits); - configListPreference(R.string.auto_resume_track_timeout_key, R.array.auto_resume_track_timeout_values, metricUnits); - } - - private void configFrequencyPreference(int key, boolean metricUnits) { - ListPreference preference = (ListPreference) findPreference(getString(key)); - - String[] options = StringUtils.getFrequencyOptions(this, metricUnits); - preference.setEntries(options); - } - - private void configDefaultActivity() { - activityTypePreference = (ActivityTypePreference) findPreference(getString(R.string.default_activity_key)); - String defaultActivity = PreferencesUtils.getString( - this, R.string.default_activity_key, PreferencesUtils.DEFAULT_ACTIVITY_DEFAULT); - activityTypePreference.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { - @Override - public boolean onPreferenceChange(Preference pref, Object newValue) { - String stringValue = (String) newValue; - pref.setSummary(stringValue != null && !stringValue.equals(PreferencesUtils.DEFAULT_ACTIVITY_DEFAULT) ? stringValue : getString(R.string.value_unknown)); - return true; - } - }); - activityTypePreference.setSummary(defaultActivity != null && !defaultActivity.equals(PreferencesUtils.DEFAULT_ACTIVITY_DEFAULT) ? defaultActivity : getString(R.string.value_unknown)); - activityTypePreference.setRecordingSettingsActivity(this); - } - - private void configListPreference(int key, int valueArray, boolean metricUnits) { - ListPreference preference = (ListPreference) findPreference(getString(key)); - - @Deprecated //TODO Can we make values an int array? - String[] values = getResources().getStringArray(valueArray); - String[] options = new String[values.length]; - switch (key) { - case R.string.min_recording_interval_key: - PreferenceHelper.setMinRecordingIntervalOptions(this, options, values); - break; - case R.string.recording_distance_interval_key: - PreferenceHelper.setRecordingDistanceIntervalOptions(this, options, values, metricUnits); - break; - case R.string.max_recording_distance_key: - PreferenceHelper.setMaxRecordingDistanceOptions(this, options, values, metricUnits); - break; - case R.string.recording_gps_accuracy_key: - PreferenceHelper.setRecordingGpsAccuracyOptions(this, options, values, metricUnits); - break; - case R.string.auto_resume_track_timeout_key: - PreferenceHelper.setAutoResumeTrackTimeoutOptions(this, options, values); - break; - default: - return; - } - - preference.setEntries(options); - } - - - public void showChooseActivityTypeDialog() { - try { - removeDialog(DIALOG_CHOOSE_ACTIVITY); - } catch (Exception e) { - // Can safely ignore. - } - showDialog(DIALOG_CHOOSE_ACTIVITY); - } - - @Override - protected Dialog onCreateDialog(int id, Bundle bundle) { - if (id != DIALOG_CHOOSE_ACTIVITY) { - return null; - } - - String category = PreferencesUtils.getString(this, R.string.default_activity_key, PreferencesUtils.DEFAULT_ACTIVITY_DEFAULT); - //TODO ATTENTION: Need to switch to FragmentActivity before this can be used. - // ChooseActivityTypeDialogFragment.showDialog(getSupportFragmentManager(), category); - return null; - } - - @Override - public void onChooseActivityTypeDone(String iconValue) { - activityTypePreference.updateValue(iconValue); - } -} diff --git a/src/main/java/de/dennisguse/opentracks/settings/ResetDialogPreference.java b/src/main/java/de/dennisguse/opentracks/settings/ResetDialogPreference.java index a7f6a5109..f56d2a8cc 100644 --- a/src/main/java/de/dennisguse/opentracks/settings/ResetDialogPreference.java +++ b/src/main/java/de/dennisguse/opentracks/settings/ResetDialogPreference.java @@ -1,11 +1,13 @@ package de.dennisguse.opentracks.settings; import android.content.Context; -import android.content.DialogInterface; -import android.preference.DialogPreference; +import android.os.Bundle; import android.util.AttributeSet; import android.widget.Toast; +import androidx.preference.DialogPreference; +import androidx.preference.PreferenceDialogFragment; + import de.dennisguse.opentracks.R; import de.dennisguse.opentracks.util.PreferencesUtils; @@ -15,13 +17,24 @@ public class ResetDialogPreference extends DialogPreference { super(context, attrs); } - @Override - public void onClick(DialogInterface dialog, int which) { - super.onClick(dialog, which); - if (which == DialogInterface.BUTTON_POSITIVE) { - PreferencesUtils.resetPreferences(getContext(), true); + public static class ResetPreferenceDialog extends PreferenceDialogFragment { - Toast.makeText(getContext(), R.string.settings_reset_done, Toast.LENGTH_SHORT).show(); + static PreferenceDialogFragment newInstance(String preferenceKey) { + ResetPreferenceDialog dialog = new ResetPreferenceDialog(); + final Bundle bundle = new Bundle(1); + bundle.putString(PreferenceDialogFragment.ARG_KEY, preferenceKey); + dialog.setArguments(bundle); + + return dialog; + } + + @Override + public void onDialogClosed(boolean positiveResult) { + if (positiveResult) { + PreferencesUtils.resetPreferences(getActivity(), true); + + Toast.makeText(getActivity(), R.string.settings_reset_done, Toast.LENGTH_SHORT).show(); + } } } } diff --git a/src/main/java/de/dennisguse/opentracks/settings/SettingsActivity.java b/src/main/java/de/dennisguse/opentracks/settings/SettingsActivity.java index 0402dfa0b..57f49ade3 100644 --- a/src/main/java/de/dennisguse/opentracks/settings/SettingsActivity.java +++ b/src/main/java/de/dennisguse/opentracks/settings/SettingsActivity.java @@ -1,126 +1,156 @@ -/* - * Copyright 2008 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ - package de.dennisguse.opentracks.settings; -import android.content.Intent; +import android.app.DialogFragment; import android.content.SharedPreferences; import android.os.Bundle; -import android.preference.ListPreference; -import android.preference.Preference; -import android.preference.Preference.OnPreferenceClickListener; -import android.preference.PreferenceActivity; -import android.provider.Settings; + +import androidx.fragment.app.FragmentActivity; +import androidx.preference.ListPreference; +import androidx.preference.Preference; +import androidx.preference.PreferenceFragment; import de.dennisguse.opentracks.R; -import de.dennisguse.opentracks.util.IntentUtils; +import de.dennisguse.opentracks.fragments.ChooseActivityTypeDialogFragment; import de.dennisguse.opentracks.util.PreferencesUtils; +import de.dennisguse.opentracks.util.StringUtils; -/** - * An activity for accessing settings. - * - * @author Jimmy Shih - */ -public class SettingsActivity extends PreferenceActivity { +public class SettingsActivity extends FragmentActivity implements ChooseActivityTypeDialogFragment.ChooseActivityTypeCaller { - private long recordingTrackId = PreferencesUtils.RECORDING_TRACK_ID_DEFAULT; - - /* - * Note that sharedPreferenceChangeListenr cannot be an anonymous inner class. - * Anonymous inner class will get garbage collected. - */ - private final SharedPreferences.OnSharedPreferenceChangeListener sharedPreferenceChangeListener = new SharedPreferences.OnSharedPreferenceChangeListener() { - @Override - public void onSharedPreferenceChanged(SharedPreferences preferences, String key) { - if (key != null && key.equals(PreferencesUtils.getKey(SettingsActivity.this, R.string.recording_track_id_key))) { - recordingTrackId = PreferencesUtils.getLong(SettingsActivity.this, R.string.recording_track_id_key); - } - - //TODO Should only be called if something meaningful happens. - runOnUiThread(new Runnable() { - @Override - public void run() { - updateUI(); - } - }); - } - }; + private PrefsFragment prefsFragment = new PrefsFragment(); @Override - protected void onCreate(Bundle bundle) { - super.onCreate(bundle); + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); - addPreferencesFromResource(R.xml.settings); + getFragmentManager().beginTransaction().replace(android.R.id.content, prefsFragment).commit(); + } - configPreference(R.string.settings_stats_key, StatsSettingsActivity.class); - configPreference(R.string.settings_recording_key, NewSettingsActivity.class); + @Override + public void onChooseActivityTypeDone(String iconValue) { + prefsFragment.setDefaultActivity(iconValue); + } - findPreference(getString(R.string.settings_sensor_bluetooth_pairing_key)) - .setOnPreferenceClickListener(new OnPreferenceClickListener() { - public boolean onPreferenceClick(Preference preference) { - Intent settingsIntent = new Intent(Settings.ACTION_BLUETOOTH_SETTINGS); - startActivity(settingsIntent); - return true; + public static class PrefsFragment extends PreferenceFragment { + + /* + * Note that sharedPreferenceChangeListener cannot be an anonymous inner class. + * Anonymous inner class will get garbage collected. + */ + private final SharedPreferences.OnSharedPreferenceChangeListener sharedPreferenceChangeListener = new SharedPreferences.OnSharedPreferenceChangeListener() { + @Override + public void onSharedPreferenceChanged(SharedPreferences preferences, String key) { + getActivity().runOnUiThread(new Runnable() { + @Override + public void run() { + updateUI(); } }); - } - - @Override - protected void onResume() { - super.onResume(); - PreferencesUtils.getSharedPreferences(this).registerOnSharedPreferenceChangeListener(sharedPreferenceChangeListener); - recordingTrackId = PreferencesUtils.getLong(this, R.string.recording_track_id_key); - updateUI(); - - ListPreference preference = (ListPreference) findPreference(getString(R.string.bluetooth_sensor_key)); - PreferenceHelper.configBluetoothSensor(preference); - } - - @Override - protected void onPause() { - super.onPause(); - PreferencesUtils.getSharedPreferences(this).unregisterOnSharedPreferenceChangeListener(sharedPreferenceChangeListener); - } - - /** - * Configures a preference by starting a new activity when it is clicked. - * - * @param key the preference key - * @param cl the class to start the new activity - */ - private void configPreference(int key, final Class cl) { - Preference preference = findPreference(getString(key)); - preference.setOnPreferenceClickListener(new OnPreferenceClickListener() { - @Override - public boolean onPreferenceClick(Preference pref) { - Intent intent = IntentUtils.newIntent(SettingsActivity.this, cl); - startActivity(intent); - return true; } - }); - } + }; - private void updateUI() { - //TODO Remove the following if recordingTrackId is replaced by direct communication rather than via preferences. - boolean isRecording = recordingTrackId != PreferencesUtils.RECORDING_TRACK_ID_DEFAULT; - Preference resetPreference = findPreference(getString(R.string.settings_reset_key)); - resetPreference.setSummary(isRecording ? getString(R.string.settings_not_while_recording) : ""); - resetPreference.setEnabled(!isRecording); + // Used to forward update from ChooseActivityTypeDialogFragment; TODO Could be replaced with LiveData. + private ActivityTypePreference.ActivityPreferenceDialog activityPreferenceDialog; - Preference speedCheckBoxPreference = findPreference(getString(R.string.chart_show_speed_key)); - speedCheckBoxPreference.setTitle(PreferencesUtils.isReportSpeed(this) ? R.string.stats_speed : R.string.stats_pace); + @Override + public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { + addPreferencesFromResource(R.xml.settings); + + boolean metricUnits = PreferencesUtils.isMetricUnits(getActivity()); + + configFrequencyPreference(R.string.voice_frequency_key, metricUnits); + configFrequencyPreference(R.string.split_frequency_key, metricUnits); + configListPreference(R.string.min_recording_interval_key, R.array.min_recording_interval_values, metricUnits); + configListPreference(R.string.recording_distance_interval_key, R.array.recording_distance_interval_values, metricUnits); + configListPreference(R.string.max_recording_distance_key, R.array.max_recording_distance_values, metricUnits); + configListPreference(R.string.recording_gps_accuracy_key, R.array.recording_gps_accuracy_values, metricUnits); + configListPreference(R.string.auto_resume_track_timeout_key, R.array.auto_resume_track_timeout_values, metricUnits); + configListPreference(R.string.auto_resume_track_timeout_key, R.array.auto_resume_track_timeout_values, metricUnits); + + ListPreference bluetoothPreference = findPreference(getString(R.string.bluetooth_sensor_key)); + PreferenceHelper.configureBluetoothSensorList(bluetoothPreference); + } + + @Override + public void onResume() { + super.onResume(); + PreferencesUtils.getSharedPreferences(getActivity()).registerOnSharedPreferenceChangeListener(sharedPreferenceChangeListener); + updateUI(); + } + + @Override + public void onPause() { + super.onPause(); + PreferencesUtils.getSharedPreferences(getActivity()).unregisterOnSharedPreferenceChangeListener(sharedPreferenceChangeListener); + } + + private void configFrequencyPreference(int key, boolean metricUnits) { + ListPreference preference = findPreference(getString(key)); + + String[] options = StringUtils.getFrequencyOptions(getActivity(), metricUnits); + preference.setEntries(options); + } + + private void configListPreference(int key, int valueArray, boolean metricUnits) { + //TODO Can we make values an int array? + String[] values = getResources().getStringArray(valueArray); + final String[] options = new String[values.length]; + switch (key) { + case R.string.min_recording_interval_key: + PreferenceHelper.setMinRecordingIntervalOptions(getActivity(), options, values); + break; + case R.string.recording_distance_interval_key: + PreferenceHelper.setRecordingDistanceIntervalOptions(getActivity(), options, values, metricUnits); + break; + case R.string.max_recording_distance_key: + PreferenceHelper.setMaxRecordingDistanceOptions(getActivity(), options, values, metricUnits); + break; + case R.string.recording_gps_accuracy_key: + PreferenceHelper.setRecordingGpsAccuracyOptions(getActivity(), options, values, metricUnits); + break; + case R.string.auto_resume_track_timeout_key: + PreferenceHelper.setAutoResumeTrackTimeoutOptions(getActivity(), options, values); + break; + default: + return; + } + + final ListPreference listPreference = findPreference(getString(key)); + listPreference.setEntries(options); + } + + @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; + } + + if (dialogFragment != null) { + dialogFragment.setTargetFragment(this, 0); + dialogFragment.show(getFragmentManager(), getClass().getSimpleName()); + return; + } + + super.onDisplayPreferenceDialog(preference); + } + + public void setDefaultActivity(String iconValue) { + if (activityPreferenceDialog != null) { + activityPreferenceDialog.updateUI(iconValue); + } + } + + private void updateUI() { + final boolean isRecording = PreferencesUtils.isRecording(getActivity()); + Preference resetPreference = findPreference(getString(R.string.settings_reset_key)); + resetPreference.setSummary(isRecording ? getString(R.string.settings_not_while_recording) : ""); + resetPreference.setEnabled(!isRecording); + + Preference speedCheckBoxPreference = findPreference(getString(R.string.chart_show_speed_key)); + speedCheckBoxPreference.setTitle(PreferencesUtils.isReportSpeed(getActivity()) ? R.string.stats_speed : R.string.stats_pace); + } } } diff --git a/src/main/java/de/dennisguse/opentracks/settings/StatsSettingsActivity.java b/src/main/java/de/dennisguse/opentracks/settings/StatsSettingsActivity.java deleted file mode 100644 index ae6b7024b..000000000 --- a/src/main/java/de/dennisguse/opentracks/settings/StatsSettingsActivity.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright 2012 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ - -package de.dennisguse.opentracks.settings; - -import android.os.Bundle; -import android.preference.ListPreference; -import android.preference.Preference; -import android.preference.Preference.OnPreferenceChangeListener; -import android.preference.PreferenceActivity; - -import de.dennisguse.opentracks.R; -import de.dennisguse.opentracks.util.PreferencesUtils; - -/** - * An activity for accessing stats settings. - * - * @author Jimmy Shih - */ -public class StatsSettingsActivity extends PreferenceActivity { - - @Override - protected void onCreate(Bundle bundle) { - super.onCreate(bundle); - addPreferencesFromResource(R.xml.settings_statistics); - - configUnitsListPreference(); - boolean metricUnits = PreferencesUtils.STATS_UNITS_DEFAULT.equals(PreferencesUtils.getString(this, R.string.stats_units_key, "")); - configRateListPreference(metricUnits); - } - - /** - * Configures the preferred units list preference. - */ - private void configUnitsListPreference() { - ListPreference listPreference = (ListPreference) findPreference(getString(R.string.stats_units_key)); - final OnPreferenceChangeListener listener = new OnPreferenceChangeListener() { - - @Override - public boolean onPreferenceChange(Preference pref, Object newValue) { - boolean metricUnits = PreferencesUtils.STATS_UNITS_DEFAULT.equals(newValue); - configRateListPreference(metricUnits); - return true; - } - }; - listPreference.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { - @Override - public boolean onPreferenceChange(Preference pref, Object newValue) { - return listener.onPreferenceChange(pref, newValue); - } - }); - } - - /** - * Configures the preferred rate list preference. - * - * @param metricUnits true if metric units - */ - private void configRateListPreference(boolean metricUnits) { - ListPreference listPreference = (ListPreference) findPreference(getString(R.string.stats_rate_key)); - String[] options = getResources().getStringArray(metricUnits ? R.array.stats_rate_metric_options : R.array.stats_rate_imperial_options); - - listPreference.setEntries(options); - } -} diff --git a/src/main/java/de/dennisguse/opentracks/util/PreferencesUtils.java b/src/main/java/de/dennisguse/opentracks/util/PreferencesUtils.java index 2bc1fb76f..b480e1518 100644 --- a/src/main/java/de/dennisguse/opentracks/util/PreferencesUtils.java +++ b/src/main/java/de/dennisguse/opentracks/util/PreferencesUtils.java @@ -19,7 +19,8 @@ package de.dennisguse.opentracks.util; import android.content.Context; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; -import android.preference.PreferenceManager; + +import androidx.preference.PreferenceManager; import de.dennisguse.opentracks.R; @@ -252,9 +253,16 @@ public class PreferencesUtils { return CHART_X_AXIS_DEFAULT.equals(getString(context, R.string.chart_x_axis_key, CHART_X_AXIS_DEFAULT)); } + public static boolean isRecording(Context context) { + long recordingTrackId = PreferencesUtils.getLong(context, R.string.recording_track_id_key); + return recordingTrackId != PreferencesUtils.RECORDING_TRACK_ID_DEFAULT; + } + + public static boolean isRecording(long recordingTrackId) { + return recordingTrackId != PreferencesUtils.RECORDING_TRACK_ID_DEFAULT; + } + public static void resetPreferences(Context context, boolean readAgain) { PreferenceManager.setDefaultValues(context, R.xml.settings, readAgain); - PreferenceManager.setDefaultValues(context, R.xml.settings_recording, readAgain); - PreferenceManager.setDefaultValues(context, R.xml.settings_statistics, readAgain); } } diff --git a/src/main/java/de/dennisguse/opentracks/util/TrackIconUtils.java b/src/main/java/de/dennisguse/opentracks/util/TrackIconUtils.java index b079c9f27..bdf97bc21 100644 --- a/src/main/java/de/dennisguse/opentracks/util/TrackIconUtils.java +++ b/src/main/java/de/dennisguse/opentracks/util/TrackIconUtils.java @@ -62,7 +62,7 @@ public class TrackIconUtils { private static final LinkedHashMap> MAP = new LinkedHashMap<>(); static { - //Reflects order in ChooseActivityTypeDialogFragment + //Reflects order in ChooseActivityTypeDialogFragmentActivity MAP.put(UNKNOWN, new Pair<>(R.string.activity_type_unknown, ACTIVITY_UNKNOWN_LOGO)); MAP.put(RUN, new Pair<>(R.string.activity_type_running, R.drawable.ic_activity_run_24dp)); MAP.put(WALK, new Pair<>(R.string.activity_type_walking, R.drawable.ic_activity_walk_24dp)); diff --git a/src/main/res/layout/activity_type_preference.xml b/src/main/res/layout/preference_activity_type.xml similarity index 100% rename from src/main/res/layout/activity_type_preference.xml rename to src/main/res/layout/preference_activity_type.xml diff --git a/src/main/res/values/themes_custom.xml b/src/main/res/values/themes_custom.xml index aafb9fbdf..8da7f3ea1 100644 --- a/src/main/res/values/themes_custom.xml +++ b/src/main/res/values/themes_custom.xml @@ -30,6 +30,7 @@ limitations under the License. @style/ActionBarStyleCustom @drawable/custom_action_mode_background @style/CustomAlertDialogTheme + @color/holo_orange_dark