forked from upstream-mirrors/OpenTracks
Announcements: can be triggered by time and distance (instead of either).
Fixes #921.
This commit is contained in:
@@ -77,7 +77,7 @@ public class TrackListActivity extends AbstractTrackDeleteActivity implements Co
|
||||
|
||||
private static final String TAG = TrackListActivity.class.getSimpleName();
|
||||
|
||||
// The following are set in onCreate
|
||||
// The following are setFrequency in onCreate
|
||||
private SharedPreferences sharedPreferences;
|
||||
private TrackRecordingServiceConnection trackRecordingServiceConnection;
|
||||
private ResourceCursorAdapter resourceCursorAdapter;
|
||||
|
||||
@@ -66,7 +66,7 @@ public class TrackRecordedActivity extends AbstractTrackDeleteActivity implement
|
||||
|
||||
private static final String CURRENT_TAB_TAG_KEY = "current_tab_tag_key";
|
||||
|
||||
// The following are set in onCreate.
|
||||
// The following are setFrequency in onCreate.
|
||||
private ContentProviderUtils contentProviderUtils;
|
||||
private SharedPreferences sharedPreferences;
|
||||
private TrackDataHub trackDataHub;
|
||||
|
||||
@@ -51,7 +51,7 @@ public class TrackRecordingActivity extends AbstractActivity implements ChooseAc
|
||||
|
||||
private static final String CURRENT_TAB_TAG_KEY = "current_tab_tag_key";
|
||||
|
||||
// The following are set in onCreate
|
||||
// The following are setFrequency in onCreate
|
||||
private ContentProviderUtils contentProviderUtils;
|
||||
private SharedPreferences sharedPreferences;
|
||||
private TrackRecordingServiceConnection trackRecordingServiceConnection;
|
||||
|
||||
@@ -108,7 +108,7 @@ public class ChartFragment extends Fragment implements TrackDataListener {
|
||||
};
|
||||
|
||||
/**
|
||||
* A runnable that will set the orange pointer as appropriate and redraw.
|
||||
* A runnable that will setFrequency the orange pointer as appropriate and redraw.
|
||||
*/
|
||||
private final Runnable updateChart = new Runnable() {
|
||||
@Override
|
||||
|
||||
@@ -73,7 +73,7 @@ public class TrackRecordingService extends Service implements TrackPointCreator.
|
||||
public static final RecordingData NOT_RECORDING = new RecordingData(null, null, null);
|
||||
public static final GpsStatusValue STATUS_GPS_DEFAULT = GpsStatusValue.GPS_NONE;
|
||||
|
||||
// The following variables are set in onCreate:
|
||||
// The following variables are setFrequency in onCreate:
|
||||
private VoiceAnnouncementManager voiceAnnouncementManager;
|
||||
private TrackRecordingServiceNotificationManager notificationManager;
|
||||
|
||||
@@ -104,20 +104,21 @@ public class TrackRecordingService extends Service implements TrackPointCreator.
|
||||
Context context = TrackRecordingService.this;
|
||||
if (PreferencesUtils.isKey(context, R.string.stats_units_key, key)) {
|
||||
boolean metricUnits = PreferencesUtils.isMetricUnits(sharedPreferences, context);
|
||||
voiceAnnouncementManager.setMetricUnits(metricUnits);
|
||||
notificationManager.setMetricUnits(metricUnits);
|
||||
}
|
||||
if (PreferencesUtils.isKey(context, R.string.voice_frequency_key, key)) {
|
||||
voiceAnnouncementManager.setTaskFrequency(PreferencesUtils.getVoiceFrequency(sharedPreferences, context));
|
||||
if (PreferencesUtils.isKey(context, R.string.voice_announcement_frequency_key, key)) {
|
||||
voiceAnnouncementManager.setFrequency(PreferencesUtils.getVoiceAnnouncementFrequency(sharedPreferences, context));
|
||||
}
|
||||
if (PreferencesUtils.isKey(context, new int[]{R.string.voice_announcement_distance_key, R.string.stats_units_key}, key)) {
|
||||
voiceAnnouncementManager.setFrequency(PreferencesUtils.getVoiceAnnouncementDistance(sharedPreferences, context));
|
||||
}
|
||||
|
||||
|
||||
trackPointCreator.onSharedPreferenceChanged(sharedPreferences, key);
|
||||
trackRecordingManager.onSharedPreferenceChanged(sharedPreferences, key);
|
||||
}
|
||||
};
|
||||
|
||||
// The following variables are set when recording:
|
||||
// The following variables are setFrequency when recording:
|
||||
private WakeLock wakeLock;
|
||||
|
||||
private final Binder binder = new Binder();
|
||||
|
||||
+38
-61
@@ -40,48 +40,35 @@ public class VoiceAnnouncementManager {
|
||||
|
||||
private final TrackRecordingService trackRecordingService;
|
||||
|
||||
private final int TASK_FREQUENCY_OFF;
|
||||
/**
|
||||
* The task frequency.
|
||||
* A positive value is a time frequency (minutes).
|
||||
* A negative value is a distance frequency (km or mi).
|
||||
* A zero value is to turn off periodic task.
|
||||
*/
|
||||
private int taskFrequency;
|
||||
|
||||
private VoiceAnnouncement voiceAnnouncement;
|
||||
|
||||
private boolean metricUnits;
|
||||
|
||||
private TrackStatistics trackStatistics;
|
||||
|
||||
private static final Distance DISTANCE_OFF = Distance.of(Double.MAX_VALUE);
|
||||
private Distance distanceFrequency = DISTANCE_OFF;
|
||||
@NonNull
|
||||
private Distance nextTotalDistance = DISTANCE_OFF;
|
||||
|
||||
private static final Duration TOTALTIME_OFF = Duration.ofMillis(Long.MAX_VALUE);
|
||||
private Duration totalTimeFrequency = TOTALTIME_OFF;
|
||||
@NonNull
|
||||
private Duration nextTotalTime = TOTALTIME_OFF;
|
||||
|
||||
public VoiceAnnouncementManager(@NonNull TrackRecordingService trackRecordingService) {
|
||||
this.trackRecordingService = trackRecordingService;
|
||||
|
||||
TASK_FREQUENCY_OFF = Integer.parseInt(trackRecordingService.getString(R.string.frequency_off));
|
||||
taskFrequency = TASK_FREQUENCY_OFF;
|
||||
}
|
||||
|
||||
public void restore(@Nullable TrackStatistics trackStatistics) {
|
||||
if (taskFrequency == TASK_FREQUENCY_OFF) {
|
||||
Log.d(TAG, "Task frequency is off.");
|
||||
return;
|
||||
}
|
||||
|
||||
voiceAnnouncement = new VoiceAnnouncement(trackRecordingService);
|
||||
voiceAnnouncement.start();
|
||||
|
||||
if (isTimeFrequency()) {
|
||||
nextTotalTime = trackStatistics != null ? calculateNextDuration(trackStatistics) : TOTALTIME_OFF;
|
||||
} else {
|
||||
// For distance periodic task
|
||||
updateNextTaskDistance(trackStatistics);
|
||||
this.trackStatistics = trackStatistics;
|
||||
|
||||
if (!totalTimeFrequency.isZero()) {
|
||||
nextTotalTime = calculateNextDuration();
|
||||
}
|
||||
if (!distanceFrequency.isZero()) {
|
||||
nextTotalDistance = calculateNextTaskDistance();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,14 +77,15 @@ public class VoiceAnnouncementManager {
|
||||
Log.e(TAG, "Cannot update when in status shutdown.");
|
||||
return;
|
||||
}
|
||||
|
||||
boolean announce = false;
|
||||
this.trackStatistics = track.getTrackStatistics();
|
||||
if (trackStatistics.getTotalDistance().greaterThan(nextTotalDistance)) {
|
||||
updateNextTaskDistance(trackStatistics);
|
||||
nextTotalDistance = calculateNextTaskDistance();
|
||||
announce = true;
|
||||
}
|
||||
if (!trackStatistics.getTotalTime().minus(nextTotalTime).isNegative()) {
|
||||
nextTotalTime = calculateNextDuration(trackStatistics);
|
||||
nextTotalTime = calculateNextDuration();
|
||||
announce = true;
|
||||
}
|
||||
|
||||
@@ -113,59 +101,48 @@ public class VoiceAnnouncementManager {
|
||||
}
|
||||
}
|
||||
|
||||
public void setTaskFrequency(int taskFrequency) {
|
||||
this.taskFrequency = taskFrequency;
|
||||
public void setFrequency(Duration frequency) {
|
||||
this.totalTimeFrequency = frequency;
|
||||
restore(this.trackStatistics);
|
||||
}
|
||||
|
||||
public void setMetricUnits(boolean metricUnits) {
|
||||
this.metricUnits = metricUnits;
|
||||
updateNextTaskDistance(this.trackStatistics);
|
||||
}
|
||||
|
||||
private void updateNextTaskDistance(TrackStatistics trackStatistics) {
|
||||
if (!isDistanceFrequency()) {
|
||||
nextTotalDistance = DISTANCE_OFF;
|
||||
Log.d(TAG, "SplitManager: Distance splits disabled.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (trackStatistics == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
nextTotalDistance = calculateNextTaskDistance(trackStatistics);
|
||||
public void setFrequency(Distance frequency) {
|
||||
this.distanceFrequency = frequency;
|
||||
restore(this.trackStatistics);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public Distance calculateNextTaskDistance(@NonNull TrackStatistics trackStatistics) {
|
||||
public Distance calculateNextTaskDistance() {
|
||||
if (trackStatistics == null) {
|
||||
return DISTANCE_OFF;
|
||||
}
|
||||
|
||||
Distance distance = trackStatistics.getTotalDistance();
|
||||
|
||||
Distance announcementInterval = Distance.one(metricUnits).multipliedBy(Math.abs(taskFrequency));
|
||||
int index = (int) (distance.dividedBy(announcementInterval));
|
||||
return announcementInterval.multipliedBy(index + 1);
|
||||
int index = (int) (distance.dividedBy(distanceFrequency));
|
||||
return distanceFrequency.multipliedBy(index + 1);
|
||||
}
|
||||
|
||||
private Duration calculateNextDuration(@Nullable TrackStatistics trackStatistics) {
|
||||
private Duration calculateNextDuration() {
|
||||
if (trackStatistics == null) {
|
||||
return null;
|
||||
return TOTALTIME_OFF;
|
||||
}
|
||||
|
||||
if (!isTimeFrequency()) {
|
||||
throw new RuntimeException("Using distance frequency as time frequency is impossible.");
|
||||
}
|
||||
Duration totalTime = trackStatistics.getTotalTime();
|
||||
Duration interval = Duration.ofMinutes(taskFrequency);
|
||||
Duration intervalMod = Duration.ofMillis(trackStatistics.getTotalTime().toMillis() % interval.toMillis());
|
||||
Duration intervalMod = Duration.ofMillis(trackStatistics.getTotalTime().toMillis() % totalTimeFrequency.toMillis());
|
||||
|
||||
return totalTime.plus(interval.minus(intervalMod));
|
||||
return totalTime.plus(totalTimeFrequency.minus(intervalMod));
|
||||
}
|
||||
|
||||
private boolean isTimeFrequency() {
|
||||
return taskFrequency > 0;
|
||||
@VisibleForTesting
|
||||
@NonNull
|
||||
public Duration getNextTotalTime() {
|
||||
return nextTotalTime;
|
||||
}
|
||||
|
||||
private boolean isDistanceFrequency() {
|
||||
return taskFrequency < 0;
|
||||
@VisibleForTesting
|
||||
@NonNull
|
||||
public Distance getNextTotalDistance() {
|
||||
return nextTotalDistance;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,12 +3,10 @@ package de.dennisguse.opentracks.settings;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.speech.tts.TextToSpeech;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.documentfile.provider.DocumentFile;
|
||||
@@ -286,8 +284,11 @@ public class SettingsActivity extends AbstractActivity implements ChooseActivity
|
||||
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 voiceFrequency = findPreference(getString(R.string.voice_announcement_frequency_key));
|
||||
voiceFrequency.setEntries(StringUtils.getAnnouncementFrequency(getActivity()));
|
||||
|
||||
ListPreference voiceDistance = findPreference(getString(R.string.voice_announcement_distance_key));
|
||||
voiceDistance.setEntries(StringUtils.getAnnouncementDistance(getActivity(), metricUnits));
|
||||
|
||||
ListPreference minRecordingInterval = findPreference(getString(R.string.min_recording_interval_key));
|
||||
minRecordingInterval.setEntries(PreferenceHelper.getMinRecordingIntervalEntries(getActivity()));
|
||||
|
||||
@@ -90,6 +90,15 @@ public class PreferencesUtils {
|
||||
return key == null || key.equals(getKey(context, keyId));
|
||||
}
|
||||
|
||||
public static boolean isKey(Context context, int[] keyIds, String key) {
|
||||
for(int keyId : keyIds) {
|
||||
if (isKey(context, keyId, key)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean getBoolean(SharedPreferences sharedPreferences, Context context, int keyId, boolean defaultValue) {
|
||||
return sharedPreferences.getBoolean(getKey(context, keyId), defaultValue);
|
||||
}
|
||||
@@ -216,13 +225,23 @@ public class PreferencesUtils {
|
||||
return getBoolean(sharedPreferences, context, R.string.stats_fullscreen_while_recording_key, DEFAULT);
|
||||
}
|
||||
|
||||
public static int getVoiceFrequency(SharedPreferences sharedPreferences, Context context) {
|
||||
final int VOICE_FREQUENCY_DEFAULT = Integer.parseInt(context.getResources().getString(R.string.voice_frequency_default));
|
||||
return getInt(sharedPreferences, context, R.string.voice_frequency_key, VOICE_FREQUENCY_DEFAULT);
|
||||
public static Duration getVoiceAnnouncementFrequency(SharedPreferences sharedPreferences, Context context) {
|
||||
final int DEFAULT = Integer.parseInt(context.getResources().getString(R.string.voice_announcement_frequency_default));
|
||||
int value = getInt(sharedPreferences, context, R.string.voice_announcement_frequency_key, DEFAULT);
|
||||
return Duration.ofSeconds(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Result depends on isMetricUnits
|
||||
*/
|
||||
public static Distance getVoiceAnnouncementDistance(SharedPreferences sharedPreferences, Context context) {
|
||||
final float DEFAULT = Integer.parseInt(context.getResources().getString(R.string.voice_announcement_distance_default));
|
||||
float value = getFloat(sharedPreferences, context, R.string.voice_announcement_distance_key, DEFAULT);
|
||||
return Distance.one(isMetricUnits(sharedPreferences, context)).multipliedBy(value);
|
||||
}
|
||||
|
||||
public static float getVoiceSpeedRate(SharedPreferences sharedPreferences, Context context) {
|
||||
final float DEFAULT = Float.parseFloat(context.getResources().getString(R.string.voice_frequency_default));
|
||||
final float DEFAULT = Float.parseFloat(context.getResources().getString(R.string.voice_speed_rate_default));
|
||||
return getFloat(sharedPreferences, context, R.string.voice_speed_rate_key, DEFAULT);
|
||||
}
|
||||
|
||||
|
||||
@@ -292,28 +292,34 @@ public class StringUtils {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the frequency display options.
|
||||
*
|
||||
* @param context the context
|
||||
* @param metricUnits true to display in metric units
|
||||
*/
|
||||
public static String[] getFrequencyOptions(Context context, boolean metricUnits) {
|
||||
String[] values = context.getResources().getStringArray(R.array.frequency_values);
|
||||
public static String[] getAnnouncementFrequency(Context context) {
|
||||
String[] values = context.getResources().getStringArray(R.array.voice_announcement_frequency_values);
|
||||
String[] options = new String[values.length];
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
int value = Integer.parseInt(values[i]);
|
||||
if (context.getString(R.string.frequency_off).equals(values[i])) {
|
||||
if (context.getString(R.string.announcement_off).equals(values[i])) {
|
||||
options[i] = context.getString(R.string.value_off);
|
||||
} else if (value < 0) {
|
||||
options[i] = context.getString(metricUnits ? R.string.value_integer_kilometer : R.string.value_integer_mile, Math.abs(value));
|
||||
} else {
|
||||
int value = Integer.parseInt(values[i]);
|
||||
options[i] = context.getString(R.string.value_integer_minute, value);
|
||||
}
|
||||
}
|
||||
return options;
|
||||
}
|
||||
|
||||
public static String[] getAnnouncementDistance(Context context, boolean metricUnits) {
|
||||
String[] values = context.getResources().getStringArray(R.array.voice_announcement_distance_values);
|
||||
String[] options = new String[values.length];
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
if (context.getString(R.string.announcement_off).equals(values[i])) {
|
||||
options[i] = context.getString(R.string.value_off);
|
||||
} else {
|
||||
int value = Integer.parseInt(values[i]);
|
||||
options[i] = context.getString(metricUnits ? R.string.value_integer_kilometer : R.string.value_integer_mile, value);
|
||||
}
|
||||
}
|
||||
return options;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the formatted altitude_m (or null) and it's unit as {@link Pair}
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user