diff --git a/app/res/layout/start_basic.xml b/app/res/layout/start_basic.xml index 545ac0ae3..9ebc39870 100644 --- a/app/res/layout/start_basic.xml +++ b/app/res/layout/start_basic.xml @@ -60,4 +60,22 @@ android:prompt="@string/Type" android:text="@string/Target_heart_rate_zone" android:visibility="gone" /> + + + + + diff --git a/app/res/values/pref_keys.xml b/app/res/values/pref_keys.xml index 279aae5b0..a5c2aab0f 100644 --- a/app/res/values/pref_keys.xml +++ b/app/res/values/pref_keys.xml @@ -81,6 +81,8 @@ basic_target_pace_max basic_target_pace_min_range basic_target_hrz + basic_enable_autolap_time + basic_autolap_time_duration intervalAudio intervalRepetitions diff --git a/app/src/main/org/runnerup/view/StartFragment.java b/app/src/main/org/runnerup/view/StartFragment.java index ed5bcb128..8c86ae38b 100644 --- a/app/src/main/org/runnerup/view/StartFragment.java +++ b/app/src/main/org/runnerup/view/StartFragment.java @@ -46,6 +46,7 @@ import android.widget.BaseAdapter; import android.widget.Button; import android.widget.CheckBox; +import android.widget.CompoundButton; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.ListView; @@ -147,6 +148,8 @@ private enum GpsLevel { TitleSpinner simpleTargetType = null; TitleSpinner simpleTargetPaceValue = null; TitleSpinner simpleTargetHrz = null; + CheckBox simpleEnableAutolapTime = null; + TitleSpinner simpleAutolapTime = null; AudioSchemeListAdapter simpleAudioListAdapter = null; HRZonesListAdapter hrZonesAdapter = null; @@ -166,6 +169,7 @@ private enum GpsLevel { AudioSchemeListAdapter advancedAudioListAdapter = null; SQLiteDatabase mDB = null; + SharedPreferences prefs = null; Formatter formatter = null; private NotificationStateManager notificationStateManager; @@ -190,6 +194,7 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat Context context = requireContext(); mDB = DBHelper.getWritableDatabase(context); formatter = new Formatter(context); + prefs = PreferenceManager.getDefaultSharedPreferences(context); bindGpsTracker(); mGpsStatus = new org.runnerup.tracker.GpsStatus(context); @@ -206,7 +211,6 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat context, R.layout.actionbar_spinner, Sport.getStringArray(getResources())); adapter.setDropDownViewResource(R.layout.actionbar_dropdown_spinner); sportSpinner.setAdapter(adapter); - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); sportSpinner.setViewSelection( prefs.getInt(getResources().getString(R.string.pref_sport), DB.ACTIVITY.SPORT_RUNNING)); @@ -271,6 +275,9 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat simpleTargetHrz = view.findViewById(R.id.tab_basic_target_hrz); simpleTargetHrz.setAdapter(hrZonesAdapter); simpleTargetType.setOnCloseDialogListener(simpleTargetTypeClick); + simpleEnableAutolapTime = view.findViewById(R.id.tab_basic_enable_autolap_time); + simpleAutolapTime = view.findViewById(R.id.tab_basic_autolap_time_duration); + simpleAutolapTime.setOnSetValueListener(onSetTimeValidator); intervalType = view.findViewById(R.id.interval_type); intervalTime = view.findViewById(R.id.start_interval_time); @@ -321,6 +328,17 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat mWearNotifier = new TrackerWear.WearNotifier(requireActivity().getApplicationContext()); mWearNotifier.onViewCreated(); + var enable_autolap_time_key = getString(R.string.pref_basic_enable_autolap_time); + simpleEnableAutolapTime.setChecked(prefs.getBoolean(enable_autolap_time_key, true)); + simpleEnableAutolapTime.setOnCheckedChangeListener( + new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton compoundButton, boolean b) { + prefs.edit().putBoolean(enable_autolap_time_key, b).apply(); + simpleAutolapTime.setEnabled(b); + } + }); + var listener = sportSpinner.getViewOnItemSelectedListener(); sportSpinner.setViewOnItemSelectedListener( new AdapterView.OnItemSelectedListener() { @@ -555,9 +573,7 @@ private void onGpsTrackerBound() { } public boolean getAutoStartGps() { - Context ctx = requireActivity().getApplicationContext(); - SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(ctx); - return pref.getBoolean(getString(R.string.pref_startgps), false); + return prefs.getBoolean(getString(R.string.pref_startgps), false); } private void startGps() { @@ -611,7 +627,6 @@ private void notificationBatteryLevel(int batteryLevel) { Context context = requireContext(); final String pref_key = getString(R.string.pref_battery_level_low_notification_discard); - final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); int batteryLevelHighThreshold = SafeParse.parseInt( @@ -689,6 +704,13 @@ private Workout prepareWorkout() { } if (w != null) { WorkoutBuilder.prepareWorkout(getResources(), pref, w); + if (sportWithoutGps && simpleEnableAutolapTime.isChecked()) { + long seconds = + SafeParse.parseSeconds(String.valueOf(simpleAutolapTime.getViewValueText()), 0); + if (seconds > 0) { + WorkoutBuilder.setAutolapTime(w, seconds); + } + } WorkoutBuilder.addAudioCuesToWorkout(getResources(), w, audioPref, pref); } return w; @@ -742,7 +764,6 @@ private List getPermissions() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { requiredPerms.add(Manifest.permission.ACCESS_BACKGROUND_LOCATION); - final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx); boolean enabled = prefs.getBoolean( this.getString(org.runnerup.R.string.pref_use_cadence_step_sensor), true); @@ -755,7 +776,6 @@ private List getPermissions() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S /* Android12, sdk31*/ && (packageManager.hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE) || packageManager.hasSystemFeature(PackageManager.FEATURE_BLUETOOTH))) { - final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx); final String btDeviceName = prefs.getString(getString(R.string.pref_bt_name), null); if (btDeviceName != null && !btDeviceName.isEmpty()) { requiredPerms.add(Manifest.permission.BLUETOOTH_CONNECT); @@ -856,7 +876,6 @@ private boolean checkPermissions(boolean popup) { // https://developer.android.com/training/monitoring-device-state/doze-standby#support_for_other_use_cases // Permission REQUEST_IGNORE_BATTERY_OPTIMIZATIONS requires special approval in Play - final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx); final Resources res = this.getResources(); final boolean suppressOptimizeBatteryPopup = prefs.getBoolean(res.getString(R.string.pref_suppress_battery_optimization_popup), false); @@ -947,6 +966,14 @@ public void updateView() { } else { noDevicesConnected.setVisibility(View.GONE); } + if (sportWithoutGps) { + simpleEnableAutolapTime.setVisibility(View.VISIBLE); + simpleAutolapTime.setVisibility(View.VISIBLE); + simpleAutolapTime.setEnabled(simpleEnableAutolapTime.isChecked()); + } else { + simpleEnableAutolapTime.setVisibility(View.GONE); + simpleAutolapTime.setVisibility(View.GONE); + } } private void updateStartButtonView() { @@ -1195,7 +1222,6 @@ public String getGpsAccuracyString(float accuracy) { private String getHRDetailString() { StringBuilder str = new StringBuilder(); - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(requireContext()); final String btDeviceName = prefs.getString(getString(R.string.pref_bt_name), null); if (btDeviceName != null) { diff --git a/app/src/main/org/runnerup/workout/Step.java b/app/src/main/org/runnerup/workout/Step.java index 037bf3338..a33b4e7c4 100644 --- a/app/src/main/org/runnerup/workout/Step.java +++ b/app/src/main/org/runnerup/workout/Step.java @@ -42,7 +42,10 @@ public class Step implements TickComponent { Range targetValue = null; /** Autolap (m) */ - private double autolap = 0; + private double autolap_distance = 0; + + /** Autolap (s) */ + private double autolap_time = 0; /** Triggers */ final ArrayList triggers = new ArrayList<>(); @@ -129,18 +132,19 @@ public void setIntensity(Intensity intensity) { this.intensity = intensity; } - /** - * @return the autolap distance (may be set in workouts too) - */ - double getAutolap() { - return autolap; - } - /** * @param val the autolap to set */ void setAutolap(double val) { - this.autolap = val; + this.autolap_distance = val; + } + + double getAutolapDistance() { + return autolap_distance; + } + + void setAutolapTime(double val) { + this.autolap_time = val; } @Override @@ -302,7 +306,7 @@ private boolean exceedDistance( } private boolean checkFinished(Workout s) { - if (this.getAutolap() == 0 && durationType == null) { + if (autolap_distance == 0 && durationType == null) { return false; } @@ -325,11 +329,18 @@ private boolean checkFinished(Workout s) { newStep = s.get(Scope.STEP, durationType) + diff >= this.durationValue; } - if (!newStep && this.getAutolap() > 0) { + if (!newStep) { double distance = s.getDistance(Scope.LAP); - double lapDist = getAutolap(); - if (exceedDistance(distance, mPrevTickLapDistance, lapDist, time)) { - newLap = true; + if (autolap_distance > 0) { + if (exceedDistance(distance, mPrevTickLapDistance, autolap_distance, time)) { + newLap = true; + } + } + if (autolap_time > 0) { + double lap_time = s.getTime(Scope.LAP); + if (lap_time >= autolap_time) { + newLap = true; + } } mPrevTickLapDistance = distance; } diff --git a/app/src/main/org/runnerup/workout/WorkoutBuilder.java b/app/src/main/org/runnerup/workout/WorkoutBuilder.java index 7e9305b20..33a5215b4 100644 --- a/app/src/main/org/runnerup/workout/WorkoutBuilder.java +++ b/app/src/main/org/runnerup/workout/WorkoutBuilder.java @@ -270,7 +270,7 @@ private static void addAudioCuesToWorkout( // Periodic distance/time and end of lap/step // Some suppressions for each intensity for related lap started/completed // endOfLap is related to the autolap - boolean endOfLap = step.getIntensity() == Intensity.ACTIVE || step.getAutolap() > 0; + boolean endOfLap = step.getIntensity() == Intensity.ACTIVE || step.getAutolapDistance() > 0; ArrayList defaultTriggers = createDefaultTriggers(res, audioPrefs, endOfLap); step.triggers.addAll(defaultTriggers); @@ -415,8 +415,8 @@ private static void checkDuplicateTriggers(Step step) { * trigger */ ArrayList list = new ArrayList<>(); - if (step.getAutolap() > 0) { - list.add(new EndOfLapSuppression(step.getAutolap())); + if (step.getAutolapDistance() > 0) { + list.add(new EndOfLapSuppression(step.getAutolapDistance())); } if (step.getDurationType() == Dimension.DISTANCE) { @@ -663,6 +663,15 @@ public static void prepareWorkout(Resources res, SharedPreferences prefs, Workou } } + public static void setAutolapTime(Workout w, double seconds) { + for (StepListEntry s : w.getStepList()) { + if (s.step().getIntensity() == Intensity.ACTIVE + || s.step().getIntensity() == Intensity.COOLDOWN) { + s.step().setAutolapTime(seconds); + } + } + } + public static void addFeedbackFromPreferences( SharedPreferences prefs, Resources res, ArrayList feedback) { int feedbackStart = feedback.size(); diff --git a/common/src/main/res/values/strings.xml b/common/src/main/res/values/strings.xml index fb3a4eab2..6eff017f6 100644 --- a/common/src/main/res/values/strings.xml +++ b/common/src/main/res/values/strings.xml @@ -164,6 +164,8 @@ Heart rate monitor Heart rate zones Autolap + Enable autolap by time + time Autolap (m) Autopause Autopause in basic workouts and Warmup and Cooldown steps