forked from upstream-mirrors/OpenTracks
Bugfix: voice announcements need to use KM/Miles (instead of m/feet).
Fixes #722.
This commit is contained in:
@@ -31,6 +31,7 @@ import androidx.test.rule.GrantPermissionRule;
|
|||||||
import androidx.test.rule.ServiceTestRule;
|
import androidx.test.rule.ServiceTestRule;
|
||||||
|
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
|
import org.junit.AfterClass;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
@@ -83,6 +84,10 @@ public class TrackRecordingServiceTest {
|
|||||||
if (Looper.myLooper() == null) Looper.prepare();
|
if (Looper.myLooper() == null) Looper.prepare();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@AfterClass
|
||||||
|
public static void finalTearDown() {
|
||||||
|
if (Looper.myLooper() != null) Looper.myLooper().quit();
|
||||||
|
}
|
||||||
|
|
||||||
private final Context context = ApplicationProvider.getApplicationContext();
|
private final Context context = ApplicationProvider.getApplicationContext();
|
||||||
private final SharedPreferences sharedPreferences = PreferencesUtils.getSharedPreferences(context);
|
private final SharedPreferences sharedPreferences = PreferencesUtils.getSharedPreferences(context);
|
||||||
|
|||||||
-59
@@ -1,59 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010 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.services.tasks;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.os.Looper;
|
|
||||||
|
|
||||||
import androidx.test.core.app.ApplicationProvider;
|
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
|
||||||
|
|
||||||
import org.junit.AfterClass;
|
|
||||||
import org.junit.BeforeClass;
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.junit.runner.RunWith;
|
|
||||||
|
|
||||||
import static org.junit.Assert.assertTrue;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests for {@link AnnouncementPeriodicTaskFactory}.
|
|
||||||
*
|
|
||||||
* @author Rodrigo Damazio
|
|
||||||
*/
|
|
||||||
@RunWith(AndroidJUnit4.class)
|
|
||||||
public class AnnouncementPeriodicTaskFactoryTest {
|
|
||||||
|
|
||||||
private final Context context = ApplicationProvider.getApplicationContext();
|
|
||||||
|
|
||||||
@BeforeClass
|
|
||||||
public static void preSetUp() {
|
|
||||||
// Prepare looper for Android's message queue
|
|
||||||
if (Looper.myLooper() == null) Looper.prepare();
|
|
||||||
}
|
|
||||||
|
|
||||||
@AfterClass
|
|
||||||
public static void finalTearDown() {
|
|
||||||
if (Looper.myLooper() != null) Looper.myLooper().quit();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testCreate() {
|
|
||||||
PeriodicTaskFactory factory = new AnnouncementPeriodicTaskFactory();
|
|
||||||
PeriodicTask task = factory.create(context);
|
|
||||||
assertTrue(task instanceof AnnouncementPeriodicTask);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+69
@@ -0,0 +1,69 @@
|
|||||||
|
package de.dennisguse.opentracks.services.tasks;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Looper;
|
||||||
|
|
||||||
|
import androidx.test.core.app.ApplicationProvider;
|
||||||
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
|
import androidx.test.rule.GrantPermissionRule;
|
||||||
|
import androidx.test.rule.ServiceTestRule;
|
||||||
|
|
||||||
|
import org.junit.AfterClass;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.TimeoutException;
|
||||||
|
|
||||||
|
import de.dennisguse.opentracks.content.data.Distance;
|
||||||
|
import de.dennisguse.opentracks.services.TrackRecordingService;
|
||||||
|
import de.dennisguse.opentracks.stats.TrackStatistics;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
public class PeriodicTaskExecutorTest {
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public final ServiceTestRule mServiceRule = ServiceTestRule.withTimeout(5, TimeUnit.SECONDS);
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public GrantPermissionRule mRuntimePermissionRule = GrantPermissionRule.grant(android.Manifest.permission.ACCESS_FINE_LOCATION);
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void preSetUp() {
|
||||||
|
// Prepare looper for Android's message queue
|
||||||
|
if (Looper.myLooper() == null) Looper.prepare();
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterClass
|
||||||
|
public static void finalTearDown() {
|
||||||
|
if (Looper.myLooper() != null) Looper.myLooper().quit();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private final Context context = ApplicationProvider.getApplicationContext();
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void calculateNextTaskDistance() throws TimeoutException {
|
||||||
|
// given
|
||||||
|
TrackRecordingService service = ((TrackRecordingService.Binder) mServiceRule.bindService(new Intent(context, TrackRecordingService.class)))
|
||||||
|
.getService();
|
||||||
|
|
||||||
|
PeriodicTaskExecutor periodicTaskExecutor = new PeriodicTaskExecutor(service, new AnnouncementPeriodicTask.Factory());
|
||||||
|
periodicTaskExecutor.setMetricUnits(true);
|
||||||
|
periodicTaskExecutor.setTaskFrequency(-5);
|
||||||
|
|
||||||
|
// when
|
||||||
|
TrackStatistics statistics = new TrackStatistics();
|
||||||
|
statistics.setTotalDistance(Distance.of(13000));
|
||||||
|
assertEquals(Distance.of(15000), periodicTaskExecutor.calculateNextTaskDistance(statistics));
|
||||||
|
|
||||||
|
statistics.setTotalDistance(Distance.of(15100));
|
||||||
|
assertEquals(Distance.of(20000), periodicTaskExecutor.calculateNextTaskDistance(statistics));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -54,7 +54,7 @@ import de.dennisguse.opentracks.services.handlers.GpsStatusValue;
|
|||||||
import de.dennisguse.opentracks.services.handlers.HandlerServer;
|
import de.dennisguse.opentracks.services.handlers.HandlerServer;
|
||||||
import de.dennisguse.opentracks.services.sensors.AltitudeSumManager;
|
import de.dennisguse.opentracks.services.sensors.AltitudeSumManager;
|
||||||
import de.dennisguse.opentracks.services.sensors.BluetoothRemoteSensorManager;
|
import de.dennisguse.opentracks.services.sensors.BluetoothRemoteSensorManager;
|
||||||
import de.dennisguse.opentracks.services.tasks.AnnouncementPeriodicTaskFactory;
|
import de.dennisguse.opentracks.services.tasks.AnnouncementPeriodicTask;
|
||||||
import de.dennisguse.opentracks.services.tasks.PeriodicTaskExecutor;
|
import de.dennisguse.opentracks.services.tasks.PeriodicTaskExecutor;
|
||||||
import de.dennisguse.opentracks.settings.SettingsActivity;
|
import de.dennisguse.opentracks.settings.SettingsActivity;
|
||||||
import de.dennisguse.opentracks.stats.TrackStatistics;
|
import de.dennisguse.opentracks.stats.TrackStatistics;
|
||||||
@@ -139,7 +139,7 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
|
|||||||
handlerServer = new HandlerServer(this);
|
handlerServer = new HandlerServer(this);
|
||||||
|
|
||||||
contentProviderUtils = new ContentProviderUtils(this);
|
contentProviderUtils = new ContentProviderUtils(this);
|
||||||
voiceExecutor = new PeriodicTaskExecutor(this, new AnnouncementPeriodicTaskFactory());
|
voiceExecutor = new PeriodicTaskExecutor(this, new AnnouncementPeriodicTask.Factory());
|
||||||
|
|
||||||
notificationManager = new TrackRecordingServiceNotificationManager(this);
|
notificationManager = new TrackRecordingServiceNotificationManager(this);
|
||||||
|
|
||||||
|
|||||||
+17
-1
@@ -23,6 +23,8 @@ import android.speech.tts.TextToSpeech;
|
|||||||
import android.speech.tts.UtteranceProgressListener;
|
import android.speech.tts.UtteranceProgressListener;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
@@ -135,7 +137,7 @@ public class AnnouncementPeriodicTask implements PeriodicTask {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run(TrackRecordingService trackRecordingService) {
|
public void run(@NonNull TrackRecordingService trackRecordingService) {
|
||||||
if (trackRecordingService == null) {
|
if (trackRecordingService == null) {
|
||||||
Log.e(TAG, "TrackRecordingService is null.");
|
Log.e(TAG, "TrackRecordingService is null.");
|
||||||
return;
|
return;
|
||||||
@@ -231,4 +233,18 @@ public class AnnouncementPeriodicTask implements PeriodicTask {
|
|||||||
// We don't care about the utterance id. It is supplied here to force onUtteranceCompleted to be called.
|
// We don't care about the utterance id. It is supplied here to force onUtteranceCompleted to be called.
|
||||||
tts.speak(announcement, TextToSpeech.QUEUE_FLUSH, null, "not used");
|
tts.speak(announcement, TextToSpeech.QUEUE_FLUSH, null, "not used");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link PeriodicTaskFactory} for text-to-speech announcement periodic task.
|
||||||
|
*
|
||||||
|
* @author Rodrigo Damazio
|
||||||
|
*/
|
||||||
|
public static class Factory implements PeriodicTaskFactory {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@NonNull
|
||||||
|
public PeriodicTask create(Context context) {
|
||||||
|
return new AnnouncementPeriodicTask(context);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
-31
@@ -1,31 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010 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.services.tasks;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A {@link PeriodicTaskFactory} for text-to-speech announcement periodic task.
|
|
||||||
*
|
|
||||||
* @author Rodrigo Damazio
|
|
||||||
*/
|
|
||||||
public class AnnouncementPeriodicTaskFactory implements PeriodicTaskFactory {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public PeriodicTask create(Context context) {
|
|
||||||
return new AnnouncementPeriodicTask(context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
package de.dennisguse.opentracks.services.tasks;
|
package de.dennisguse.opentracks.services.tasks;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.services.TrackRecordingService;
|
import de.dennisguse.opentracks.services.TrackRecordingService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -35,7 +37,7 @@ public interface PeriodicTask {
|
|||||||
*
|
*
|
||||||
* @param trackRecordingService the track recording service
|
* @param trackRecordingService the track recording service
|
||||||
*/
|
*/
|
||||||
void run(TrackRecordingService trackRecordingService);
|
void run(@NonNull TrackRecordingService trackRecordingService);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shuts down this task and clean up resources.
|
* Shuts down this task and clean up resources.
|
||||||
|
|||||||
@@ -17,6 +17,9 @@ package de.dennisguse.opentracks.services.tasks;
|
|||||||
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.VisibleForTesting;
|
||||||
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.R;
|
import de.dennisguse.opentracks.R;
|
||||||
@@ -52,14 +55,13 @@ public class PeriodicTaskExecutor {
|
|||||||
|
|
||||||
private boolean metricUnits;
|
private boolean metricUnits;
|
||||||
|
|
||||||
// The next distance for the distance periodic task
|
private Distance nextTaskDistance = Distance.of(Double.MAX_VALUE);
|
||||||
private double nextTaskDistance = Double.MAX_VALUE;
|
|
||||||
|
|
||||||
public PeriodicTaskExecutor(TrackRecordingService trackRecordingService, PeriodicTaskFactory periodicTaskFactory) {
|
public PeriodicTaskExecutor(@NonNull TrackRecordingService trackRecordingService, PeriodicTaskFactory periodicTaskFactory) {
|
||||||
this.trackRecordingService = trackRecordingService;
|
this.trackRecordingService = trackRecordingService;
|
||||||
this.periodicTaskFactory = periodicTaskFactory;
|
this.periodicTaskFactory = periodicTaskFactory;
|
||||||
|
|
||||||
TASK_FREQUENCY_OFF = Integer.parseInt(trackRecordingService.getBaseContext().getResources().getString(R.string.frequency_off));
|
TASK_FREQUENCY_OFF = Integer.parseInt(trackRecordingService.getString(R.string.frequency_off));
|
||||||
taskFrequency = TASK_FREQUENCY_OFF;
|
taskFrequency = TASK_FREQUENCY_OFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,7 +99,7 @@ public class PeriodicTaskExecutor {
|
|||||||
timerTaskExecutor.scheduleTask(Duration.ofMinutes(taskFrequency));
|
timerTaskExecutor.scheduleTask(Duration.ofMinutes(taskFrequency));
|
||||||
} else {
|
} else {
|
||||||
// For distance periodic task
|
// For distance periodic task
|
||||||
calculateNextTaskDistance();
|
updateNextTaskDistance();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -128,59 +130,48 @@ public class PeriodicTaskExecutor {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Distance distance = trackStatistics.getTotalDistance();
|
if (trackStatistics.getTotalDistance().greaterThan(nextTaskDistance)) {
|
||||||
|
|
||||||
if (distance.greaterThan(Distance.of(nextTaskDistance))) {
|
|
||||||
periodicTask.run(trackRecordingService);
|
periodicTask.run(trackRecordingService);
|
||||||
calculateNextTaskDistance();
|
updateNextTaskDistance();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets task frequency.
|
|
||||||
*
|
|
||||||
* @param taskFrequency the task frequency
|
|
||||||
*/
|
|
||||||
public void setTaskFrequency(int taskFrequency) {
|
public void setTaskFrequency(int taskFrequency) {
|
||||||
this.taskFrequency = taskFrequency;
|
this.taskFrequency = taskFrequency;
|
||||||
restore();
|
restore();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets metricUnits.
|
|
||||||
*
|
|
||||||
* @param metricUnits true to use metric units
|
|
||||||
*/
|
|
||||||
public void setMetricUnits(boolean metricUnits) {
|
public void setMetricUnits(boolean metricUnits) {
|
||||||
this.metricUnits = metricUnits;
|
this.metricUnits = metricUnits;
|
||||||
calculateNextTaskDistance();
|
updateNextTaskDistance();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private void updateNextTaskDistance() {
|
||||||
* Calculates the next distance for the distance periodic task.
|
|
||||||
*/
|
|
||||||
private void calculateNextTaskDistance() {
|
|
||||||
if (!trackRecordingService.isRecording() || trackRecordingService.isPaused() || periodicTask == null) {
|
if (!trackRecordingService.isRecording() || trackRecordingService.isPaused() || periodicTask == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!isDistanceFrequency()) {
|
||||||
|
nextTaskDistance = Distance.of(Double.MAX_VALUE);
|
||||||
|
Log.d(TAG, "SplitManager: Distance splits disabled.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
TrackStatistics trackStatistics = trackRecordingService.getTrackStatistics();
|
TrackStatistics trackStatistics = trackRecordingService.getTrackStatistics();
|
||||||
if (trackStatistics == null) {
|
if (trackStatistics == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isDistanceFrequency()) {
|
nextTaskDistance = calculateNextTaskDistance(trackStatistics);
|
||||||
nextTaskDistance = Double.MAX_VALUE;
|
}
|
||||||
Log.d(TAG, "SplitManager: Distance splits disabled.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
double distance = trackStatistics.getTotalDistance().toKM_Miles(metricUnits);
|
@VisibleForTesting
|
||||||
|
public Distance calculateNextTaskDistance(TrackStatistics trackStatistics) {
|
||||||
|
Distance distance = trackStatistics.getTotalDistance();
|
||||||
|
|
||||||
// The index will be negative since the frequency is negative.
|
Distance announcementInterval = Distance.one(metricUnits).multipliedBy(Math.abs(taskFrequency));
|
||||||
int index = (int) (distance / taskFrequency);
|
int index = (int) (distance.dividedBy(announcementInterval));
|
||||||
index -= 1;
|
return announcementInterval.multipliedBy(index + 1);
|
||||||
nextTaskDistance = taskFrequency * index;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ package de.dennisguse.opentracks.services.tasks;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An interface for classes that can create {@link PeriodicTask}.
|
* An interface for classes that can create {@link PeriodicTask}.
|
||||||
*
|
*
|
||||||
@@ -30,5 +32,6 @@ interface PeriodicTaskFactory {
|
|||||||
*
|
*
|
||||||
* @return the task, or null if the task is not supported
|
* @return the task, or null if the task is not supported
|
||||||
*/
|
*/
|
||||||
|
@NonNull
|
||||||
PeriodicTask create(Context context);
|
PeriodicTask create(Context context);
|
||||||
}
|
}
|
||||||
@@ -219,6 +219,26 @@
|
|||||||
<item>@string/settings_recording_track_name_number_option</item>
|
<item>@string/settings_recording_track_name_number_option</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
|
<string name="voice_frequency_key" translatable="false">voiceFrequency</string>
|
||||||
|
<string name="voice_frequency_default" translatable="false">@string/frequency_off</string>
|
||||||
|
<string name="frequency_off" translatable="false">0</string>
|
||||||
|
<string-array name="frequency_values">
|
||||||
|
<item>@string/frequency_off</item>
|
||||||
|
<item>1</item>
|
||||||
|
<item>2</item>
|
||||||
|
<item>5</item>
|
||||||
|
<item>10</item>
|
||||||
|
<item>15</item>
|
||||||
|
<item>30</item>
|
||||||
|
<item>60</item>
|
||||||
|
<item>-1</item>
|
||||||
|
<item>-5</item>
|
||||||
|
<item>-10</item>
|
||||||
|
<item>-25</item>
|
||||||
|
<item>-50</item>
|
||||||
|
<item>-100</item>
|
||||||
|
</string-array>
|
||||||
|
|
||||||
<string name="export_trackfileformat_key" translatable="false">exportTrackFileFormat</string>
|
<string name="export_trackfileformat_key" translatable="false">exportTrackFileFormat</string>
|
||||||
<!-- See TrackFileFormat -->
|
<!-- See TrackFileFormat -->
|
||||||
<string name="export_trackfileformat_default" translatable="false">KMZ_WITH_TRACKDETAIL_AND_SENSORDATA_AND_PICTURES</string>
|
<string name="export_trackfileformat_default" translatable="false">KMZ_WITH_TRACKDETAIL_AND_SENSORDATA_AND_PICTURES</string>
|
||||||
|
|||||||
@@ -18,25 +18,6 @@
|
|||||||
|
|
||||||
<string name="split_frequency_key" translatable="false" tools:keep="@string/split_frequency_key">splitFrequency</string>
|
<string name="split_frequency_key" translatable="false" tools:keep="@string/split_frequency_key">splitFrequency</string>
|
||||||
<string name="split_frequency_default" translatable="false" tools:keep="@string/split_frequency_default">@string/frequency_off</string>
|
<string name="split_frequency_default" translatable="false" tools:keep="@string/split_frequency_default">@string/frequency_off</string>
|
||||||
<string name="voice_frequency_key" translatable="false">voiceFrequency</string>
|
|
||||||
<string name="voice_frequency_default" translatable="false">@string/frequency_off</string>
|
|
||||||
<string name="frequency_off" translatable="false">0</string>
|
|
||||||
<string-array name="frequency_values">
|
|
||||||
<item>@string/frequency_off</item>
|
|
||||||
<item>1</item>
|
|
||||||
<item>2</item>
|
|
||||||
<item>5</item>
|
|
||||||
<item>10</item>
|
|
||||||
<item>15</item>
|
|
||||||
<item>30</item>
|
|
||||||
<item>60</item>
|
|
||||||
<item>-1</item>
|
|
||||||
<item>-5</item>
|
|
||||||
<item>-10</item>
|
|
||||||
<item>-25</item>
|
|
||||||
<item>-50</item>
|
|
||||||
<item>-100</item>
|
|
||||||
</string-array>
|
|
||||||
|
|
||||||
<string name="chart_show_cadence_key" translatable="false" tools:keep="@string/chart_show_cadence_key">chartShowCadence</string>
|
<string name="chart_show_cadence_key" translatable="false" tools:keep="@string/chart_show_cadence_key">chartShowCadence</string>
|
||||||
<bool name="chart_show_cadence_default" translatable="false" tools:keep="@bool/chart_show_cadence_default">
|
<bool name="chart_show_cadence_default" translatable="false" tools:keep="@bool/chart_show_cadence_default">
|
||||||
|
|||||||
Reference in New Issue
Block a user