Merging to head.

This commit is contained in:
Rodrigo Damazio
2011-04-12 01:42:27 -03:00
parent 3501fff7fc
commit 28a5c5b343
40 changed files with 1701 additions and 996 deletions
+7 -5
View File
@@ -112,9 +112,9 @@ limitations under the License.
<item>3.1 miles (senyal GPS pobre)</item>
</string-array>
<!-- Split frequency -->
<string-array name="split_frequency_options">
<item>Sense divisió</item>
<!-- Task frequency -->
<string-array name="task_frequency_options">
<item>Inactiu</item>
<item>100 km</item>
<item>50 km</item>
<item>25 km</item>
@@ -130,8 +130,8 @@ limitations under the License.
<item>1 min</item>
</string-array>
<string-array name="split_frequency_options_ft">
<item>No splitting</item>
<string-array name="task_frequency_options_ft">
<item>Inactiu</item>
<item>100 mi</item>
<item>50 mi</item>
<item>25 mi</item>
@@ -286,6 +286,8 @@ limitations under the License.
<array name="sensor_type_options">
<item>Cap</item>
<item>ANT+ Sensors</item>
<item>SRM ANT+ Bridge</item>
<item>Zephyr Bluetooth</item>
</array>
+4 -5
View File
@@ -48,7 +48,6 @@ limitations under the License.
<item>328 Fuß</item>
</string-array>
<!-- Maximum recording distance -->
<string-array name="max_recording_distance_options">
<item>50 m</item>
@@ -113,9 +112,9 @@ limitations under the License.
<item>3,1 Meilen (sehr schlechtes GPS-Signal)</item>
</string-array>
<!-- Split frequency -->
<string-array name="split_frequency_options">
<item>Nicht zerteilen</item>
<!-- Task frequency -->
<string-array name="task_frequency_options">
<item>Aus</item>
<item>100 km</item>
<item>50 km</item>
<item>25 km</item>
@@ -132,7 +131,7 @@ limitations under the License.
</string-array>
<string-array name="split_frequency_options_ft">
<item>Nicht zerteilen</item>
<item>Aus</item>
<item>100 Meilen</item>
<item>50 Meilen</item>
<item>25 Meilen</item>
+5 -17
View File
@@ -15,18 +15,6 @@ See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<!-- Task frequency -->
<string-array name="task_frequency_options">
<item>Apagado</item>
<item>1 min</item>
<item>2 min</item>
<item>5 min</item>
<item>10 min</item>
<item>15 min</item>
<item>30 min</item>
<item>60 min</item>
</string-array>
<!-- Minimum recording distance -->
<string-array name="min_recording_distance_options">
<item>1 m</item>
@@ -112,9 +100,9 @@ limitations under the License.
<item>3.1 miles (señal GPS débil)</item>
</string-array>
<!-- Split frequency -->
<string-array name="split_frequency_options">
<item>No dividir</item>
<!-- Task frequency -->
<string-array name="task_frequency_options">
<item>Apagado</item>
<item>100 km</item>
<item>50 km</item>
<item>25 km</item>
@@ -130,8 +118,8 @@ limitations under the License.
<item>1 min</item>
</string-array>
<string-array name="split_frequency_options_ft">
<item>No dividir</item>
<string-array name="task_frequency_options_ft">
<item>Apagado</item>
<item>100 mi</item>
<item>50 mi</item>
<item>25 mi</item>
+10 -10
View File
@@ -25,7 +25,7 @@ limitations under the License.
<string name="delete_all_tracks">Borrar todos los recorridos</string>
<string name="settings">Configuraciones</string>
<string name="elevation">Elevación</string>
<string name="choose_track_message">Por favor seleccione el recorrido que desea ver</string>
<string name="choose_track_message">Por favor, seleccione el recorrido que desea ver</string>
<string name="current_track">Recorrido actual</string>
<string name="current_segment">Último segmento</string>
@@ -41,21 +41,21 @@ limitations under the License.
<string name="error_generic">A ocurrido un error. Por favor, inténtelo de nuevo.</string>
<string name="error_track_does_not_exist">El recorrido no existe.</string>
<string name="error_out_of_memory">El archivo es demasiado grande (tiene que ser menor a 500 KB). Abortando.</string>
<string name="error_unable_to_insert_marker">No se puede insertar el marcador. La ubicación no esta disponible.</string>
<string name="error_unable_to_insert_marker">No se puede insertar el marcador. La ubicación no está disponible.</string>
<!-- Status messages -->
<string name="wait_for_fix">Esperando una ubicación mas exacta del GPS. Asegúrese que el cielo sea visible.</string>
<string name="status_now_recording">Grabando un nuevo recorrido.</string>
<string name="status_stopped_recording">Grabacíon interrumpida.</string>
<string name="status_new_fusiontable_has_been_created">Un mapa Google Fusion Tables nuevo has sido creado en google.com/fusiontables.</string>
<string name="status_stopped_recording">Grabación interrumpida.</string>
<string name="status_new_fusiontable_has_been_created">Una nueva tabla de Google Fusion ha sido creada en google.com/fusiontables.</string>
<string name="status_tracks_have_been_uploaded">Su recorrido ha sido enviado a maps.google.com.</string>
<string name="status_tracks_have_been_uploaded_to_new_doc">Su recorrido ha sido enviado a una nueva hoja de cálculo en docs.google.com.</string>
<string name="status_tracks_have_been_uploaded_to_new_doc">Su recorrido ha sido enviado a una nueva hoja de cálculo de docs.google.com.</string>
<string name="status_tracks_have_been_uploaded_to_docs">Su recorrido ha sido enviado a docs.google.com.</string>
<string name="status_enable_gps">Por favor presione aquí para ir al menú de Seguridad y Ubicación y asegúrese que el GPS esté habilitado. Presione el botón de regreso para regresar.</string>
<string name="status_approximate_location">Nota: Una ubicación aproximada es mostrada, basada en informacion de torres de telefonía celular y red WIFI.</string>
<string name="status_no_location">La ubicación actual no puede ser determinada. Habilite más fuentes de datos (vea configuraciones de Seguridad y Ubicación) y asegúrese que el cielo sea visible. Inténtelo mas tarde.</string>
<string name="status_waypoint_inserted">Una señal de recorrido fue insertada.</string>
<string name="status_statistics_inserted">Una señal con estadísticas fue insertada.</string>
<string name="status_enable_gps">Por favor, presione aquí para ir al menú de Seguridad y Ubicación, y asegúrese que el GPS esté habilitado. Presione el botón "atrás" para regresar.</string>
<string name="status_approximate_location">Nota: Una ubicación aproximada es determinada a partir de torres de telefonía celular y redes WIFI.</string>
<string name="status_no_location">No puede ser determinada la ubicación actual. Habilite más fuentes de datos (vea las configuraciones de Seguridad y Ubicación) y asegúrese que el cielo sea visible. Inténtelo mas tarde.</string>
<string name="status_waypoint_inserted">Un marcador de recorrido fue insertado.</string>
<string name="status_statistics_inserted">Un marcador de estadísticas fue insertado.</string>
<!-- Progress dialog -->
<string name="progress_title">Por favor espere...</string>
+6 -19
View File
@@ -15,18 +15,6 @@ See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<!-- Task frequency -->
<string-array name="task_frequency_options">
<item>Absent</item>
<item>1 min</item>
<item>2 min</item>
<item>5 min</item>
<item>10 min</item>
<item>15 min</item>
<item>30 min</item>
<item>60 min</item>
</string-array>
<!-- Minimum recording distance -->
<string-array name="min_recording_distance_options">
<item>1 m</item>
@@ -112,10 +100,9 @@ limitations under the License.
<item>3.1 miles (mauvais signal GPS)</item>
</string-array>
<!-- Split frequency -->
<string-array name="split_frequency_options">
<item>Pas de séparation</item>
<!-- Task frequency -->
<string-array name="task_frequency_options">
<item>Absent</item>
<item>100 km</item>
<item>50 km</item>
<item>25 km</item>
@@ -131,8 +118,8 @@ limitations under the License.
<item>1 min</item>
</string-array>
<string-array name="split_frequency_options_ft">
<item>Pas de séparation</item>
<string-array name="task_frequency_options_ft">
<item>Absent</item>
<item>100 mi</item>
<item>50 mi</item>
<item>25 mi</item>
@@ -310,5 +297,5 @@ limitations under the License.
<item>Pont SRM ANT+</item>
<item>Bluetooth Zephyr</item>
</array>
</resources>
+5 -17
View File
@@ -15,18 +15,6 @@ See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<!-- Task frequency -->
<string-array name="task_frequency_options">
<item>Disattivato</item>
<item>1 min</item>
<item>2 min</item>
<item>5 min</item>
<item>10 min</item>
<item>15 min</item>
<item>30 min</item>
<item>60 min</item>
</string-array>
<!-- Minimum recording distance -->
<string-array name="min_recording_distance_options">
<item>1 m</item>
@@ -112,9 +100,9 @@ limitations under the License.
<item>3.1 mi (segnale GPS debole)</item>
</string-array>
<!-- Split frequency -->
<string-array name="split_frequency_options">
<item>Non dividere</item>
<!-- Task frequency -->
<string-array name="task_frequency_options">
<item>Disattivato</item>
<item>100 km</item>
<item>50 km</item>
<item>25 km</item>
@@ -130,8 +118,8 @@ limitations under the License.
<item>1 min</item>
</string-array>
<string-array name="split_frequency_options_ft">
<item>Non dividere</item>
<string-array name="task_frequency_options_ft">
<item>Disattivato</item>
<item>100 mi</item>
<item>50 mi</item>
<item>25 mi</item>
+7 -22
View File
@@ -15,19 +15,7 @@ See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<!-- Task frequency -->
<string-array name="task_frequency_options">
<item>不使用</item>
<item>1 分</item>
<item>2 分</item>
<item>5 分</item>
<item>10 分</item>
<item>15 分</item>
<item>30 分</item>
<item>60 分</item>
</string-array>
<!-- Minimum recording distance -->
<!-- Minimum recording distance -->
<string-array name="min_recording_distance_options">
<item>1 m</item>
<item>2 m</item>
@@ -48,7 +36,6 @@ limitations under the License.
<item>328 ft</item>
</string-array>
<!-- Maximum recording distance -->
<string-array name="max_recording_distance_options">
<item>50 m</item>
@@ -68,7 +55,6 @@ limitations under the License.
<item>3.1 mi</item>
</string-array>
<!-- Minimum recording interval -->
<string-array name="min_recording_interval_options">
<item>電源節約 (動的制御)</item>
@@ -89,7 +75,6 @@ limitations under the License.
<item>30 分</item>
</string-array>
<!-- Minimum required accuracy -->
<string-array name="min_required_accuracy_options">
<item>10 m (GPS信号強度良好)</item>
@@ -115,10 +100,9 @@ limitations under the License.
<item>3.1 mi (GPS信号強度不良)</item>
</string-array>
<!-- Split frequency -->
<string-array name="split_frequency_options">
<item>分割なし</item>
<!-- Task frequency -->
<string-array name="task_frequency_options">
<item>不使用</item>
<item>100 km</item>
<item>50 km</item>
<item>25 km</item>
@@ -134,8 +118,8 @@ limitations under the License.
<item>1 分</item>
</string-array>
<string-array name="split_frequency_options_ft">
<item>分割なし</item>
<string-array name="task_frequency_options_ft">
<item>不使用</item>
<item>100 mi</item>
<item>50 mi</item>
<item>25 mi</item>
@@ -294,4 +278,5 @@ limitations under the License.
<item>SRM ANT+ ブリッジ</item>
<item>Zephyr Bluetooth</item>
</array>
</resources>
+6 -18
View File
@@ -15,18 +15,6 @@ See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<!-- Task frequency -->
<string-array name="task_frequency_options">
<item>Brak</item>
<item>1 min</item>
<item>2 min</item>
<item>5 min</item>
<item>10 min</item>
<item>15 min</item>
<item>30 min</item>
<item>60 min</item>
</string-array>
<!-- Minimum recording distance -->
<string-array name="min_recording_distance_options">
<item>1 m</item>
@@ -112,9 +100,9 @@ limitations under the License.
<item>3.1 mili (słaby sygnał GPS)</item>
</string-array>
<!-- Split frequency -->
<string-array name="split_frequency_options">
<item>Brak dzielenia</item>
<!-- Task frequency -->
<string-array name="task_frequency_options">
<item>Brak</item>
<item>100 km</item>
<item>50 km</item>
<item>25 km</item>
@@ -130,8 +118,8 @@ limitations under the License.
<item>1 min</item>
</string-array>
<string-array name="split_frequency_options_ft">
<item>Brak dzielenia</item>
<string-array name="task_frequency_options_ft">
<item>Brak</item>
<item>100 mi</item>
<item>50 mi</item>
<item>25 mi</item>
@@ -146,7 +134,7 @@ limitations under the License.
<item>2 min</item>
<item>1 min</item>
</string-array>
<!-- Auto-resume track timeout -->
<string-array name="auto_resume_track_timeout_options">
<item>Nigdy</item>
+19 -36
View File
@@ -15,21 +15,8 @@ See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<!-- Task frequency -->
<array name="task_frequency_options">
<item>Desligado</item>
<item>1 min</item>
<item>2 min</item>
<item>5 min</item>
<item>10 min</item>
<item>15 min</item>
<item>30 min</item>
<item>60 min</item>
</array>
<!-- Minimum recording distance -->
<array name="min_recording_distance_options">
<string-array name="min_recording_distance_options">
<item>1 m</item>
<item>2 m</item>
<item>3 m</item>
@@ -37,9 +24,9 @@ limitations under the License.
<item>5 m (recomendada)</item>
<item>10 m</item>
<item>100 m</item>
</array>
</string-array>
<array name="min_recording_distance_options_ft">
<string-array name="min_recording_distance_options_ft">
<item>3 pés</item>
<item>6 pés</item>
<item>10 pés</item>
@@ -47,31 +34,29 @@ limitations under the License.
<item>16 pés (recomendado)</item>
<item>33 pés</item>
<item>328 pés</item>
</array>
</string-array>
<!-- Maximum recording distance -->
<array name="max_recording_distance_options">
<string-array name="max_recording_distance_options">
<item>50 m</item>
<item>100 m</item>
<item>200 m (recomendado)</item>
<item>500 m</item>
<item>1000 m</item>
<item>5000 m</item>
</array>
</string-array>
<array name="max_recording_distance_options_ft">
<string-array name="max_recording_distance_options_ft">
<item>164 pés</item>
<item>328 pés</item>
<item>656 pés (recomendado)</item>
<item>1640 pés</item>
<item>0.6 milhas</item>
<item>3.1 milhas</item>
</array>
</string-array>
<!-- Minimum recording interval -->
<array name="min_recording_interval_options">
<string-array name="min_recording_interval_options">
<item>economia de bateria (adaptativo)</item>
<item>alta precisão (adaptativo)</item>
<item>máxima (recomendada)</item>
@@ -88,11 +73,10 @@ limitations under the License.
<item>10 min</item>
<item>15 min</item>
<item>30 min</item>
</array>
</string-array>
<!-- Minimum required accuracy -->
<array name="min_required_accuracy_options">
<string-array name="min_required_accuracy_options">
<item>10 m (sinal de GPS excelente)</item>
<item>20 m</item>
<item>50 m</item>
@@ -102,9 +86,9 @@ limitations under the License.
<item>1000 m</item>
<item>2000 m</item>
<item>5000 m (sinal de GPS ruim)</item>
</array>
</string-array>
<array name="min_required_accuracy_options_ft">
<string-array name="min_required_accuracy_options_ft">
<item>33 pés (sinal de GPS excelente)</item>
<item>66 pés</item>
<item>165 pés</item>
@@ -114,12 +98,11 @@ limitations under the License.
<item>0.6 milhas</item>
<item>1.2 milhas</item>
<item>3.1 milhas (sinal de GPS ruim)</item>
</array>
</string-array>
<!-- Split frequency -->
<string-array name="split_frequency_options">
<item>Sem divisões</item>
<!-- Task frequency -->
<string-array name="task_frequency_options">
<item>Desligado</item>
<item>100 km</item>
<item>50 km</item>
<item>25 km</item>
@@ -135,8 +118,8 @@ limitations under the License.
<item>1 min</item>
</string-array>
<string-array name="split_frequency_options_ft">
<item>Sem divisões</item>
<string-array name="task_frequency_options_ft">
<item>Desligado</item>
<item>100 mi</item>
<item>50 mi</item>
<item>25 mi</item>
+282
View File
@@ -0,0 +1,282 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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.
-->
<resources>
<!-- Minimum recording distance -->
<string-array name="min_recording_distance_options">
<item>1 м</item>
<item>2 м</item>
<item>3 м</item>
<item>4 м</item>
<item>5 м (рекомендуется)</item>
<item>10 м</item>
<item>100 м</item>
</string-array>
<string-array name="min_recording_distance_options_ft">
<item>3 фута</item>
<item>6 футов</item>
<item>10 футов</item>
<item>13 футов</item>
<item>16 футов (рекомендуется)</item>
<item>33 фута</item>
<item>328 футов</item>
</string-array>
<!-- Maximum recording distance -->
<string-array name="max_recording_distance_options">
<item>50 м</item>
<item>100 м</item>
<item>200 м (рекомендуется)</item>
<item>500 м</item>
<item>1000 м</item>
<item>5000 м</item>
</string-array>
<string-array name="max_recording_distance_options_ft">
<item>164 фута</item>
<item>328 футов</item>
<item>656 фута (рекомендуется)</item>
<item>1640 футов</item>
<item>0,6 мили</item>
<item>3,1 мили</item>
</string-array>
<!-- Minimum recording interval -->
<string-array name="min_recording_interval_options">
<item>экономия батареи (адаптивная)</item>
<item>высокая точность (адаптивная)</item>
<item>высочайшая точность (рекомендуется)</item>
<item>2 с</item>
<item>3 с</item>
<item>4 с</item>
<item>5 с</item>
<item>10 с</item>
<item>20 с</item>
<item>30 с</item>
<item>1 мин</item>
<item>2 мин</item>
<item>5 мин</item>
<item>10 мин</item>
<item>15 мин</item>
<item>30 мин</item>
</string-array>
<!-- Minimum required accuracy -->
<string-array name="min_required_accuracy_options">
<item>10 м (отличный сигнал GPS)</item>
<item>20 м</item>
<item>50 м</item>
<item>100 м</item>
<item>200 м (рекомендуется)</item>
<item>500 м</item>
<item>1000 м</item>
<item>2000 м</item>
<item>5000 м (плохой сигнал GPS)</item>
</string-array>
<string-array name="min_required_accuracy_options_ft">
<item>33 фута (отличный сигнал GPS)</item>
<item>66 футов</item>
<item>165 футов</item>
<item>328 футов</item>
<item>656 футов (рекомендуется)</item>
<item>1640 футов</item>
<item>0,6 мили</item>
<item>1,2 мили</item>
<item>3,1 мили (плохой сигнал GPS)</item>
</string-array>
<!-- Task frequency -->
<string-array name="task_frequency_options">
<item>Выкл.</item>
<item>100 км</item>
<item>50 км</item>
<item>25 км</item>
<item>10 км</item>
<item>5 км</item>
<item>1 км</item>
<item>60 мин</item>
<item>30 мин</item>
<item>15 мин</item>
<item>10 мин</item>
<item>5 мин</item>
<item>2 мин</item>
<item>1 мин</item>
</string-array>
<string-array name="task_frequency_options_ft">
<item>Выкл.</item>
<item>100 миль</item>
<item>50 миль</item>
<item>25 миль</item>
<item>10 миль</item>
<item>5 миль</item>
<item>1 миля</item>
<item>60 мин</item>
<item>30 мин</item>
<item>15 мин</item>
<item>10 мин</item>
<item>5 мин</item>
<item>2 мин</item>
<item>1 мин</item>
</string-array>
<!-- Auto-resume track timeout -->
<string-array name="auto_resume_track_timeout_options">
<item>Никогда</item>
<item>5 мин</item>
<item>10 мин</item>
<item>15 мин</item>
<item>Всегда</item>
</string-array>
<!-- Other non-preference arrays -->
<array name="activity_types">
<item>не определен</item>
<item>смешанного типа</item>
<item>другое</item>
<item>бег</item>
<item>бег по улице</item>
<item>бег по треку</item>
<item>бег по тропе</item>
<item>ходьба</item>
<item>быстрая ходьба</item>
<item>пешая прогулка</item>
<item>прогулка по туристической тропе</item>
<item>прогулка по бездорожью</item>
<item>восхождение</item>
<item>велосипедная прогулка</item>
<item>шоссейный велосипед</item>
<item>горный велосипед</item>
<item>велотрек</item>
<item>катание на коньках</item>
<item>катания на роликовых коньках</item>
<item>катания на роликовых коньках</item>
<item>прогулка на снегоступах</item>
<item>лыжи</item>
<item>сноубординг</item>
<item>сани</item>
<item>ледяной парусный спорт</item>
<item>парусный спорт</item>
<item>гребля</item>
<item>каякинг</item>
<item>академическая гребля</item>
<item>моторная лодка</item>
<item>паром</item>
<item>RC лодка</item>
<item>серфинг</item>
<item>виндсерфинг</item>
<item>кайтсерфинг</item>
<item>водные лыжи</item>
<item>вейкбординг</item>
<item>самолет</item>
<item>гидроплан</item>
<item>коммерческий самолет</item>
<item>вертолет</item>
<item>воздушный шар</item>
<item>дирижабль</item>
<item>RC самолет</item>
<item>RC вертолет</item>
<item>прыжки</item>
<item>планеризм</item>
<item>дельтаплан</item>
<item>парный планеризм</item>
<item>верховая езда</item>
<item>катание на лошадях</item>
<item>прогулка на осле</item>
<item>вождение автомобиля</item>
<item>вождение автобуса</item>
<item>поезд</item>
<item>мотоцикл</item>
<item>Байк</item>
<item>ATV</item>
<item>парусный спорт на земле</item>
<item>фрисби</item>
<item>алтимат фризби</item>
</array>
<array name="waypoint_types">
<item>банкомат</item>
<item>банк</item>
<item>бар</item>
<item>барбекю</item>
<item>здание</item>
<item>автобусная остановка</item>
<item>кафе</item>
<item>костер</item>
<item>лагерь</item>
<item>церковь</item>
<item>кофейня</item>
<item>удобный магазин</item>
<item>питьевая вода</item>
<item>оползень</item>
<item>паром</item>
<item>камин</item>
<item>пожарная станция</item>
<item>рыболовство</item>
<item>автозаправочная станция</item>
<item>поле для гольфа</item>
<item>продуктовый магазин</item>
<item>парикмахерская</item>
<item>гавань</item>
<item>тропа</item>
<item>отель</item>
<item>дом</item>
<item>информация</item>
<item>пересечение</item>
<item>почтовый ящик</item>
<item>рынок</item>
<item>место встречи</item>
<item>опера</item>
<item>парковка</item>
<item>почтовое отделение</item>
<item>выбоина</item>
<item>полицейский участок</item>
<item>железнодорожный переезд</item>
<item>ресторан</item>
<item>покупки</item>
<item>вид</item>
<item>магазин</item>
<item>бассейн</item>
<item>телефон</item>
<item>театр</item>
<item>туалет</item>
<item>туристическая информация</item>
<item>туннель</item>
<item>дерево</item>
<item>водопад</item>
<item>фонтан</item>
<item>путевая точка</item>
</array>
<array name="sensor_type_options">
<item>Нет</item>
<item>ANT+ Sensors</item>
<item>SRM ANT+ Bridge</item>
<item>Zephyr Bluetooth</item>
</array>
</resources>
+501
View File
@@ -0,0 +1,501 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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.
-->
<resources>
<!-- Used by the Menu -->
<string name="start_recording">Запись трека</string>
<string name="stop_recording">Остановить запись</string>
<string name="switch_to_sat">Режим спутника</string>
<string name="switch_to_map">Режим карты</string>
<string name="mylocation">Мое местоположение</string>
<string name="list_tracks">Треки</string>
<string name="list_markers">Маркеры</string>
<string name="delete_all_tracks">Удалить все треки</string>
<string name="settings">Настройки</string>
<string name="elevation">Высота</string>
<string name="choose_track_message">Пожалуйста, выберите трек для просмотра</string>
<string name="current_track">Текущий трек</string>
<string name="current_segment">Последний сегмент</string>
<string name="sensor_state">Состояние датчика</string>
<string name="aggregated_stats">Совокупная статистика</string>
<!-- Error messages -->
<string name="error_no_location_manager">На этом устройстве не был обнаружен диспетчер местоположения!</string>
<string name="error_no_gps_location_provider">На этом устройстве не был обнаружен поставщик GPS местоположения.</string>
<string name="error_sending_to_mymap">Ошибка при отправке вашего трека в Google \"Мои карты\".</string>
<string name="error_sending_to_fusiontables">Ошибка при отправке вашего трека в Google Fusion Tables.</string>
<string name="error_sending_to_docs">Ошибка при отправке вашего трека в Google Документы.</string>
<string name="error_please_try_again_later">Пожалуйста, повторите попытку позже.</string>
<string name="error_unable_to_start_recording">Не удалось начать запись. Попробуйте еще раз.</string>
<string name="error_unable_to_stop_recording">Не удалось остановить запись. Попробуйте еще раз.</string>
<string name="error_unable_to_read_file">Не удалось прочитать из файла.</string>
<string name="error_invalid_gpx_format">Неверный формат GPX файла.</string>
<string name="error_generic">Произошла ошибка. Пожалуйста, попробуйте еще раз.</string>
<string name="error_track_does_not_exist">Трек не существует.</string>
<string name="error_out_of_memory">Этот файл слишком большой (должен быть меньше, чем 500 КБ). Прервано.</string>
<string name="error_unable_to_insert_marker">Невозможно вставить маркер. Местоположение неизвестно.</string>
<!-- Status messages -->
<string name="wait_for_fix">Ожидание сигнала GPS. Убедитесь в том, что вы находитесь под открытым небом.</string>
<string name="status_now_recording">Записывается новый трек.</string>
<string name="status_stopped_recording">Запись вашего трека остановлена.</string>
<string name="status_new_mymap_has_been_created">Новая Google \"Мои карты\" была создана на maps.google.com.</string>
<string name="status_new_fusiontable_has_been_created">Новая таблица Google Fusion была создана на google.com/fusiontables.</string>
<string name="status_tracks_have_been_uploaded">Твой трек был отправлен на maps.google.com.</string>
<string name="status_tracks_have_been_uploaded_to_new_doc">Ваш трек был отправлен в новую электронную таблицу на docs.google.com.</string>
<string name="status_tracks_have_been_uploaded_to_docs">Ваш трек был отправлен в docs.google.com.</string>
<string name="status_mymap_info">Это может занять несколько минут, прежде чем появятся новые треки.</string>
<string name="status_enable_gps">Пожалуйста, нажмите здесь для перехода к разделу настроек Координаты и отметьте пункт \"Спутники GPS\". Для возвращения нажмите кнопку Назад.</string>
<string name="status_approximate_location">Примечание: приблизительное местоположение определено относительно вышек сотовой связи и беспроводных сетей.</string>
<string name="status_no_location">В настоящее время местоположение не может быть определено. Включите больше источников местоположение (см. раздел настроек Координаты) и убедитесь в том, что находитесь под открытым небом. Повторите попытку позднее.</string>
<string name="status_waypoint_inserted">Маркер путевой точки был вставлен.</string>
<string name="status_statistics_inserted">Маркер статистики был вставлен.</string>
<string name="status_track_upload_status">Статус загрузки:</string>
<!-- Progress dialog -->
<string name="progress_title">Пожалуйста, подождите...</string>
<string name="progress_message">Отправка вашего трека в Google.</string>
<string name="progress_message_reading_track">Чтение трека...</string>
<string name="progress_message_preparing_track">Подготовка трека...</string>
<string name="progress_message_authenticating_fusiontables">Аутентификация на Google Fusion Tables...</string>
<string name="progress_message_authenticating_mymaps">Аутентификация на Google Карты...</string>
<string name="progress_message_authenticating_docs">Аутентификация в Google Документы...</string>
<string name="progress_message_sending_docs">Отправка трека в Google Документы...</string>
<string name="progress_message_sending_mymaps">Отправка трека в Google Карты...</string>
<string name="progress_message_creating_map">Создание новой \"Моей карты\" ...</string>
<string name="progress_message_sending_fusiontables">Отправка трека в Fusion Tables...</string>
<string name="progress_message_creating_fusiontable">Создание новой Fusion table...</string>
<string name="import_progress_message">Импорт GPS трека. Это может занять некоторое время.</string>
<string name="write_progress_message">Запись файла на SD карту. Это может занять некоторое время.</string>
<string name="progress_message_updating_track">Обновление статистики трека...</string>
<!-- Used by DeleteAllDataHandler -->
<string name="are_you_sure_question">Вы уверены?</string>
<string name="all_data_will_be_permanently_deleted">Все треки и маркеры будут удалены с этого телефона.</string>
<string name="track_will_be_permanently_deleted">Трек и его маркеры будут удалены из этого телефона.</string>
<string name="marker_will_be_permanently_deleted">Маркер будет удален с этого телефона.</string>
<!-- Text and links when uploading to Google Fusion Tables -->
<string name="new_map_description">Создано My Tracks на Android.</string>
<string name="fusiontable_link">Создано &lt;a href=\'http://mytracks.appspot.com\'&gt;My Tracks&lt;/a&gt; на Android.</string>
<!-- Text and links when uploading to Google My Maps -->
<string name="my_map_link">Создано &lt;a href=\'http://mytracks.appspot.com\'&gt;My Tracks&lt;/a&gt; на Android.</string>
<string name="new_map_title">Новая карта</string>
<!-- Formatting of track and marker descriptions -->
<string name="points">Точки</string>
<string name="recorded_date">Записан</string>
<string name="category">Тип деятельности</string>
<string name="waypoint_category">Тип маркера</string>
<string name="part">(Часть %d)</string>
<!-- Used by the track recording service -->
<string name="recording_your_track">Запись трека...</string>
<string name="new_track">Трек %d</string>
<!-- Common -->
<string name="no">Нет</string>
<string name="yes">Да</string>
<string name="ok">ОК</string>
<string name="error">Ошибка</string>
<string name="success">Готово</string>
<string name="waypoint">Путевая точка</string>
<string name="license">Лицензия</string>
<string name="cancel">Отмена</string>
<string name="close">Закрыть</string>
<string name="edit">Правка</string>
<string name="save">Сохранить</string>
<!-- Placemark labels for start and end of track -->
<string name="start">(Старт)</string>
<string name="end">(Конец)</string>
<!-- TrackList -->
<string name="tracklist_show_track">Показать</string>
<string name="tracklist_send_to_mymaps">Отправить в Google \"Мои карты\"</string>
<string name="tracklist_send_to_new_mymap">Отправить в новый Google \"Мои карты\"</string>
<string name="tracklist_send_to_fusiontables">Отправить в Google Fusion Tables</string>
<string name="tracklist_send_to_new_fusiontable">Отправить в новую Google Fusion Table</string>
<string name="tracklist_send_to_docs">Отправить в Google Документы</string>
<string name="tracklist_send_to_google">Отправить в Google ...</string>
<string name="tracklist_delete_track">Удалить из телефона...</string>
<string name="tracklist_edit_track">Править детали</string>
<string name="tracklist_write_to_sd">Записать на SD карту...</string>
<string name="tracklist_save_as_gpx">Сохранить файл GPX</string>
<string name="tracklist_save_as_kml">Сохранить файл KML</string>
<string name="tracklist_save_as_csv">Сохранить файл CSV</string>
<string name="tracklist_save_as_tcx">Сохранить файл TCX</string>
<string name="tracklist_btn_send_all_to_fusiontables">Отправить в Google Fusion Tables</string>
<string name="tracklist_btn_send_all_to_mymaps">Отправить в Google \"Мои карты\"</string>
<string name="tracklist_btn_delete_all">Удалить все</string>
<!-- Export All -->
<string name="tracklist_btn_export_all">Экспорт всех</string>
<string name="export_done">Экспорт закончен</string>
<string name="tracklist_pick_one">Выберите трек. Нажмите и удерживайте для получения дополнительных возможностей.</string>
<string name="tracklist_all_tracks">Все треки:</string>
<string name="tracklist_this_track">Этот трек</string>
<string name="tracklist_share_track">Поделиться с друзьями...</string>
<string name="tracklist_share_link">Ссылка на карту</string>
<string name="tracklist_share_gpx_file">Файл GPX</string>
<string name="tracklist_share_kml_file">Файл KML</string>
<string name="tracklist_share_csv_file">Файла CSV</string>
<string name="tracklist_share_tcx_file">Файл TCX</string>
<string name="tracklist_clear_map">Очистить карту</string>
<!-- Import All -->
<string name="tracklist_btn_import_all">Импорт всех</string>
<string name="import_done">Импорт закончен</string>
<!-- Format:
$1 : Successful imports
$2 : Attempted imports
$3 : MyTracks gpx path
-->
<string name="import_done">Импортировано %1$d из %2$d GPX файлов с %3$s</string>
<string name="import_empty">GPX файлы не найденны в %s. Возможно не читается SD-карта или каталог не содержит GPX файлы.</string>
<string name="import_error">Ошибка импорта файла %s</string>
<!-- Waypoints list -->
<string name="waypointslist_btn_delete_all">Удалить все маркеры</string>
<string name="waypointslist_this_waypoint">Этот маркер</string>
<string name="waypointslist_delete_waypoint">Удалить</string>
<string name="waypointslist_edit_waypoint">Править детали</string>
<string name="waypointslist_show_waypoint">Показать на карте</string>
<string name="waypointslist_btn_insert_waypoint">Вставить путевую точку</string>
<string name="waypointslist_btn_insert_statistics">Вставить статистику</string>
<string name="waypointslist_pick_one">Выберите маркер. Нажмите и удерживайте для получения дополнительных возможностей.</string>
<!-- MyTracks Details -->
<string name="trackdetails_title">Трек детали</string>
<string name="trackdetails_name">Название трека</string>
<string name="trackdetails_description">Описание трека</string>
<string name="trackdetails_category">Тип деятельности (например: пешая прогулка, велосипедная прогулка, бег, восхождение...)</string>
<!-- MyTracks Waypoint Details -->
<string name="waypointdetails_title">Маркер детали</string>
<string name="waypointdetails_name">Имя маркера</string>
<string name="waypointdetails_description">Описание маркера</string>
<string name="waypointdetails_category">Тип маркера (например: здание, выбоина, достопримечательность...)</string>
<!-- MyTracks Settings -->
<string name="mytracks_settings">Настройки My Tracks</string>
<string name="settings_display">Отображение</string>
<string name="settings_recording">Запись</string>
<string name="settings_sharing">Обмен</string>
<string name="settings_not_available_summary">Не доступен в вашем версии Android</string>
<string name="settings_not_while_recording">Не доступно во время записи трека</string>
<string name="settings_announcement_frequency">Частота объявлений</string>
<string name="settings_announcement_frequency_summary">Минимальное время между двумя голосовыми объявлениями</string>
<string name="settings_min_recording_distance">Минимальное расстояние между точками</string>
<string name="settings_min_recording_distance_summary">Наименьшее расстояние между двумя записями вашей позиции</string>
<string name="settings_max_recording_distance">Максимальное расстояние между точками</string>
<string name="settings_max_recording_distance_summary">Если два пункта находятся дальше, чем указано, то трек будет разделен</string>
<string name="settings_min_recording_interval">Минимальное время между точками</string>
<string name="settings_min_recording_interval_summary">Наименьший интервал времени между двумя записями вашей позиции</string>
<string name="settings_min_required_accuracy">Минимальная точность</string>
<string name="settings_min_required_accuracy_summary">Запись будет приостановлена, если ваша позиция не является достаточно точной</string>
<string name="settings_metric_units">Использовать метрические единицы</string>
<string name="settings_metric_units_summary_on">Все расстояния будут отображаться в метрических единицах</string>
<string name="settings_metric_units_summary_off">Все расстояния будут отображаться в имперских единицах</string>
<string name="settings_map_public">Обнародовать карты</string>
<string name="settings_map_public_summary_on">Загруженные карты будут общедоступны на maps.google.com</string>
<string name="settings_map_public_summary_off">Загруженные карты не будут перечислены публично на maps.google.com</string>
<string name="settings_report_speed_or_pace">Отображать скорость</string>
<string name="settings_report_speed_or_pace_summary_on">Скорость будет отображаться</string>
<string name="settings_report_speed_or_pace_summary_off">Темп будет отображаться</string>
<string name="settings_share_url_only">Поделиться только URL</string>
<string name="settings_share_url_only_summary_on">При обмене будет отправлен только URL-адрес</string>
<string name="settings_share_url_only_summary_off">Содержимое трека будет также включено при обмене</string>
<string name="settings_split_frequency">Частота деления</string>
<string name="settings_split_frequency_summary">Максимальное время или расстояние, после которого будет вставлен новый маркер деления</string>
<string name="settings_auto_resume_track_timeout">Автоматическое возобновление трек тайм-аут</string>
<string name="settings_auto_resume_track_timeout_summary">Максимальное время в минутах, после которого предыдущая запись трека не будет возобновлена на перезагруженном телефоне</string>
<string name="settings_timestamp_track_name">Штамп времени как название дорожки</string>
<string name="settings_timestamp_track_name_summary_on">По умолчанию имя трека будет складываться из даты и времени старта трека</string>
<string name="settings_timestamp_track_name_summary_off">Названия треков будут иметь прирост чисел для каждого нового трека.</string>
<string name="settings_reset">Восстановить значения по умолчанию</string>
<string name="settings_reset_summary">Восстановить значения по умолчанию во всех настройках</string>
<string name="settings_reset_dialog_message">Все ваши настройки будут стерты и восстановлены значения по умолчанию. Записанные треки будут сохранены. Вы уверены?</string>
<string name="settings_reset_done">Все настройки были возвращены к значениям по умолчанию.</string>
<string name="pace_label">Темп</string>
<string name="eclair_required">Поддерживается только в Android 2.0 или выше</string>
<string name="settings_sensor_type">Тип датчика</string>
<string name="settings_sensor_type_summary">Тип подключенного датчика</string>
<string name="settings_heart_rate_ant_sensor_id">Очистить ANT подсоединенного датчика пульса</string>
<string name="settings_power_ant_sensor_id">Очистить ANT подсоединенного датчика мощности</string>
<string name="settings_srm_bridge_ant_sensor_id">Очистить ANT подсоединенного датчика SRM</string>
<string name="settings_ant_not_paired">ANT датчик не подсоединен</string>
<string name="settings_ant_paired">ANT датчик подсоединен с: %d</string>
<string name="bluetooth_sensor_title">Bluetooth датчик</string>
<string name="bluetooth_sensor_summary">Подключенный bluetooth датчик</string>
<string name="settings_modular_stats_display_title">Отображение модульной статистики</string>
<!-- Backups -->
<string name="settings_backup">Резервное копирование (BETA)</string>
<string name="settings_sd_backup">Резервное копирование SD карты</string>
<string name="settings_backup_to_sd">Резервировать</string>
<string name="settings_backup_to_sd_summary">Создать полную копию всех ваших треков и настроек на SD карту</string>
<string name="settings_restore_from_sd">Восстановить</string>
<string name="settings_restore_from_sd_summary">Восстановить все треки и параметры с SD карты</string>
<string name="restore_overwrites_warning">Восстановление резервной копии с SD карты ПЕРЕЗАПИШЕТ все текущие треки и настройки. Вы уверены?</string>
<string name="select_backup_to_restore">Выберите резервную копию для восстановления</string>
<string name="no_backups">Резервные копии не найдены.</string>
<string name="backup_write_progress_message">Запись на SD-карту всех треков и настроек. Это может занять некоторое время...</string>
<string name="backup_import_progress_message">Чтение всех треков и настроек с SD-карты. Это может занять некоторое время...</string>
<!-- MyTracksSky -->
<string name="mytracks_sky">Спутники GPS</string>
<!-- My Maps -->
<string name="select_map_message">Выберите карту из вашей учетной записи:</string>
<string name="create_new_map">Создать новую карту...</string>
<string name="map_list_title">Отправить в Google \"Мои карты\"</string>
<string name="maps_list_loading">Загрузка карты ...</string>
<string name="maps_list_failed">Ваши карты не могут быть загружены в данный момент!</string>
<string name="open_map">Выберите эту карту</string>
<string name="edit_map_details">Править детали карты</string>
<string name="share_track">Поделиться треком</string>
<string name="delete_map">Удалить Карту из вашей учетной записи</string>
<string name="map_title">Название карты:</string>
<string name="map_description">Описание карты:</string>
<string name="map_searchable_edit">Сделать чтобы карта и ее содержимое отображались в результатах поиска</string>
<string name="map_not_searchable_edit">Не позволить этой карте или ее содержимому отображаться в результатах поиска, хотя они все еще могут просматриваться другими через прямой URL-адрес</string>
<string name="map_searchable">Эта карта и ее содержимое будут отображаться в результатах поиска</string>
<string name="map_not_searchable">Ни эта карта, ни ее содержимое не будут отображаться в результатах поиска, но их могут по-прежнему просматривать другие через прямую ссылку</string>
<!-- Sharing -->
<string name="share_map">Поделиться картой с друзьями</string>
<string name="share_map_subject">Я хотел бы поделиться с вами треком</string>
<string name="share_map_body_format">Я думаю, вы можете быть заинтересованы в этом треке:
%s</string>
<string name="send_track_subject">Я хотел бы поделиться с вами треком</string>
<string name="send_track_body_format">Я думаю, вы можете быть заинтересованы в этом треке.
Просмотреть трек можно с помощью Google Планета Земля или другого программного обоспечения для карт.</string>
<!-- Visibility -->
<string name="public_map">Общественные</string>
<string name="unlisted_map">Частные</string>
<string name="mapslist_no_maps_available">У вас пока еще нет карт.</string>
<!-- Statistics View -->
<!-- Average Moving -->
<string name="average_moving_speed_label">Средняя скорость движения</string>
<string name="average_moving_pace_label">Средний темп движения</string>
<!-- Average -->
<string name="average_speed_label">Средняя скорость</string>
<string name="average_pace_label">Средний темп</string>
<string name="elevation_chart_name">Диаграмма высоты</string>
<string name="elevation_gain_label">Набор высоты</string>
<string name="elevation_label">Высота</string>
<string name="latitude_label">Широта</string>
<string name="longitude_label">Долгота</string>
<!-- Min -->
<string name="min_elevation_label">Минимальная высота</string>
<string name="min_grade_label">Минимальный уклон</string>
<string name="min_pace_label">Минимальный темп</string>
<!-- Max -->
<string name="max_elevation_label">Максимальная высота</string>
<string name="max_grade_label">Максимальный уклон</string>
<string name="max_speed_label">Максимальная скорость</string>
<string name="loading_track">Загрузка трека...</string>
<!-- Chart Settings -->
<string name="chart_settings">Настройки диаграммы</string>
<!-- X Axis -->
<string name="x_axis">Ось X</string>
<string name="by_distance">По расстоянию</string>
<string name="by_time">По времени</string>
<!-- Y Axis -->
<string name="y_axis">Ось Y</string>
<!-- Units -->
<!-- Time -->
<string name="hour">час</string>
<string name="hours">часов</string>
<string name="hr">ч</string>
<string name="min">мин</string>
<string name="minute">минута</string>
<string name="minutes">минут</string>
<string name="second">секунда</string>
<string name="seconds">секунд</string>
<string name="milliseconds">мс</string>
<!-- Distance -->
<string name="meter">м</string>
<string name="kilometer">км</string>
<string name="kilometers_long">километров</string>
<string name="feet">футов</string>
<string name="mile">миль</string>
<string name="miles_long">мили</string>
<!-- Speed and Pace -->
<string name="kilometer_per_hour">км/ч</string>
<string name="kilometer_per_hour_long">километров в час</string>
<string name="min_per_kilometer">мин/км</string>
<string name="per_kilometer">за километр</string>
<string name="mile_per_hour">миль/ч</string>
<string name="mile_per_hour_long">миль в час</string>
<string name="min_per_mile">мин/миля</string>
<string name="per_mile">за милю</string>
<!-- Sensors -->
<string name="watts">Вт</string>
<string name="revolutions_per_minute">об/мин</string>
<string name="bpm">bpm</string>
<!-- Stats Labels -->
<string name="moving_time_label">Время движения</string>
<string name="total_time_label">Общее время</string>
<string name="time_label">Время</string>
<string name="sd_unavail">SD карта недоступна</string>
<string name="speed">Скорость</string>
<string name="start_trip">Вы должны начать путешествие.</string>
<string name="statistics">Статистика</string>
<string name="total_distance_label">Общее расстояние</string>
<string name="distance_label">Расстояние</string>
<string name="power">Мощность</string>
<string name="cadence">Каденс</string>
<string name="heart_rate">Пульс</string>
<string name="max_heart_rate">Максимальный пульс</string>
<string name="unknown">-</string>
<string name="waiting">Ожидание...</string>
<!-- End User License Agreement -->
<string name="eula_title">Лицензионное соглашение</string>
<string name="accept">Принять</string>
<string name="decline">Отклонить</string>
<!-- About -->
<string name="about">О программе</string>
<string name="help">Справка</string>
<string name="about_team">Команда:</string>
<string name="about_version">Версия:</string>
<string name="about_support">Поддержка:</string>
<string name="about_privacy">Приватность:</string>
<!-- Send to Google -->
<string name="sendtogoogle_title">Отправить...</string>
<string name="sendtogoogle_google_fusiontables">Google Fusion Tables</string>
<string name="sendtogoogle_google_mymaps">Google \"Мои карты\"</string>
<string name="sendtogoogle_google_docs">Google Документы</string>
<string name="sendtogoogle_send_now">Отправить</string>
<string name="sendtogoogle_create_new_map">Создать новую карту</string>
<string name="sendtogoogle_pick_existing_map">Выбрать существующую карту</string>
<string name="sendtogoogle_send_stats">Отправить статистику трека</string>
<string name="sendtogoogle_send_stats_and_points">Отправить статистику и точки</string>
<!-- Getting the account to upload to. -->
<string name="no_account_found_title">Учетная запись не найдена</string>
<string name="no_account_found">Не найдена учетная запись для загрузки треков.</string>
<string name="choose_account_title">Выбор учетной записи</string>
<!-- SD card -->
<string name="io_no_external_storage_found">Не обнаружено внешнее устройство хранения данных. Убедитесь, что SD карта вставлена, и что ваш телефон не подключен к компьютеру.</string>
<string name="io_write_failed">Невозможно записать файл.</string>
<string name="io_read_failed">Невозможно прочитать из файла.</string>
<string name="io_create_dir_failed">Невозможно создать папку на SD карте.</string>
<string name="io_write_finished">Запись на SD карту закончена.</string>
<string name="io_read_finished">Чтение с SD карты закончено.</string>
<!-- VersionChecker -->
<string name="version_check_title">Проверить обновления</string>
<string name="version_check_upgrade_button">Обновить сейчас</string>
<string name="version_check_continue_button">Продолжить без обновления</string>
<string name="upgrade_required">Ваша версия %1$S больше не может работать должным образом, и больше не поддерживается. Обновите %1$s для продолжения использования.</string>
<string name="upgrade_recommended">Ваша версия %1$S больше не может работать должным образом. Вы можете обновить ее сейчас, либо продолжать использовать ее на свой страх и риск. Некоторые функции, такие как синхронизация с сервером может не функционировать до обновления.</string>
<string name="upgrade_available">Доступна новая версия %1$s. Вы можете продолжать использовать текущую версию без проблем, но вы не получите новейшие функции, до тех пор, пока не обновитесь.</string>
<!-- Welcome -->
<string name="welcome">Добро пожаловать</string>
<string name="welcome_read_later">Ок</string>
<string name="welcome_about">О My Tracks</string>
<!-- Announcement -->
<string name="announce_no_distance">My Tracks нет расстояния</string>
<!-- Format:
$1 : Distance label
$2 : Distance value (5)
$3 : Distance units (mi, km)
$4 : Time description (10 minutes 5 seconds)
$5 : Speed value (5.6) : Pace value (5 minutes 6 seconds)
$6 : Speed units (mph) : Pace units (per mile)
-->
<string name="announce_template">Мои треки %1$s %2$.2f %3$s в %4$s на %5$s %6$s</string>
<!-- Check Units -->
<string name="check_units_title">Единицы измерения обратите внимание</string>
<string name="check_units_message">По умолчанию используются метрические единицы. Вы хотели бы изменить этот параметр?</string>
<!-- Fake preference keys - never saved, but show options in the preferences screen -->
<string name="method_bluetooth">Bluetooth</string>
<string name="bluetooth_options">Параметры Bluetooth</string>
<string name="bluetooth_pairing">Подключение устройства</string>
<string name="bluetooth_pairing_summary">Открыть настройки Android по bluetooth для подключения устройства</string>
<string name="sensor_bluetooth_options_key">bluetoothSensorsEnabled</string>
<string name="ant_options">Параметры ANT</string>
<string name="sensor_options">Параметры датчика</string>
<!-- Bluetooth Sensor -->
<string name="bluetooth_connected">Подключен к %s</string>
<string name="bluetooth_connecting">Подключение Bluetooth датчика...</string>
<string name="bluetooth_not_connected">Bluetooth датчик не подключен</string>
<!-- Sensor State -->
<string name="sensor_data_time">Датчик времени</string>
<string name="power_meter_enabled">Измеритель мощности включен</string>
<string name="heart_rate_monitor_enabled">Монитор пульса включен</string>
<string name="no_sensor_manager">Нет диспетчера датчиков</string>
<string name="enabled">Включено</string>
<string name="connecting">Подключение</string>
<string name="connected">Подключено</string>
<string name="disconnected">Отключено</string>
<string name="no_sensor_service">Нет службы датчиков</string>
<string name="searching">Поиск</string>
<string name="sending">Отправка</string>
<!-- Manifest description (not seen inside the app) -->
<string name="notification_permission_label">получать уведомления о записи трека</string>
<string name="read_tracks_permission_label">чтение записанных данных трека</string>
<string name="write_tracks_permission_label">запись данных трека, старт/стоп записи треков</string>
<string name="notification_permission_description">Получать уведомления, при старте или останове записи трека.</string>
<string name="read_tracks_permission_description">Иметь возможность читать данные трека, такие как точки и путевые точки.</string>
<string name="write_tracks_permission_description">Иметь возможность записать данные трека, такие как начало записи или добавление путевых точек.</string>
</resources>
+5 -18
View File
@@ -15,18 +15,6 @@ See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<!-- Task frequency -->
<string-array name="task_frequency_options">
<item>Av</item>
<item>1 min</item>
<item>2 min</item>
<item>5 min</item>
<item>10 min</item>
<item>15 min</item>
<item>30 min</item>
<item>60 min</item>
</string-array>
<!-- Minimum recording distance -->
<string-array name="min_recording_distance_options">
<item>1 m</item>
@@ -67,7 +55,6 @@ limitations under the License.
<item>3.1 miles</item>
</string-array>
<!-- Minimum recording interval -->
<string-array name="min_recording_interval_options">
<item>batterioptimerad (anpassningsbar)</item>
@@ -113,9 +100,9 @@ limitations under the License.
<item>3.1 miles (dålig GPS-signal)</item>
</string-array>
<!-- Split frequency -->
<string-array name="split_frequency_options">
<item>Ingen delning</item>
<!-- Task frequency -->
<string-array name="task_frequency_options">
<item>Av</item>
<item>100 km</item>
<item>50 km</item>
<item>25 km</item>
@@ -131,8 +118,8 @@ limitations under the License.
<item>1 min</item>
</string-array>
<string-array name="split_frequency_options_ft">
<item>Ingen delning</item>
<string-array name="task_frequency_options_ft">
<item>Av</item>
<item>100 mi</item>
<item>50 mi</item>
<item>25 mi</item>
+6 -17
View File
@@ -15,18 +15,6 @@ See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<!-- Task frequency -->
<string-array name="task_frequency_options">
<item>关闭</item>
<item>1 分钟</item>
<item>2 分钟</item>
<item>5 分钟</item>
<item>10 分钟</item>
<item>15 分钟</item>
<item>30 分钟</item>
<item>60 分钟</item>
</string-array>
<!-- Minimum recording distance -->
<string-array name="min_recording_distance_options">
<item>1 米</item>
@@ -112,9 +100,9 @@ limitations under the License.
<item>3.1 英里 (糟糕的 GPS 信号)</item>
</string-array>
<!-- Split frequency -->
<string-array name="split_frequency_options">
<item>不分割</item>
<!-- Task frequency -->
<string-array name="task_frequency_options">
<item>关闭</item>
<item>100 千米</item>
<item>50 千米</item>
<item>25 千米</item>
@@ -130,8 +118,8 @@ limitations under the License.
<item>1 分钟</item>
</string-array>
<string-array name="split_frequency_options_ft">
<item>不分割</item>
<string-array name="task_frequency_options_ft">
<item>关闭</item>
<item>100 英里</item>
<item>50 英里</item>
<item>25 英里</item>
@@ -155,6 +143,7 @@ limitations under the License.
<item>15 分钟</item>
<item>总是</item>
</string-array>
<!-- Other non-preference arrays -->
<array name="activity_types">
<item>未知</item>
+5 -138
View File
@@ -15,31 +15,6 @@ See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<!-- Task frequency -->
<string-array name="task_frequency_options">
<item>Off</item>
<item>1 min</item>
<item>2 min</item>
<item>5 min</item>
<item>10 min</item>
<item>15 min</item>
<item>30 min</item>
<item>60 min</item>
</string-array>
<!-- DO NOT TRANSLATE -->
<string-array name="task_frequency_values">
<item>-1</item>
<item>1</item>
<item>2</item>
<item>5</item>
<item>10</item>
<item>15</item>
<item>30</item>
<item>60</item>
</string-array>
<!-- Minimum recording distance -->
<string-array name="min_recording_distance_options">
<item>1 m</item>
@@ -61,18 +36,6 @@ limitations under the License.
<item>328 ft</item>
</string-array>
<!-- DO NOT TRANSLATE -->
<string-array name="min_recording_distance_values">
<item>1</item>
<item>2</item>
<item>3</item>
<item>4</item>
<item>5</item>
<item>10</item>
<item>100</item>
</string-array>
<!-- Maximum recording distance -->
<string-array name="max_recording_distance_options">
<item>50 m</item>
@@ -92,17 +55,6 @@ limitations under the License.
<item>3.1 miles</item>
</string-array>
<!-- DO NOT TRANSLATE -->
<string-array name="max_recording_distance_values">
<item>50</item>
<item>100</item>
<item>200</item>
<item>500</item>
<item>1000</item>
<item>5000</item>
</string-array>
<!-- Minimum recording interval -->
<string-array name="min_recording_interval_options">
<item>battery miser (adaptive)</item>
@@ -123,27 +75,6 @@ limitations under the License.
<item>30 min</item>
</string-array>
<!-- DO NOT TRANSLATE -->
<string-array name="min_recording_interval_values">
<item>-2</item>
<item>-1</item>
<item>0</item>
<item>2</item>
<item>3</item>
<item>4</item>
<item>5</item>
<item>10</item>
<item>20</item>
<item>30</item>
<item>60</item>
<item>120</item>
<item>300</item>
<item>480</item>
<item>900</item>
<item>1800</item>
</string-array>
<!-- Minimum required accuracy -->
<string-array name="min_required_accuracy_options">
<item>10 m (excellent GPS signal)</item>
@@ -169,23 +100,9 @@ limitations under the License.
<item>3.1 miles (poor GPS signal)</item>
</string-array>
<!-- DO NOT TRANSLATE -->
<string-array name="min_required_accuracy_values">
<item>10</item>
<item>20</item>
<item>50</item>
<item>100</item>
<item>200</item>
<item>500</item>
<item>1000</item>
<item>2000</item>
<item>5000</item>
</string-array>
<!-- Split frequency -->
<string-array name="split_frequency_options">
<item>No splitting</item>
<!-- Task frequency -->
<string-array name="task_frequency_options">
<item>Off</item>
<item>100 km</item>
<item>50 km</item>
<item>25 km</item>
@@ -201,8 +118,8 @@ limitations under the License.
<item>1 min</item>
</string-array>
<string-array name="split_frequency_options_ft">
<item>No splitting</item>
<string-array name="task_frequency_options_ft">
<item>Off</item>
<item>100 mi</item>
<item>50 mi</item>
<item>25 mi</item>
@@ -218,24 +135,6 @@ limitations under the License.
<item>1 min</item>
</string-array>
<!-- DO NOT TRANSLATE -->
<string-array name="split_frequency_values">
<item>0</item>
<item>-100</item>
<item>-50</item>
<item>-25</item>
<item>-10</item>
<item>-5</item>
<item>-1</item>
<item>60</item>
<item>30</item>
<item>15</item>
<item>10</item>
<item>5</item>
<item>2</item>
<item>1</item>
</string-array>
<!-- Auto-resume track timeout -->
<string-array name="auto_resume_track_timeout_options">
<item>Never</item>
@@ -245,16 +144,6 @@ limitations under the License.
<item>Always</item>
</string-array>
<!-- DO NOT TRANSLATE -->
<string-array name="auto_resume_track_timeout_values">
<item>0</item>
<item>5</item>
<item>10</item>
<item>15</item>
<item>-1</item>
</string-array>
<!-- Other non-preference arrays -->
<array name="activity_types">
<item>unknown</item>
@@ -383,14 +272,6 @@ limitations under the License.
<item>way point</item>
</array>
<!-- DO NOT TRANSLATE -->
<array name="export_formats">
<item>GPX</item>
<item>KML</item>
<item>CSV</item>
<item>TCX</item>
</array>
<array name="sensor_type_options">
<item>None</item>
<item>ANT+ Sensors</item>
@@ -398,18 +279,4 @@ limitations under the License.
<item>Zephyr Bluetooth</item>
</array>
<!-- DO NOT TRANSLATE -->
<array name="sensor_type_values">
<item>@string/none</item>
<item>@string/ant_sensor_type</item>
<item>@string/srm_ant_bridge_sensor_type</item>
<item>@string/zephyr_sensor_type</item>
</array>
<!-- DO NOT TRANSLATE -->
<string-array name="ant_sensor_type_values">
<item>@string/ant_sensor_type</item>
<item>@string/srm_ant_bridge_sensor_type</item>
</string-array>
</resources>
@@ -0,0 +1,122 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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.
-->
<resources>
<!-- Do not translate any arrays in this file. -->
<string-array name="min_required_accuracy_values">
<item>10</item>
<item>20</item>
<item>50</item>
<item>100</item>
<item>200</item>
<item>500</item>
<item>1000</item>
<item>2000</item>
<item>5000</item>
</string-array>
<string-array name="min_recording_distance_values">
<item>1</item>
<item>2</item>
<item>3</item>
<item>4</item>
<item>5</item>
<item>10</item>
<item>100</item>
</string-array>
<string-array name="min_recording_distance_values">
<item>1</item>
<item>2</item>
<item>3</item>
<item>4</item>
<item>5</item>
<item>10</item>
<item>100</item>
</string-array>
<string-array name="max_recording_distance_values">
<item>50</item>
<item>100</item>
<item>200</item>
<item>500</item>
<item>1000</item>
<item>5000</item>
</string-array>
<string-array name="min_recording_interval_values">
<item>-2</item>
<item>-1</item>
<item>0</item>
<item>2</item>
<item>3</item>
<item>4</item>
<item>5</item>
<item>10</item>
<item>20</item>
<item>30</item>
<item>60</item>
<item>120</item>
<item>300</item>
<item>480</item>
<item>900</item>
<item>1800</item>
</string-array>
<string-array name="task_frequency_values">
<item>0</item>
<item>-100</item>
<item>-50</item>
<item>-25</item>
<item>-10</item>
<item>-5</item>
<item>-1</item>
<item>60</item>
<item>30</item>
<item>15</item>
<item>10</item>
<item>5</item>
<item>2</item>
<item>1</item>
</string-array>
<string-array name="auto_resume_track_timeout_values">
<item>0</item>
<item>5</item>
<item>10</item>
<item>15</item>
<item>-1</item>
</string-array>
<array name="export_formats">
<item>GPX</item>
<item>KML</item>
<item>CSV</item>
<item>TCX</item>
</array>
<array name="sensor_type_values">
<item>@string/none</item>
<item>@string/ant_sensor_type</item>
<item>@string/srm_ant_bridge_sensor_type</item>
<item>@string/zephyr_sensor_type</item>
</array>
<string-array name="ant_sensor_type_values">
<item>@string/ant_sensor_type</item>
<item>@string/srm_ant_bridge_sensor_type</item>
</string-array>
</resources>
+2 -2
View File
@@ -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" />
<com.google.android.apps.mytracks.IntegerListPreference
@@ -24,7 +24,7 @@ import com.google.android.apps.mytracks.content.Sensor;
import com.google.android.apps.mytracks.content.Sensor.SensorDataSet;
import com.google.android.apps.mytracks.content.Track;
import com.google.android.apps.mytracks.content.Waypoint;
import com.google.android.apps.mytracks.services.StatusAnnouncerFactory;
import com.google.android.apps.mytracks.services.tasks.StatusAnnouncerFactory;
import com.google.android.apps.mytracks.stats.DoubleBuffer;
import com.google.android.apps.mytracks.stats.TripStatisticsBuilder;
import com.google.android.apps.mytracks.util.ApiFeatures;
@@ -21,7 +21,7 @@ import com.google.android.apps.mytracks.TrackDataHub.ListenerDataType;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.content.Track;
import com.google.android.apps.mytracks.content.Waypoint;
import com.google.android.apps.mytracks.services.StatusAnnouncerFactory;
import com.google.android.apps.mytracks.services.tasks.StatusAnnouncerFactory;
import com.google.android.apps.mytracks.stats.TripStatistics;
import com.google.android.apps.mytracks.util.ApiFeatures;
import com.google.android.apps.mytracks.util.GeoRect;
@@ -43,8 +43,8 @@ import com.google.android.apps.mytracks.io.sendtogoogle.SendDialog;
import com.google.android.apps.mytracks.io.sendtogoogle.SendResult;
import com.google.android.apps.mytracks.io.sendtogoogle.SendType;
import com.google.android.apps.mytracks.services.ITrackRecordingService;
import com.google.android.apps.mytracks.services.StatusAnnouncerFactory;
import com.google.android.apps.mytracks.services.TrackRecordingService;
import com.google.android.apps.mytracks.services.tasks.StatusAnnouncerFactory;
import com.google.android.apps.mytracks.util.ApiFeatures;
import com.google.android.apps.mytracks.util.FileUtils;
import com.google.android.apps.mytracks.util.SystemUtils;
@@ -19,8 +19,8 @@ import static com.google.android.apps.mytracks.Constants.TAG;
import com.google.android.apps.mytracks.io.backup.BackupActivityHelper;
import com.google.android.apps.mytracks.io.backup.BackupPreferencesListener;
import com.google.android.apps.mytracks.services.StatusAnnouncerFactory;
import com.google.android.apps.mytracks.services.sensors.ant.AntUtils;
import com.google.android.apps.mytracks.services.tasks.StatusAnnouncerFactory;
import com.google.android.apps.mytracks.util.ApiFeatures;
import com.google.android.apps.mytracks.util.BluetoothDeviceUtils;
import com.google.android.maps.mytracks.R;
@@ -266,9 +266,6 @@ public class SettingsActivity extends PreferenceActivity {
final ListPreference minRequiredAccuracy =
(ListPreference) findPreference(
getString(R.string.min_required_accuracy_key));
final ListPreference splitFrequency =
(ListPreference) findPreference(
getString(R.string.split_frequency_key));
minRecordingDistance.setEntries(isMetric
? R.array.min_recording_distance_options
@@ -279,11 +276,20 @@ public class SettingsActivity extends PreferenceActivity {
minRequiredAccuracy.setEntries(isMetric
? R.array.min_required_accuracy_options
: R.array.min_required_accuracy_options_ft);
splitFrequency.setEntries(isMetric
? R.array.split_frequency_options
: R.array.split_frequency_options_ft);
setTaskOptions(isMetric, R.string.announcement_frequency_key);
setTaskOptions(isMetric, R.string.split_frequency_key);
}
/**
* Set the user visible options for a periodic task.
*/
private void setTaskOptions(boolean isMetric, int listId) {
final ListPreference taskFrequency =
(ListPreference) findPreference(getString(listId));
taskFrequency.setEntries(isMetric
? R.array.task_frequency_options
: R.array.task_frequency_options_ft);
}
/**
* Configures preference actions related to bluetooth.
@@ -20,7 +20,7 @@ import static com.google.android.apps.mytracks.Constants.TAG;
import com.google.android.apps.mytracks.TrackDataHub.ListenerDataType;
import com.google.android.apps.mytracks.content.Track;
import com.google.android.apps.mytracks.content.Waypoint;
import com.google.android.apps.mytracks.services.StatusAnnouncerFactory;
import com.google.android.apps.mytracks.services.tasks.StatusAnnouncerFactory;
import com.google.android.apps.mytracks.util.ApiFeatures;
import com.google.android.maps.mytracks.R;
@@ -798,7 +798,7 @@ public class TrackDataHub {
if (RECORDING_TRACK_KEY.equals(key)) {
recordingTrackId = preferences.getLong(RECORDING_TRACK_KEY, -1);
} else if (MIN_REQUIRED_ACCURACY_KEY.equals(key)) {
minRequiredAccuracy = preferences.getInt(RECORDING_TRACK_KEY,
minRequiredAccuracy = preferences.getInt(MIN_REQUIRED_ACCURACY_KEY,
Constants.DEFAULT_MIN_REQUIRED_ACCURACY);
} else if (METRIC_UNITS_KEY.equals(key)) {
useMetricUnits = preferences.getBoolean(METRIC_UNITS_KEY, true);
@@ -1,12 +1,12 @@
/*
* Copyright 2008 Google Inc.
*
* Copyright 2011 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
@@ -15,332 +15,54 @@
*/
package com.google.android.apps.mytracks.io.file;
import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.content.MyTracksLocation;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.content.Track;
import com.google.android.apps.mytracks.content.Waypoint;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils.LocationIterator;
import com.google.android.apps.mytracks.util.FileUtils;
import com.google.android.apps.mytracks.util.LocationUtils;
import com.google.android.maps.mytracks.R;
import android.app.Activity;
import android.content.Context;
import android.database.Cursor;
import android.location.Location;
import android.util.Log;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.OutputStream;
/**
* The class which exports tracks to the SD card.
* This writer is format-neutral - it handles creating the output file
* and reading the track to be exported, but requires an instance of
* Implementations of this class export tracks to the SD card. This class is
* intended to be format-neutral - it handles creating the output file and
* reading the track to be exported, but requires an instance of
* {@link TrackFormatWriter} to actually format the data.
*
* @author Sandor Dornbush
* @author Rodrigo Damazio
*/
public class TrackWriter {
private final Context context;
private final MyTracksProviderUtils providerUtils;
private final Track track;
private final TrackFormatWriter writer;
private final FileUtils fileUtils;
private Runnable onCompletion = null;
private boolean success = false;
private int errorMessage = -1;
private File directory = null;
private File file = null;
public TrackWriter(Context context, MyTracksProviderUtils providerUtils,
Track track, TrackFormatWriter writer) {
this.context = context;
this.providerUtils = providerUtils;
this.track = track;
this.writer = writer;
this.fileUtils = new FileUtils();
}
public interface TrackWriter {
/**
* Sets a completion callback.
*
* @param onCompletion Runnable that will be executed when finished
*/
public void setOnCompletion(Runnable onCompletion) {
this.onCompletion = onCompletion;
}
void setOnCompletion(Runnable onCompletion);
/**
* Sets a custom directory where the file will be written.
*/
public void setDirectory(File directory) {
this.directory = directory;
}
void setDirectory(File directory);
public String getAbsolutePath() {
return file.getAbsolutePath();
}
/**
* Returns the absolute path to the file which was created.
*/
String getAbsolutePath();
/**
* Writes the given track id to the SD card.
* This is non-blocking.
*/
public void writeTrackAsync() {
Thread t = new Thread() {
@Override
public void run() {
writeTrack();
}
};
t.start();
}
void writeTrackAsync();
/**
* Writes the given track id to the SD card.
* This is blocking.
*/
public void writeTrack() {
// Open the input and output
success = false;
errorMessage = R.string.error_track_does_not_exist;
if (track != null) {
if (openFile()) {
writeDocument();
}
}
finished();
}
public int getErrorMessage() {
return errorMessage;
}
public boolean wasSuccess() {
return success;
}
/*
* Helper methods:
* ===============
*/
private void finished() {
if (onCompletion != null) {
runOnUiThread(onCompletion);
return;
}
}
void writeTrack();
/**
* Runs the given runnable in the UI thread.
* Returns true if the write completed successfully.
*/
protected void runOnUiThread(Runnable runnable) {
if (context instanceof Activity) {
((Activity) context).runOnUiThread(runnable);
}
}
boolean wasSuccess();
/**
* Opens the file and prepares the format writer for it.
*
* @return true on success, false otherwise (and errorMessage is set)
* Returns the error message (if any) generated by a writer failure.
*/
protected boolean openFile() {
if (!canWriteFile()) {
return false;
}
// Make sure the file doesn't exist yet (possibly by changing the filename)
String fileName = fileUtils.buildUniqueFileName(
directory, track.getName(), writer.getExtension());
if (fileName == null) {
Log.e(Constants.TAG,
"Unable to get a unique filename for " + fileName);
return false;
}
Log.i(Constants.TAG, "Writing track to: " + fileName);
try {
writer.prepare(track, newOutputStream(fileName));
} catch (FileNotFoundException e) {
Log.e(Constants.TAG, "Failed to open output file.", e);
errorMessage = R.string.io_write_failed;
return false;
}
return true;
}
/**
* Checks and returns whether we're ready to create the output file.
*/
protected boolean canWriteFile() {
if (directory == null) {
String dirName =
fileUtils.buildExternalDirectoryPath(writer.getExtension());
directory = newFile(dirName);
}
if (!fileUtils.isSdCardAvailable()) {
Log.i(Constants.TAG, "Could not find SD card.");
errorMessage = R.string.io_no_external_storage_found;
return false;
}
if (!fileUtils.ensureDirectoryExists(directory)) {
Log.i(Constants.TAG, "Could not create export directory.");
errorMessage = R.string.io_create_dir_failed;
return false;
}
return true;
}
/**
* Creates a new output stream to write to the given filename.
*
* @throws FileNotFoundException if the file could't be created
*/
protected OutputStream newOutputStream(String fileName)
throws FileNotFoundException {
file = new File(directory, fileName);
return new FileOutputStream(file);
}
/**
* Creates a new file object for the given path.
*/
protected File newFile(String path) {
return new File(path);
}
/**
* Writes the waypoints for the given track.
*
* @param trackId the ID of the track to write waypoints for
*/
private void writeWaypoints(long trackId) {
// TODO: Stream through he waypoints in chunks.
// I am leaving the number of waypoints very high which should not be a
// problem because we don't try to load them into objects all at the
// same time.
Cursor cursor = null;
cursor = providerUtils.getWaypointsCursor(trackId, 0,
Constants.MAX_LOADED_WAYPOINTS_POINTS);
if (cursor != null) {
try {
if (cursor.moveToFirst()) {
// Yes, this will skip the 1st way point and that is intentional
// as the 1st points holds the stats for the current/last segment.
while (cursor.moveToNext()) {
Waypoint wpt = providerUtils.createWaypoint(cursor);
writer.writeWaypoint(wpt);
}
}
} finally {
if (cursor != null) {
cursor.close();
}
}
}
}
/**
* Does the actual work of writing the track to the now open file.
*/
void writeDocument() {
Log.d(Constants.TAG, "Started writing track.");
writer.writeHeader();
writeWaypoints(track.getId());
writeLocations();
writer.writeFooter();
writer.close();
success = true;
Log.d(Constants.TAG, "Done writing track.");
errorMessage = R.string.io_write_finished;
}
private void writeLocations() {
boolean wroteFirst = false;
boolean segmentOpen = false;
boolean isLastValid = false;
class TrackWriterLocationFactory implements MyTracksProviderUtils.LocationFactory {
Location currentLocation;
Location lastLocation;
@Override
public Location createLocation() {
if (currentLocation == null) {
currentLocation = new MyTracksLocation("");
}
return currentLocation;
}
public void swapLocations() {
Location tmpLoc = lastLocation;
lastLocation = currentLocation;
currentLocation = tmpLoc;
if (currentLocation != null) {
currentLocation.reset();
}
}
};
TrackWriterLocationFactory locationFactory = new TrackWriterLocationFactory();
LocationIterator it = providerUtils.getLocationIterator(track.getId(), 0, false,
locationFactory);
try {
if (!it.hasNext()) {
Log.w(Constants.TAG, "Unable to get any points to write");
return;
}
while (it.hasNext()) {
Location loc = it.next();
boolean isValid = LocationUtils.isValidLocation(loc);
boolean validSegment = isValid && isLastValid;
if (!wroteFirst && validSegment) {
// Found the first two consecutive points which are valid
writer.writeBeginTrack(locationFactory.lastLocation);
wroteFirst = true;
}
if (validSegment) {
if (!segmentOpen) {
// Start a segment for this point
writer.writeOpenSegment();
segmentOpen = true;
// Write the previous point, which we had previously skipped
writer.writeLocation(locationFactory.lastLocation);
}
// Write the current point
writer.writeLocation(loc);
} else {
if (segmentOpen) {
writer.writeCloseSegment();
segmentOpen = false;
}
}
locationFactory.swapLocations();
isLastValid = isValid;
}
if (segmentOpen) {
writer.writeCloseSegment();
segmentOpen = false;
}
if (wroteFirst) {
writer.writeEndTrack(locationFactory.lastLocation);
}
} finally {
it.close();
}
}
int getErrorMessage();
}
@@ -106,7 +106,7 @@ public class TrackWriterFactory {
MyTracksProviderUtils providerUtils,
Track track, TrackFileFormat format) {
TrackFormatWriter writer = format.newFormatWriter(context);
return new TrackWriter(context, providerUtils, track, writer);
return new TrackWriterImpl(context, providerUtils, track, writer);
}
private TrackWriterFactory() { }
@@ -0,0 +1,336 @@
/*
* Copyright 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks.io.file;
import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.content.MyTracksLocation;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils.LocationIterator;
import com.google.android.apps.mytracks.content.Track;
import com.google.android.apps.mytracks.content.Waypoint;
import com.google.android.apps.mytracks.util.FileUtils;
import com.google.android.apps.mytracks.util.LocationUtils;
import com.google.android.maps.mytracks.R;
import android.app.Activity;
import android.content.Context;
import android.database.Cursor;
import android.location.Location;
import android.util.Log;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.OutputStream;
/**
* This class exports tracks to the SD card. It is intended to be format-
* neutral -- it handles creating the output file and reading the track to be
* exported, but requires an instance of {@link TrackFormatWriter} to actually
* format the data.
*
* @author Sandor Dornbush
* @author Rodrigo Damazio
*/
public class TrackWriterImpl implements TrackWriter {
private final Context context;
private final MyTracksProviderUtils providerUtils;
private final Track track;
private final TrackFormatWriter writer;
private final FileUtils fileUtils;
private Runnable onCompletion = null;
private boolean success = false;
private int errorMessage = -1;
private File directory = null;
private File file = null;
TrackWriterImpl(Context context, MyTracksProviderUtils providerUtils,
Track track, TrackFormatWriter writer) {
this.context = context;
this.providerUtils = providerUtils;
this.track = track;
this.writer = writer;
this.fileUtils = new FileUtils();
}
@Override
public void setOnCompletion(Runnable onCompletion) {
this.onCompletion = onCompletion;
}
@Override
public void setDirectory(File directory) {
this.directory = directory;
}
@Override
public String getAbsolutePath() {
return file.getAbsolutePath();
}
@Override
public void writeTrackAsync() {
Thread t = new Thread() {
@Override
public void run() {
writeTrack();
}
};
t.start();
}
@Override
public void writeTrack() {
// Open the input and output
success = false;
errorMessage = R.string.error_track_does_not_exist;
if (track != null) {
if (openFile()) {
writeDocument();
}
}
finished();
}
@Override
public int getErrorMessage() {
return errorMessage;
}
@Override
public boolean wasSuccess() {
return success;
}
/*
* Helper methods:
* ===============
*/
private void finished() {
if (onCompletion != null) {
runOnUiThread(onCompletion);
return;
}
}
/**
* Runs the given runnable in the UI thread.
*/
protected void runOnUiThread(Runnable runnable) {
if (context instanceof Activity) {
((Activity) context).runOnUiThread(runnable);
}
}
/**
* Opens the file and prepares the format writer for it.
*
* @return true on success, false otherwise (and errorMessage is set)
*/
protected boolean openFile() {
if (!canWriteFile()) {
return false;
}
// Make sure the file doesn't exist yet (possibly by changing the filename)
String fileName = fileUtils.buildUniqueFileName(
directory, track.getName(), writer.getExtension());
if (fileName == null) {
Log.e(Constants.TAG,
"Unable to get a unique filename for " + fileName);
return false;
}
Log.i(Constants.TAG, "Writing track to: " + fileName);
try {
writer.prepare(track, newOutputStream(fileName));
} catch (FileNotFoundException e) {
Log.e(Constants.TAG, "Failed to open output file.", e);
errorMessage = R.string.io_write_failed;
return false;
}
return true;
}
/**
* Checks and returns whether we're ready to create the output file.
*/
protected boolean canWriteFile() {
if (directory == null) {
String dirName =
fileUtils.buildExternalDirectoryPath(writer.getExtension());
directory = newFile(dirName);
}
if (!fileUtils.isSdCardAvailable()) {
Log.i(Constants.TAG, "Could not find SD card.");
errorMessage = R.string.io_no_external_storage_found;
return false;
}
if (!fileUtils.ensureDirectoryExists(directory)) {
Log.i(Constants.TAG, "Could not create export directory.");
errorMessage = R.string.io_create_dir_failed;
return false;
}
return true;
}
/**
* Creates a new output stream to write to the given filename.
*
* @throws FileNotFoundException if the file could't be created
*/
protected OutputStream newOutputStream(String fileName)
throws FileNotFoundException {
file = new File(directory, fileName);
return new FileOutputStream(file);
}
/**
* Creates a new file object for the given path.
*/
protected File newFile(String path) {
return new File(path);
}
/**
* Writes the waypoints for the given track.
*
* @param trackId the ID of the track to write waypoints for
*/
private void writeWaypoints(long trackId) {
// TODO: Stream through he waypoints in chunks.
// I am leaving the number of waypoints very high which should not be a
// problem because we don't try to load them into objects all at the
// same time.
Cursor cursor = null;
cursor = providerUtils.getWaypointsCursor(trackId, 0,
Constants.MAX_LOADED_WAYPOINTS_POINTS);
if (cursor != null) {
try {
if (cursor.moveToFirst()) {
// Yes, this will skip the 1st way point and that is intentional
// as the 1st points holds the stats for the current/last segment.
while (cursor.moveToNext()) {
Waypoint wpt = providerUtils.createWaypoint(cursor);
writer.writeWaypoint(wpt);
}
}
} finally {
if (cursor != null) {
cursor.close();
}
}
}
}
/**
* Does the actual work of writing the track to the now open file.
*/
void writeDocument() {
Log.d(Constants.TAG, "Started writing track.");
writer.writeHeader();
writeWaypoints(track.getId());
writeLocations();
writer.writeFooter();
writer.close();
success = true;
Log.d(Constants.TAG, "Done writing track.");
errorMessage = R.string.io_write_finished;
}
private void writeLocations() {
boolean wroteFirst = false;
boolean segmentOpen = false;
boolean isLastValid = false;
class TrackWriterLocationFactory implements MyTracksProviderUtils.LocationFactory {
Location currentLocation;
Location lastLocation;
@Override
public Location createLocation() {
if (currentLocation == null) {
currentLocation = new MyTracksLocation("");
}
return currentLocation;
}
public void swapLocations() {
Location tmpLoc = lastLocation;
lastLocation = currentLocation;
currentLocation = tmpLoc;
if (currentLocation != null) {
currentLocation.reset();
}
}
};
TrackWriterLocationFactory locationFactory = new TrackWriterLocationFactory();
LocationIterator it = providerUtils.getLocationIterator(track.getId(), 0, false,
locationFactory);
try {
if (!it.hasNext()) {
Log.w(Constants.TAG, "Unable to get any points to write");
return;
}
while (it.hasNext()) {
Location loc = it.next();
boolean isValid = LocationUtils.isValidLocation(loc);
boolean validSegment = isValid && isLastValid;
if (!wroteFirst && validSegment) {
// Found the first two consecutive points which are valid
writer.writeBeginTrack(locationFactory.lastLocation);
wroteFirst = true;
}
if (validSegment) {
if (!segmentOpen) {
// Start a segment for this point
writer.writeOpenSegment();
segmentOpen = true;
// Write the previous point, which we had previously skipped
writer.writeLocation(locationFactory.lastLocation);
}
// Write the current point
writer.writeLocation(loc);
} else {
if (segmentOpen) {
writer.writeCloseSegment();
segmentOpen = false;
}
}
locationFactory.swapLocations();
isLastValid = isValid;
}
if (segmentOpen) {
writer.writeCloseSegment();
segmentOpen = false;
}
if (wroteFirst) {
writer.writeEndTrack(locationFactory.lastLocation);
}
} finally {
it.close();
}
}
}
@@ -156,11 +156,11 @@ public class PreferenceManager implements OnSharedPreferenceChangeListener {
}
}
if (key == null || key.equals(splitFrequencyKey)) {
service.getSplitManager().setSplitFrequency(
service.setSplitFrequency(
sharedPreferences.getInt(splitFrequencyKey, 0));
}
if (key == null || key.equals(metricUnitsKey)) {
service.getSplitManager().setMetricUnits(
service.setMetricUnits(
sharedPreferences.getBoolean(metricUnitsKey, true));
}
}
@@ -1,160 +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 com.google.android.apps.mytracks.content.WaypointCreationRequest;
import com.google.android.apps.mytracks.util.UnitConversions;
import android.util.Log;
/**
* This class manages inserting time or distance splits.
*
* @author Sandor Dornbush
*/
public class SplitManager {
/**
* The frequency of splits.
*/
private int splitFrequency = 0;
/**
* The next distance when a split should be taken.
*/
private double nextSplitDistance = 0;
/**
* Splits executer.
*/
private PeriodicTaskExecuter splitExecuter = null;
private boolean metricUnits;
private final TrackRecordingService service;
public SplitManager(TrackRecordingService service) {
this.service = service;
}
/**
* Restores the manager.
*/
public void restore() {
if ((splitFrequency > 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.
* &lt; 0 Use the absolute value as a distance in the current measurement km
* or mi
* 0 Turn off splits
* &gt; 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();
}
}
@@ -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();
}
}
}
@@ -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);
}
}
@@ -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.
@@ -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.
@@ -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.
* &lt; 0 Use the absolute value as a distance in the current measurement km
* or mi
* 0 Turn off the task
* &gt; 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;
}
}
@@ -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);
}
@@ -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();
}
}
}
@@ -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()) {
@@ -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,
@@ -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();
@@ -10,7 +10,7 @@ import com.google.android.apps.mytracks.content.Track;
import com.google.android.apps.mytracks.content.Waypoint;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils.Factory;
import com.google.android.apps.mytracks.io.file.TrackFormatWriter;
import com.google.android.apps.mytracks.io.file.TrackWriter;
import com.google.android.apps.mytracks.io.file.TrackWriterImpl;
import com.google.android.apps.mytracks.services.TrackRecordingServiceTest.MockContext;
import com.google.android.apps.mytracks.testing.TestingProviderUtilsFactory;
@@ -35,10 +35,10 @@ import org.easymock.IMocksControl;
*/
public class TrackWriterTest extends AndroidTestCase {
/**
* {@link TrackWriter} subclass which mocks out methods called from
* {@link TrackWriter#openFile}.
* {@link TrackWriterImpl} subclass which mocks out methods called from
* {@link TrackWriterImpl#openFile}.
*/
private static final class OpenFileTrackWriter extends TrackWriter {
private static final class OpenFileTrackWriter extends TrackWriterImpl {
private final ByteArrayOutputStream stream;
private final boolean canWrite;
@@ -46,9 +46,9 @@ public class TrackWriterTest extends AndroidTestCase {
* Constructor.
*
* @param stream the stream to return from
* {@link TrackWriter#newOutputStream}, or null to throw a
* {@link TrackWriterImpl#newOutputStream}, or null to throw a
* {@link FileNotFoundException}
* @param canWrite the value that {@link TrackWriter#canWriteFile} will
* @param canWrite the value that {@link TrackWriterImpl#canWriteFile} will
* return
*/
private OpenFileTrackWriter(Context context,
@@ -80,16 +80,16 @@ public class TrackWriterTest extends AndroidTestCase {
}
/**
* {@link TrackWriter} subclass which mocks out methods called from
* {@link TrackWriter#writeTrack}.
* {@link TrackWriterImpl} subclass which mocks out methods called from
* {@link TrackWriterImpl#writeTrack}.
*/
private final class WriteTracksTrackWriter extends TrackWriter {
private final class WriteTracksTrackWriter extends TrackWriterImpl {
private final boolean openResult;
/**
* Constructor.
*
* @param openResult the return value for {@link TrackWriter#openFile}
* @param openResult the return value for {@link TrackWriterImpl#openFile}
*/
private WriteTracksTrackWriter(Context context,
MyTracksProviderUtils providerUtils, Track track,
@@ -123,7 +123,7 @@ public class TrackWriterTest extends AndroidTestCase {
private Track track;
private TrackFormatWriter formatWriter;
private TrackWriter writer;
private TrackWriterImpl writer;
private IMocksControl mocksControl;
private MyTracksProviderUtils providerUtils;
private Factory oldProviderUtilsFactory;
@@ -228,7 +228,7 @@ public class TrackWriterTest extends AndroidTestCase {
}
public void testWriteDocument_emptyTrack() {
writer = new TrackWriter(getContext(), providerUtils, track, formatWriter);
writer = new TrackWriterImpl(getContext(), providerUtils, track, formatWriter);
// Set expected mock behavior
formatWriter.writeHeader();
@@ -243,7 +243,7 @@ public class TrackWriterTest extends AndroidTestCase {
}
public void testWriteDocument() {
writer = new TrackWriter(getContext(), providerUtils, track, formatWriter);
writer = new TrackWriterImpl(getContext(), providerUtils, track, formatWriter);
final Location[] locs = {
new Location("fake0"),
@@ -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);
@@ -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;