diff --git a/MyTracks/res/values-ca/arrays.xml b/MyTracks/res/values-ca/arrays.xml index 2eddecf5b..2bba332fa 100644 --- a/MyTracks/res/values-ca/arrays.xml +++ b/MyTracks/res/values-ca/arrays.xml @@ -112,9 +112,9 @@ limitations under the License. 3.1 miles (senyal GPS pobre) - - - Sense divisió + + + Inactiu 100 km 50 km 25 km @@ -130,8 +130,8 @@ limitations under the License. 1 min - - No splitting + + Inactiu 100 mi 50 mi 25 mi @@ -286,6 +286,8 @@ limitations under the License. Cap + ANT+ Sensors + SRM ANT+ Bridge Zephyr Bluetooth diff --git a/MyTracks/res/values-de/arrays.xml b/MyTracks/res/values-de/arrays.xml index ed7915fc8..f33ae9fe1 100644 --- a/MyTracks/res/values-de/arrays.xml +++ b/MyTracks/res/values-de/arrays.xml @@ -48,7 +48,6 @@ limitations under the License. 328 Fuß - 50 m @@ -113,9 +112,9 @@ limitations under the License. 3,1 Meilen (sehr schlechtes GPS-Signal) - - - Nicht zerteilen + + + Aus 100 km 50 km 25 km @@ -132,7 +131,7 @@ limitations under the License. - Nicht zerteilen + Aus 100 Meilen 50 Meilen 25 Meilen diff --git a/MyTracks/res/values-es/arrays.xml b/MyTracks/res/values-es/arrays.xml index 25bd36439..2c9ac030a 100644 --- a/MyTracks/res/values-es/arrays.xml +++ b/MyTracks/res/values-es/arrays.xml @@ -15,18 +15,6 @@ See the License for the specific language governing permissions and limitations under the License. --> - - - Apagado - 1 min - 2 min - 5 min - 10 min - 15 min - 30 min - 60 min - - 1 m @@ -112,9 +100,9 @@ limitations under the License. 3.1 miles (señal GPS débil) - - - No dividir + + + Apagado 100 km 50 km 25 km @@ -130,8 +118,8 @@ limitations under the License. 1 min - - No dividir + + Apagado 100 mi 50 mi 25 mi diff --git a/MyTracks/res/values-fr/arrays.xml b/MyTracks/res/values-fr/arrays.xml index 0c9eedf72..18740a364 100644 --- a/MyTracks/res/values-fr/arrays.xml +++ b/MyTracks/res/values-fr/arrays.xml @@ -15,18 +15,6 @@ See the License for the specific language governing permissions and limitations under the License. --> - - - Absent - 1 min - 2 min - 5 min - 10 min - 15 min - 30 min - 60 min - - 1 m @@ -112,10 +100,9 @@ limitations under the License. 3.1 miles (mauvais signal GPS) - - - - Pas de séparation + + + Absent 100 km 50 km 25 km @@ -131,8 +118,8 @@ limitations under the License. 1 min - - Pas de séparation + + Absent 100 mi 50 mi 25 mi @@ -310,5 +297,5 @@ limitations under the License. Pont SRM ANT+ Bluetooth Zephyr - + diff --git a/MyTracks/res/values-it/arrays.xml b/MyTracks/res/values-it/arrays.xml index 4b8e02cb5..9974d2fc2 100644 --- a/MyTracks/res/values-it/arrays.xml +++ b/MyTracks/res/values-it/arrays.xml @@ -15,18 +15,6 @@ See the License for the specific language governing permissions and limitations under the License. --> - - - Disattivato - 1 min - 2 min - 5 min - 10 min - 15 min - 30 min - 60 min - - 1 m @@ -112,9 +100,9 @@ limitations under the License. 3.1 mi (segnale GPS debole) - - - Non dividere + + + Disattivato 100 km 50 km 25 km @@ -130,8 +118,8 @@ limitations under the License. 1 min - - Non dividere + + Disattivato 100 mi 50 mi 25 mi diff --git a/MyTracks/res/values-ja/arrays.xml b/MyTracks/res/values-ja/arrays.xml index 582056996..31e45abee 100644 --- a/MyTracks/res/values-ja/arrays.xml +++ b/MyTracks/res/values-ja/arrays.xml @@ -15,19 +15,7 @@ See the License for the specific language governing permissions and limitations under the License. --> - - - 不使用 - 1 分 - 2 分 - 5 分 - 10 分 - 15 分 - 30 分 - 60 分 - - - + 1 m 2 m @@ -48,7 +36,6 @@ limitations under the License. 328 ft - 50 m @@ -68,7 +55,6 @@ limitations under the License. 3.1 mi - 電源節約 (動的制御) @@ -89,7 +75,6 @@ limitations under the License. 30 分 - 10 m (GPS信号強度良好) @@ -115,10 +100,9 @@ limitations under the License. 3.1 mi (GPS信号強度不良) - - - - 分割なし + + + 不使用 100 km 50 km 25 km @@ -134,8 +118,8 @@ limitations under the License. 1 分 - - 分割なし + + 不使用 100 mi 50 mi 25 mi @@ -294,4 +278,5 @@ limitations under the License. SRM ANT+ ブリッジ Zephyr Bluetooth + diff --git a/MyTracks/res/values-pl/arrays.xml b/MyTracks/res/values-pl/arrays.xml index 80c7d0dbd..bf55da1a4 100644 --- a/MyTracks/res/values-pl/arrays.xml +++ b/MyTracks/res/values-pl/arrays.xml @@ -15,18 +15,6 @@ See the License for the specific language governing permissions and limitations under the License. --> - - - Brak - 1 min - 2 min - 5 min - 10 min - 15 min - 30 min - 60 min - - 1 m @@ -112,9 +100,9 @@ limitations under the License. 3.1 mili (słaby sygnał GPS) - - - Brak dzielenia + + + Brak 100 km 50 km 25 km @@ -130,8 +118,8 @@ limitations under the License. 1 min - - Brak dzielenia + + Brak 100 mi 50 mi 25 mi @@ -146,7 +134,7 @@ limitations under the License. 2 min 1 min - + Nigdy diff --git a/MyTracks/res/values-pt-rBR/arrays.xml b/MyTracks/res/values-pt-rBR/arrays.xml index 8f442d0fd..60090ae40 100644 --- a/MyTracks/res/values-pt-rBR/arrays.xml +++ b/MyTracks/res/values-pt-rBR/arrays.xml @@ -15,21 +15,8 @@ See the License for the specific language governing permissions and limitations under the License. --> - - - Desligado - 1 min - 2 min - 5 min - 10 min - 15 min - 30 min - 60 min - - - - + 1 m 2 m 3 m @@ -37,9 +24,9 @@ limitations under the License. 5 m (recomendada) 10 m 100 m - + - + 3 pés 6 pés 10 pés @@ -47,31 +34,29 @@ limitations under the License. 16 pés (recomendado) 33 pés 328 pés - - + - + 50 m 100 m 200 m (recomendado) 500 m 1000 m 5000 m - + - + 164 pés 328 pés 656 pés (recomendado) 1640 pés 0.6 milhas 3.1 milhas - - + - + economia de bateria (adaptativo) alta precisão (adaptativo) máxima (recomendada) @@ -88,11 +73,10 @@ limitations under the License. 10 min 15 min 30 min - - + - + 10 m (sinal de GPS excelente) 20 m 50 m @@ -102,9 +86,9 @@ limitations under the License. 1000 m 2000 m 5000 m (sinal de GPS ruim) - + - + 33 pés (sinal de GPS excelente) 66 pés 165 pés @@ -114,12 +98,11 @@ limitations under the License. 0.6 milhas 1.2 milhas 3.1 milhas (sinal de GPS ruim) - + - - - - Sem divisões + + + Desligado 100 km 50 km 25 km @@ -135,8 +118,8 @@ limitations under the License. 1 min - - Sem divisões + + Desligado 100 mi 50 mi 25 mi diff --git a/MyTracks/res/values-sv/arrays.xml b/MyTracks/res/values-sv/arrays.xml index eb24d0ef3..fef8a4ec9 100644 --- a/MyTracks/res/values-sv/arrays.xml +++ b/MyTracks/res/values-sv/arrays.xml @@ -15,18 +15,6 @@ See the License for the specific language governing permissions and limitations under the License. --> - - - Av - 1 min - 2 min - 5 min - 10 min - 15 min - 30 min - 60 min - - 1 m @@ -67,7 +55,6 @@ limitations under the License. 3.1 miles - batterioptimerad (anpassningsbar) @@ -113,9 +100,9 @@ limitations under the License. 3.1 miles (dålig GPS-signal) - - - Ingen delning + + + Av 100 km 50 km 25 km @@ -131,8 +118,8 @@ limitations under the License. 1 min - - Ingen delning + + Av 100 mi 50 mi 25 mi diff --git a/MyTracks/res/values-zh-rCN/arrays.xml b/MyTracks/res/values-zh-rCN/arrays.xml index 48f15e956..e3108f9e2 100644 --- a/MyTracks/res/values-zh-rCN/arrays.xml +++ b/MyTracks/res/values-zh-rCN/arrays.xml @@ -15,18 +15,6 @@ See the License for the specific language governing permissions and limitations under the License. --> - - - 关闭 - 1 分钟 - 2 分钟 - 5 分钟 - 10 分钟 - 15 分钟 - 30 分钟 - 60 分钟 - - 1 米 @@ -112,9 +100,9 @@ limitations under the License. 3.1 英里 (糟糕的 GPS 信号) - - - 不分割 + + + 关闭 100 千米 50 千米 25 千米 @@ -130,8 +118,8 @@ limitations under the License. 1 分钟 - - 不分割 + + 关闭 100 英里 50 英里 25 英里 @@ -155,6 +143,7 @@ limitations under the License. 15 分钟 总是 + 未知 diff --git a/MyTracks/res/values/arrays.xml b/MyTracks/res/values/arrays.xml index d50dfd701..783668362 100644 --- a/MyTracks/res/values/arrays.xml +++ b/MyTracks/res/values/arrays.xml @@ -15,31 +15,6 @@ See the License for the specific language governing permissions and limitations under the License. --> - - - Off - 1 min - 2 min - 5 min - 10 min - 15 min - 30 min - 60 min - - - - - -1 - 1 - 2 - 5 - 10 - 15 - 30 - 60 - - - 1 m @@ -61,18 +36,6 @@ limitations under the License. 328 ft - - - 1 - 2 - 3 - 4 - 5 - 10 - 100 - - - 50 m @@ -92,17 +55,6 @@ limitations under the License. 3.1 miles - - - 50 - 100 - 200 - 500 - 1000 - 5000 - - - battery miser (adaptive) @@ -123,27 +75,6 @@ limitations under the License. 30 min - - - -2 - -1 - 0 - 2 - 3 - 4 - 5 - 10 - 20 - 30 - 60 - 120 - 300 - 480 - 900 - 1800 - - - 10 m (excellent GPS signal) @@ -169,23 +100,9 @@ limitations under the License. 3.1 miles (poor GPS signal) - - - 10 - 20 - 50 - 100 - 200 - 500 - 1000 - 2000 - 5000 - - - - - - No splitting + + + Off 100 km 50 km 25 km @@ -201,8 +118,8 @@ limitations under the License. 1 min - - No splitting + + Off 100 mi 50 mi 25 mi @@ -218,24 +135,6 @@ limitations under the License. 1 min - - - 0 - -100 - -50 - -25 - -10 - -5 - -1 - 60 - 30 - 15 - 10 - 5 - 2 - 1 - - Never @@ -245,16 +144,6 @@ limitations under the License. Always - - - 0 - 5 - 10 - 15 - -1 - - - unknown @@ -383,14 +272,6 @@ limitations under the License. way point - - - GPX - KML - CSV - TCX - - None ANT+ Sensors @@ -398,18 +279,4 @@ limitations under the License. Zephyr Bluetooth - - - @string/none - @string/ant_sensor_type - @string/srm_ant_bridge_sensor_type - @string/zephyr_sensor_type - - - - - @string/ant_sensor_type - @string/srm_ant_bridge_sensor_type - - diff --git a/MyTracks/res/values/arrays_do_not_translate.xml b/MyTracks/res/values/arrays_do_not_translate.xml new file mode 100644 index 000000000..219049f4f --- /dev/null +++ b/MyTracks/res/values/arrays_do_not_translate.xml @@ -0,0 +1,122 @@ + + + + + + 10 + 20 + 50 + 100 + 200 + 500 + 1000 + 2000 + 5000 + + + + 1 + 2 + 3 + 4 + 5 + 10 + 100 + + + + 1 + 2 + 3 + 4 + 5 + 10 + 100 + + + + 50 + 100 + 200 + 500 + 1000 + 5000 + + + + -2 + -1 + 0 + 2 + 3 + 4 + 5 + 10 + 20 + 30 + 60 + 120 + 300 + 480 + 900 + 1800 + + + + 0 + -100 + -50 + -25 + -10 + -5 + -1 + 60 + 30 + 15 + 10 + 5 + 2 + 1 + + + + 0 + 5 + 10 + 15 + -1 + + + + GPX + KML + CSV + TCX + + + + @string/none + @string/ant_sensor_type + @string/srm_ant_bridge_sensor_type + @string/zephyr_sensor_type + + + + @string/ant_sensor_type + @string/srm_ant_bridge_sensor_type + + diff --git a/MyTracks/res/xml/preferences.xml b/MyTracks/res/xml/preferences.xml index e4d0b093f..d964f124b 100644 --- a/MyTracks/res/xml/preferences.xml +++ b/MyTracks/res/xml/preferences.xml @@ -48,8 +48,8 @@ limitations under the License. android:key="@string/split_frequency_key" android:title="@string/settings_split_frequency" android:summary="@string/settings_split_frequency_summary" - android:entries="@array/split_frequency_options" - android:entryValues="@array/split_frequency_values" + android:entries="@array/task_frequency_options" + android:entryValues="@array/task_frequency_values" android:defaultValue="0" /> 0) && (splitExecuter != null)) { - splitExecuter.scheduleTask(splitFrequency * 60000); - } - calculateNextSplit(); - } - - /** - * Shuts down the manager. - */ - public void shutdown() { - if (splitExecuter != null) { - splitExecuter.shutdown(); - } - } - - /** - * Calculates the next distance that a split should be inserted at. - */ - public void calculateNextSplit() { - // TODO: Decouple service from this class once and forever. - if (!service.isRecording()) { - return; - } - - if (splitFrequency >= 0) { - nextSplitDistance = Double.MAX_VALUE; - Log.d(Constants.TAG, - "SplitManager: Distance splits disabled."); - return; - } - - double dist = service.getTripStatistics().getTotalDistance() / 1000; - if (!metricUnits) { - dist *= UnitConversions.KM_TO_MI; - } - // The index will be negative since the frequency is negative. - int index = (int) (dist / splitFrequency); - index -= 1; - nextSplitDistance = splitFrequency * index; - Log.d(Constants.TAG, - "SplitManager: Next split distance: " + nextSplitDistance); - } - - /** - * Updates split manager with new trip statistics. - */ - public void updateSplits() { - if (this.splitFrequency >= 0) { - return; - } - // Convert the distance in meters to km or mi. - double distance = service.getTripStatistics().getTotalDistance() / 1000.0; - if (!metricUnits) { - distance *= UnitConversions.KM_TO_MI; - } - - if (distance > this.nextSplitDistance) { - service.insertWaypoint(WaypointCreationRequest.DEFAULT_STATISTICS); - calculateNextSplit(); - } - } - - /** - * Sets the split frequency. - * < 0 Use the absolute value as a distance in the current measurement km - * or mi - * 0 Turn off splits - * > 0 Use the value as a time in minutes - * @param splitFrequency The frequency in time or distance - */ - public void setSplitFrequency(int splitFrequency) { - Log.d(Constants.TAG, - "setSplitFrequency: splitFrequency = " + splitFrequency); - this.splitFrequency = splitFrequency; - - // TODO: Decouple service from this class once and forever. - if (!service.isRecording()) { - return; - } - - if (splitFrequency < 1) { - if (splitExecuter != null) { - splitExecuter.shutdown(); - splitExecuter = null; - } - } - if (splitFrequency > 0) { - if (splitExecuter == null) { - TimeSplitTask splitter = new TimeSplitTask(); - splitExecuter = new PeriodicTaskExecuter(splitter, service); - } - splitExecuter.scheduleTask(splitFrequency * 60000); - } else { - // For distance based splits. - calculateNextSplit(); - } - } - - public void setMetricUnits(boolean metricUnits) { - this.metricUnits = metricUnits; - calculateNextSplit(); - } -} diff --git a/MyTracks/src/com/google/android/apps/mytracks/services/TaskExecuterManager.java b/MyTracks/src/com/google/android/apps/mytracks/services/TaskExecuterManager.java deleted file mode 100644 index ec3b47d82..000000000 --- a/MyTracks/src/com/google/android/apps/mytracks/services/TaskExecuterManager.java +++ /dev/null @@ -1,87 +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 com.google.android.apps.mytracks.services; - -import com.google.android.apps.mytracks.Constants; - -import android.util.Log; - -/** - * This class manages a period task executer. - * - * @author Sandor Dornbush - */ -public class TaskExecuterManager { - - private int frequency; - private final PeriodicTask task; - private PeriodicTaskExecuter executer; - - public TaskExecuterManager(int frequency, PeriodicTask task, - TrackRecordingService service) { - this.task = task; - setFrequency(frequency, service); - } - - public int getFrequency() { - return frequency; - } - - /** - * Sets the frequency that the task should be run at. - * If needed the task will be scheduled. - * - * @param frequency The frequency in minutes for the task to run - * @param service The service to run the task on - */ - public void setFrequency(int frequency, TrackRecordingService service) { - this.frequency = frequency; - Log.i(Constants.TAG, "Frequency set to " + frequency - + " for task " + task.getClass().getSimpleName()); - - if (frequency == -1) { - if (executer != null) { - executer.shutdown(); - executer = null; - Log.i(Constants.TAG, - "Shut down service: " + task.getClass().getSimpleName()); - } - } else { - if (executer == null) { - executer = new PeriodicTaskExecuter(task, service); - } - executer.scheduleTask(frequency * 60000); - } - } - - /** - * Restores the task at the current frequency. - */ - public void restore() { - if (frequency > 0) { - executer.scheduleTask(frequency * 60000); - } - } - - /** - * Shuts down this executer. - */ - public void shutdown() { - if (executer != null) { - executer.shutdown(); - } - } -} diff --git a/MyTracks/src/com/google/android/apps/mytracks/services/TrackRecordingService.java b/MyTracks/src/com/google/android/apps/mytracks/services/TrackRecordingService.java index fa15577d4..2934dbf69 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/services/TrackRecordingService.java +++ b/MyTracks/src/com/google/android/apps/mytracks/services/TrackRecordingService.java @@ -31,6 +31,9 @@ import com.google.android.apps.mytracks.content.WaypointsColumns; import com.google.android.apps.mytracks.content.Sensor.SensorDataSet; import com.google.android.apps.mytracks.services.sensors.SensorManager; import com.google.android.apps.mytracks.services.sensors.SensorManagerFactory; +import com.google.android.apps.mytracks.services.tasks.PeriodicTaskExecutor; +import com.google.android.apps.mytracks.services.tasks.SplitTask; +import com.google.android.apps.mytracks.services.tasks.StatusAnnouncerFactory; import com.google.android.apps.mytracks.stats.TripStatistics; import com.google.android.apps.mytracks.stats.TripStatisticsBuilder; import com.google.android.apps.mytracks.util.ApiFeatures; @@ -111,10 +114,10 @@ public class TrackRecordingService extends Service implements LocationListener { private double length; /** - * Status announcer executer. + * Status announcer executor. */ - private PeriodicTaskExecuter announcementExecuter; - private SplitManager splitManager; + private PeriodicTaskExecutor announcementExecutor; + private PeriodicTaskExecutor splitExecutor; private SensorManager sensorManager; @@ -185,11 +188,9 @@ public class TrackRecordingService extends Service implements LocationListener { private Location lastValidLocation; /** - * The frequency of status announcements. + * A service to run tasks outside of the main thread. */ - private int announcementFrequency = -1; - - private ExecutorService executerServce; + private ExecutorService executorService; /* * Utility functions @@ -273,7 +274,8 @@ public class TrackRecordingService extends Service implements LocationListener { "Caught SQLiteException: " + e.getMessage(), e); return false; } - splitManager.updateSplits(); + announcementExecutor.update(); + splitExecutor.update(); return true; } @@ -425,9 +427,7 @@ public class TrackRecordingService extends Service implements LocationListener { TripStatistics stats = track.getStatistics(); statsBuilder = new TripStatisticsBuilder(stats.getStartTime()); statsBuilder.setMinRecordingDistance(minRecordingDistance); - setUpAnnouncer(); - splitManager.restore(); length = 0; lastValidLocation = null; @@ -475,7 +475,8 @@ public class TrackRecordingService extends Service implements LocationListener { } } - splitManager.calculateNextSplit(); + announcementExecutor.restore(); + splitExecutor.restore(); } /* @@ -483,7 +484,7 @@ public class TrackRecordingService extends Service implements LocationListener { */ @Override public void onLocationChanged(final Location location) { - this.executerServce.submit( + executorService.submit( new Runnable() { @Override public void run() { @@ -662,8 +663,8 @@ public class TrackRecordingService extends Service implements LocationListener { notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); locationManager = (LocationManager) getSystemService(LOCATION_SERVICE); - splitManager = new SplitManager(this); + setUpTaskExecutors(); prefManager = new PreferenceManager(this); registerLocationListener(); @@ -688,49 +689,29 @@ public class TrackRecordingService extends Service implements LocationListener { prefManager.setRecordingTrack(recordingTrackId = -1); } showNotification(); - executerServce = Executors.newSingleThreadExecutor(); + executorService = Executors.newSingleThreadExecutor(); } /** - * Creates an {@link Executer} and schedules {@class SafeStatusAnnouncerTask}. - * The announcer requires a TTS service and user should have enabled - * the announcements, otherwise this method is no-op. + * Creates the periodic task executors. */ - private void setUpAnnouncer() { - Log.d(TAG, "TrackRecordingService.setUpAnnouncer: " - + announcementExecuter); - if (announcementFrequency != -1 && recordingTrackId != -1) { - handler.post(new Runnable() { - @Override - public void run() { - if (announcementExecuter == null) { - StatusAnnouncerFactory statusAnnouncerFactory = - new StatusAnnouncerFactory(ApiFeatures.getInstance()); - PeriodicTask announcer = statusAnnouncerFactory.create( - TrackRecordingService.this); - if (announcer == null) { - return; - } - - // TODO: Either use TaskExecuterManager everywhere, or get rid of it - announcementExecuter = new PeriodicTaskExecuter(announcer, - TrackRecordingService.this); - } - announcementExecuter.scheduleTask(announcementFrequency * 60000); - } - }); - } + private void setUpTaskExecutors() { + announcementExecutor = new PeriodicTaskExecutor( + this, new StatusAnnouncerFactory(ApiFeatures.getInstance())); + splitExecutor = new PeriodicTaskExecutor(this, new SplitTask.Factory()); } - private void shutdownAnnouncer() { - Log.d(TAG, "TrackRecordingService.shutdownAnnouncer: " - + announcementExecuter); - if (announcementExecuter != null) { - try { - announcementExecuter.shutdown(); - } finally { - announcementExecuter = null; - } + private void shutdownTaskExecutors() { + Log.d(TAG, "TrackRecordingService.shutdownExecuters"); + try { + announcementExecutor.shutdown(); + } finally { + announcementExecutor = null; + } + try { + splitExecutor.shutdown(); + } finally { + splitExecutor = null; } } @@ -747,9 +728,7 @@ public class TrackRecordingService extends Service implements LocationListener { timer.cancel(); timer.purge(); unregisterLocationListener(); - shutdownAnnouncer(); - splitManager.shutdown(); - splitManager = null; + shutdownTaskExecutors(); if (sensorManager != null) { sensorManager.shutdown(); sensorManager = null; @@ -1104,11 +1083,9 @@ public class TrackRecordingService extends Service implements LocationListener { waypointStatsBuilder = new TripStatisticsBuilder(startTime); waypointStatsBuilder.setMinRecordingDistance(minRecordingDistance); currentWaypointId = insertWaypoint(WaypointCreationRequest.DEFAULT_STATISTICS); - setUpAnnouncer(); length = 0; showNotification(); registerLocationListener(); - splitManager.restore(); sensorManager = SensorManagerFactory.getSensorManager(this); if (sensorManager != null) { sensorManager.onStartTrack(); @@ -1123,6 +1100,8 @@ public class TrackRecordingService extends Service implements LocationListener { // Notify the world that we're now recording. sendTrackBroadcast( R.string.track_started_broadcast_action, recordingTrackId); + announcementExecutor.restore(); + splitExecutor.restore(); return recordingTrackId; } @@ -1133,7 +1112,8 @@ public class TrackRecordingService extends Service implements LocationListener { throw new IllegalStateException("No recording track in progress!"); } - shutdownAnnouncer(); + announcementExecutor.shutdown(); + splitExecutor.shutdown(); isRecording = false; Track recordingTrack = providerUtils.getTrack(recordingTrackId); if (recordingTrack != null) { @@ -1193,19 +1173,6 @@ public class TrackRecordingService extends Service implements LocationListener { this.recordingTrackId = recordingTrackId; } - public int getAnnouncementFrequency() { - return announcementFrequency; - } - - public void setAnnouncementFrequency(int announcementFrequency) { - this.announcementFrequency = announcementFrequency; - if (announcementFrequency == -1) { - shutdownAnnouncer(); - } else { - setUpAnnouncer(); - } - } - public int getMaxRecordingDistance() { return maxRecordingDistance; } @@ -1251,7 +1218,16 @@ public class TrackRecordingService extends Service implements LocationListener { this.autoResumeTrackTimeout = autoResumeTrackTimeout; } - public SplitManager getSplitManager() { - return splitManager; + public void setAnnouncementFrequency(int announcementFrequency) { + announcementExecutor.setTaskFrequency(announcementFrequency); + } + + public void setSplitFrequency(int frequency) { + splitExecutor.setTaskFrequency(frequency); + } + + public void setMetricUnits(boolean metric) { + announcementExecutor.setMetricUnits(metric); + splitExecutor.setMetricUnits(metric); } } diff --git a/MyTracks/src/com/google/android/apps/mytracks/services/FroyoStatusAnnouncerTask.java b/MyTracks/src/com/google/android/apps/mytracks/services/tasks/FroyoStatusAnnouncerTask.java similarity index 97% rename from MyTracks/src/com/google/android/apps/mytracks/services/FroyoStatusAnnouncerTask.java rename to MyTracks/src/com/google/android/apps/mytracks/services/tasks/FroyoStatusAnnouncerTask.java index 06050a2c6..5bdec230a 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/services/FroyoStatusAnnouncerTask.java +++ b/MyTracks/src/com/google/android/apps/mytracks/services/tasks/FroyoStatusAnnouncerTask.java @@ -14,7 +14,7 @@ * the License. */ -package com.google.android.apps.mytracks.services; +package com.google.android.apps.mytracks.services.tasks; import static com.google.android.apps.mytracks.Constants.TAG; @@ -26,6 +26,7 @@ import android.util.Log; import java.util.HashMap; + /** * This class will periodically announce the user's trip statistics for Froyo and future handsets. * This class will request and release audio focus. diff --git a/MyTracks/src/com/google/android/apps/mytracks/services/PeriodicTask.java b/MyTracks/src/com/google/android/apps/mytracks/services/tasks/PeriodicTask.java similarity index 88% rename from MyTracks/src/com/google/android/apps/mytracks/services/PeriodicTask.java rename to MyTracks/src/com/google/android/apps/mytracks/services/tasks/PeriodicTask.java index 354b4bccd..1d351bec4 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/services/PeriodicTask.java +++ b/MyTracks/src/com/google/android/apps/mytracks/services/tasks/PeriodicTask.java @@ -14,7 +14,9 @@ * the License. */ -package com.google.android.apps.mytracks.services; +package com.google.android.apps.mytracks.services.tasks; + +import com.google.android.apps.mytracks.services.TrackRecordingService; /** * This is interface for a task that will be executed on some schedule. diff --git a/MyTracks/src/com/google/android/apps/mytracks/services/tasks/PeriodicTaskExecutor.java b/MyTracks/src/com/google/android/apps/mytracks/services/tasks/PeriodicTaskExecutor.java new file mode 100644 index 000000000..f307e4741 --- /dev/null +++ b/MyTracks/src/com/google/android/apps/mytracks/services/tasks/PeriodicTaskExecutor.java @@ -0,0 +1,189 @@ +/* + * 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 com.google.android.apps.mytracks.services.tasks; + +import static com.google.android.apps.mytracks.Constants.TAG; + +import com.google.android.apps.mytracks.services.TrackRecordingService; +import com.google.android.apps.mytracks.util.UnitConversions; + +import android.util.Log; + +/** + * Execute a task on a time or distance schedule. + * + * @author Sandor Dornbush + */ +public class PeriodicTaskExecutor { + + /** + * The frequency of the task. + * A value greater than zero is a frequency in time. + * A value less than zero is considered a frequency in distance. + */ + private int taskFrequency = 0; + + /** + * The next distance when the task should execute. + */ + private double nextTaskDistance = 0; + + /** + * Time based executor. + */ + private TimerTaskExecutor timerExecutor = null; + + private boolean metricUnits; + + private final TrackRecordingService service; + + private final PeriodicTaskFactory factory; + + private PeriodicTask task; + + public PeriodicTaskExecutor(TrackRecordingService service, PeriodicTaskFactory factory) { + this.service = service; + this.factory = factory; + } + + /** + * Restores the manager. + */ + public void restore() { + // TODO: Decouple service from this class once and forever. + if (!service.isRecording()) { + return; + } + + if (!isTimeFrequency()) { + if (timerExecutor != null) { + timerExecutor.shutdown(); + timerExecutor = null; + } + } + if (taskFrequency == 0) { + return; + } + + // Try to make the task. + task = factory.create(service); + // Returning null is ok. + if (task == null) { + return; + } + task.start(); + + if (isTimeFrequency()) { + if (timerExecutor == null) { + timerExecutor = new TimerTaskExecutor(task, service); + } + timerExecutor.scheduleTask(taskFrequency * 60000); + } else { + // For distance based splits. + calculateNextTaskDistance(); + } + } + + /** + * Shuts down the manager. + */ + public void shutdown() { + if (task != null) { + task.shutdown(); + task = null; + } + if (timerExecutor != null) { + timerExecutor.shutdown(); + timerExecutor = null; + } + } + + /** + * Calculates the next distance when the task should execute. + */ + void calculateNextTaskDistance() { + // TODO: Decouple service from this class once and forever. + if (!service.isRecording() || task == null) { + return; + } + + if (!isDistanceFrequency()) { + nextTaskDistance = Double.MAX_VALUE; + Log.d(TAG, "SplitManager: Distance splits disabled."); + return; + } + + double distance = service.getTripStatistics().getTotalDistance() / 1000; + if (!metricUnits) { + distance *= UnitConversions.KM_TO_MI; + } + // The index will be negative since the frequency is negative. + int index = (int) (distance / taskFrequency); + index -= 1; + nextTaskDistance = taskFrequency * index; + Log.d(TAG, "SplitManager: Next split distance: " + nextTaskDistance); + } + + /** + * Updates executer with new trip statistics. + */ + public void update() { + if (!isDistanceFrequency() || task == null) { + return; + } + // Convert the distance in meters to km or mi. + double distance = service.getTripStatistics().getTotalDistance() / 1000.0; + if (!metricUnits) { + distance *= UnitConversions.KM_TO_MI; + } + + if (distance > nextTaskDistance) { + task.run(service); + calculateNextTaskDistance(); + } + } + + private boolean isTimeFrequency() { + return taskFrequency > 0; + } + + private boolean isDistanceFrequency() { + return taskFrequency < 0; + } + + /** + * Sets the task frequency. + * < 0 Use the absolute value as a distance in the current measurement km + * or mi + * 0 Turn off the task + * > 0 Use the value as a time in minutes + * @param taskFrequency The frequency in time or distance + */ + public void setTaskFrequency(int taskFrequency) { + Log.d(TAG, "setTaskFrequency: taskFrequency = " + taskFrequency); + this.taskFrequency = taskFrequency; + restore(); + } + + public void setMetricUnits(boolean metricUnits) { + this.metricUnits = metricUnits; + calculateNextTaskDistance(); + } + + double getNextTaskDistance() { + return nextTaskDistance; + } +} diff --git a/MyTracks/src/com/google/android/apps/mytracks/services/tasks/PeriodicTaskFactory.java b/MyTracks/src/com/google/android/apps/mytracks/services/tasks/PeriodicTaskFactory.java new file mode 100644 index 000000000..f3f8be445 --- /dev/null +++ b/MyTracks/src/com/google/android/apps/mytracks/services/tasks/PeriodicTaskFactory.java @@ -0,0 +1,33 @@ +/* + * 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 com.google.android.apps.mytracks.services.tasks; + +import android.content.Context; + +/** + * An interface for classes that can create periodic tasks. + * + * @author Sandor Dornbush + */ +public interface PeriodicTaskFactory { + + /** + * Creates a periodic task which does voice announcements. + * + * @return the task, or null if task is not supported + */ + PeriodicTask create(Context context); +} \ No newline at end of file diff --git a/MyTracks/src/com/google/android/apps/mytracks/services/TimeSplitTask.java b/MyTracks/src/com/google/android/apps/mytracks/services/tasks/SplitTask.java similarity index 64% rename from MyTracks/src/com/google/android/apps/mytracks/services/TimeSplitTask.java rename to MyTracks/src/com/google/android/apps/mytracks/services/tasks/SplitTask.java index 333ce6ae4..763a922be 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/services/TimeSplitTask.java +++ b/MyTracks/src/com/google/android/apps/mytracks/services/tasks/SplitTask.java @@ -14,16 +14,22 @@ * the License. */ -package com.google.android.apps.mytracks.services; +package com.google.android.apps.mytracks.services.tasks; import com.google.android.apps.mytracks.content.WaypointCreationRequest; +import com.google.android.apps.mytracks.services.TrackRecordingService; + +import android.content.Context; /** - * A simple task to insert statistics markers every n minutes. + * A simple task to insert statistics markers periodically. * @author Sandor Dornbush */ -public class TimeSplitTask implements PeriodicTask { +public class SplitTask implements PeriodicTask { + + private SplitTask() { + } @Override public void run(TrackRecordingService service) { @@ -37,4 +43,15 @@ public class TimeSplitTask implements PeriodicTask { @Override public void start() { } + + /** + * Create new SplitTasks. + */ + public static class Factory implements PeriodicTaskFactory { + + @Override + public PeriodicTask create(Context context) { + return new SplitTask(); + } + } } diff --git a/MyTracks/src/com/google/android/apps/mytracks/services/StatusAnnouncerFactory.java b/MyTracks/src/com/google/android/apps/mytracks/services/tasks/StatusAnnouncerFactory.java similarity index 87% rename from MyTracks/src/com/google/android/apps/mytracks/services/StatusAnnouncerFactory.java rename to MyTracks/src/com/google/android/apps/mytracks/services/tasks/StatusAnnouncerFactory.java index 01216a164..30c87d781 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/services/StatusAnnouncerFactory.java +++ b/MyTracks/src/com/google/android/apps/mytracks/services/tasks/StatusAnnouncerFactory.java @@ -13,7 +13,7 @@ * License for the specific language governing permissions and limitations under * the License. */ -package com.google.android.apps.mytracks.services; +package com.google.android.apps.mytracks.services.tasks; import com.google.android.apps.mytracks.util.ApiFeatures; @@ -26,7 +26,7 @@ import android.media.AudioManager; * * @author Rodrigo Damazio */ -public class StatusAnnouncerFactory { +public class StatusAnnouncerFactory implements PeriodicTaskFactory { private final boolean hasTts; @@ -34,11 +34,7 @@ public class StatusAnnouncerFactory { this.hasTts = apiFeatures.hasTextToSpeech(); } - /** - * Creates a periodic task which does voice announcements. - * - * @return the task, or null if announcements are not supported - */ + @Override public PeriodicTask create(Context context) { if (hasTts) { if (ApiFeatures.getInstance().isAudioFocusSupported()) { diff --git a/MyTracks/src/com/google/android/apps/mytracks/services/StatusAnnouncerTask.java b/MyTracks/src/com/google/android/apps/mytracks/services/tasks/StatusAnnouncerTask.java similarity index 96% rename from MyTracks/src/com/google/android/apps/mytracks/services/StatusAnnouncerTask.java rename to MyTracks/src/com/google/android/apps/mytracks/services/tasks/StatusAnnouncerTask.java index 4f27556d1..bf0645b3e 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/services/StatusAnnouncerTask.java +++ b/MyTracks/src/com/google/android/apps/mytracks/services/tasks/StatusAnnouncerTask.java @@ -14,11 +14,12 @@ * the License. */ -package com.google.android.apps.mytracks.services; +package com.google.android.apps.mytracks.services.tasks; import static com.google.android.apps.mytracks.Constants.TAG; import com.google.android.apps.mytracks.Constants; +import com.google.android.apps.mytracks.services.TrackRecordingService; import com.google.android.apps.mytracks.stats.TripStatistics; import com.google.android.apps.mytracks.util.StringUtils; import com.google.android.apps.mytracks.util.UnitConversions; @@ -101,7 +102,8 @@ public class StatusAnnouncerTask implements PeriodicTask { */ protected void onTtsInit(int status) { Log.i(TAG, "TrackRecordingService.TTS init: " + status); - this.ready = status == TextToSpeech.SUCCESS; + // TTS should be valid here but NPE exceptions were reported to the market. + this.ready = status == TextToSpeech.SUCCESS && tts != null; if (ready) { // Force the language to be the same as the string we will be speaking, diff --git a/MyTracks/src/com/google/android/apps/mytracks/services/PeriodicTaskExecuter.java b/MyTracks/src/com/google/android/apps/mytracks/services/tasks/TimerTaskExecutor.java similarity index 81% rename from MyTracks/src/com/google/android/apps/mytracks/services/PeriodicTaskExecuter.java rename to MyTracks/src/com/google/android/apps/mytracks/services/tasks/TimerTaskExecutor.java index 955db49e1..ec7d66c05 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/services/PeriodicTaskExecuter.java +++ b/MyTracks/src/com/google/android/apps/mytracks/services/tasks/TimerTaskExecutor.java @@ -14,9 +14,9 @@ * the License. */ -package com.google.android.apps.mytracks.services; +package com.google.android.apps.mytracks.services.tasks; -import com.google.android.apps.mytracks.Constants; +import static com.google.android.apps.mytracks.Constants.TAG; import android.util.Log; @@ -24,12 +24,14 @@ import java.util.Date; import java.util.Timer; import java.util.TimerTask; +import com.google.android.apps.mytracks.services.TrackRecordingService; + /** - * This class will periodically announce the user's trip statistics. + * This class will periodically perform a task. * * @author Sandor Dornbush */ -public class PeriodicTaskExecuter { +public class TimerTaskExecutor { private final PeriodicTask task; private final TrackRecordingService service; @@ -40,8 +42,8 @@ public class PeriodicTaskExecuter { */ private Timer timer; - public PeriodicTaskExecuter(PeriodicTask task, - TrackRecordingService service) { + public TimerTaskExecutor(PeriodicTask task, + TrackRecordingService service) { this.task = task; this.service = service; } @@ -77,8 +79,7 @@ public class PeriodicTaskExecuter { } Date start = new Date(next); - Log.i(Constants.TAG, - task.getClass().getSimpleName() + " scheduled to start at " + start + Log.i(TAG, task.getClass().getSimpleName() + " scheduled to start at " + start + " every " + interval + " milliseconds."); timer.scheduleAtFixedRate(new PeriodicTimerTask(), start, interval); } @@ -87,8 +88,7 @@ public class PeriodicTaskExecuter { * Cleans up this object. */ public void shutdown() { - Log.i(Constants.TAG, - task.getClass().getSimpleName() + " shutting down."); + Log.i(TAG, task.getClass().getSimpleName() + " shutting down."); if (timer != null) { timer.cancel(); timer.purge(); diff --git a/MyTracksTest/src/com/google/android/apps/mytracks/services/StatusAnnouncerFactoryTest.java b/MyTracksTest/src/com/google/android/apps/mytracks/services/tasks/StatusAnnouncerFactoryTest.java similarity index 87% rename from MyTracksTest/src/com/google/android/apps/mytracks/services/StatusAnnouncerFactoryTest.java rename to MyTracksTest/src/com/google/android/apps/mytracks/services/tasks/StatusAnnouncerFactoryTest.java index 304002a8d..ea9a8d441 100644 --- a/MyTracksTest/src/com/google/android/apps/mytracks/services/StatusAnnouncerFactoryTest.java +++ b/MyTracksTest/src/com/google/android/apps/mytracks/services/tasks/StatusAnnouncerFactoryTest.java @@ -13,8 +13,11 @@ * License for the specific language governing permissions and limitations under * the License. */ -package com.google.android.apps.mytracks.services; +package com.google.android.apps.mytracks.services.tasks; +import com.google.android.apps.mytracks.services.tasks.PeriodicTask; +import com.google.android.apps.mytracks.services.tasks.StatusAnnouncerFactory; +import com.google.android.apps.mytracks.services.tasks.StatusAnnouncerTask; import com.google.android.apps.mytracks.util.ApiFeatures; import android.media.AudioManager; @@ -55,7 +58,7 @@ public class StatusAnnouncerFactoryTest extends AndroidTestCase { public void testCreate() { apiFeatures.setHasTextToSpeech(true); - StatusAnnouncerFactory factory = + PeriodicTaskFactory factory = new StatusAnnouncerFactory(apiFeatures); PeriodicTask task = factory.create(getContext()); assertTrue(task instanceof StatusAnnouncerTask); @@ -63,7 +66,7 @@ public class StatusAnnouncerFactoryTest extends AndroidTestCase { public void testCreate_notAvailable() { apiFeatures.setHasTextToSpeech(false); - StatusAnnouncerFactory factory = + PeriodicTaskFactory factory = new StatusAnnouncerFactory(apiFeatures); PeriodicTask task = factory.create(getContext()); assertNull(task); diff --git a/MyTracksTest/src/com/google/android/apps/mytracks/services/StatusAnnouncerTaskTest.java b/MyTracksTest/src/com/google/android/apps/mytracks/services/tasks/StatusAnnouncerTaskTest.java similarity index 99% rename from MyTracksTest/src/com/google/android/apps/mytracks/services/StatusAnnouncerTaskTest.java rename to MyTracksTest/src/com/google/android/apps/mytracks/services/tasks/StatusAnnouncerTaskTest.java index 4bc7a3664..5d0bc0c87 100644 --- a/MyTracksTest/src/com/google/android/apps/mytracks/services/StatusAnnouncerTaskTest.java +++ b/MyTracksTest/src/com/google/android/apps/mytracks/services/tasks/StatusAnnouncerTaskTest.java @@ -13,13 +13,14 @@ * License for the specific language governing permissions and limitations under * the License. */ -package com.google.android.apps.mytracks.services; +package com.google.android.apps.mytracks.services.tasks; import static com.google.android.testing.mocking.AndroidMock.capture; import static com.google.android.testing.mocking.AndroidMock.eq; import static com.google.android.testing.mocking.AndroidMock.expect; import static com.google.android.testing.mocking.AndroidMock.same; +import com.google.android.apps.mytracks.services.tasks.StatusAnnouncerTask; import com.google.android.apps.mytracks.stats.TripStatistics; import com.google.android.apps.mytracks.util.StringUtils; import com.google.android.testing.mocking.AndroidMock;