Kill second head.

This commit is contained in:
Sandor Dornbush
2011-04-21 16:01:08 -07:00
198 changed files with 10855 additions and 4490 deletions
+2
View File
@@ -5,3 +5,5 @@ syntax:glob
*/proguard/**
.metadata
MyTracksTest/annotations.log
**/*.pyc
**/*.pyo
+18 -12
View File
@@ -17,8 +17,8 @@ limitations under the License.
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.google.android.maps.mytracks"
android:installLocation="auto"
android:versionCode="24"
android:versionName="1.1.1">
android:versionCode="27"
android:versionName="1.1.4">
<application android:icon="@drawable/arrow_icon"
android:label="@string/app_name"
android:backupAgent="com.google.android.apps.mytracks.io.backup.MyTracksBackupAgent">
@@ -52,23 +52,28 @@ limitations under the License.
</intent-filter>
</activity>
<activity android:name="com.google.android.apps.mytracks.MyTracksMap"
<activity android:name="com.google.android.apps.mytracks.MapActivity"
android:label="MyTracks"
android:exported="false" />
<activity android:name="com.google.android.apps.mytracks.MyTracksList"
<activity android:name="com.google.android.apps.mytracks.MyMapsList"
android:label="@string/map_list_title"
android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|fontScale"
android:exported="false" />
<activity android:name="com.google.android.apps.mytracks.TrackList"
android:label="Recorded Tracks" />
<activity android:name="com.google.android.apps.mytracks.MyTracksWaypointsList"
<activity android:name="com.google.android.apps.mytracks.WaypointsList"
android:label="Recorded Waypoints" />
<activity android:name="com.google.android.apps.mytracks.MyTracksDetails"
<activity android:name="com.google.android.apps.mytracks.TrackDetails"
android:label="@string/trackdetails_title" />
<activity android:name="com.google.android.apps.mytracks.MyTracksWaypointDetails"
<activity android:name="com.google.android.apps.mytracks.WaypointDetails"
android:label="@string/waypointdetails_title" />
<activity android:name="com.google.android.apps.mytracks.MyTracksSettings"
<activity android:name="com.google.android.apps.mytracks.SettingsActivity"
android:label="@string/mytracks_settings" />
<activity android:name="com.google.android.apps.mytracks.AggregatedStatsActivity"
@@ -96,7 +101,7 @@ limitations under the License.
android:exported="true"
android:permission="com.google.android.apps.mytracks.WRITE_TRACK_DATA" />
<receiver android:name="com.google.android.apps.mytracks.MyTracksReceiver">
<receiver android:name="com.google.android.apps.mytracks.BootReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
@@ -105,7 +110,7 @@ limitations under the License.
<!-- Permissions to initialize service -->
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<!-- Permissions for recording tracks and showing maps -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
@@ -159,14 +164,15 @@ limitations under the License.
<!-- Features required -->
<uses-feature android:name="android.hardware.location" android:required="true"/>
<uses-feature android:name="android.hardware.location.gps" android:required="true"/>
<uses-feature android:name="android.hardware.touchscreen" android:required="true"/>
<!-- Features optional -->
<uses-feature android:name="android.hardware.bluetooth" android:required="false"/>
<uses-feature android:name="android.hardware.faketouch" android:required="false"/>
<uses-feature android:name="android.hardware.location.network" android:required="false"/>
<uses-feature android:name="android.hardware.sensor.compass" android:required="false"/>
<uses-feature android:name="android.hardware.telephony" android:required="false"/>
<uses-feature android:name="android.hardware.telephony.gsm" android:required="false"/>
<uses-feature android:name="android.hardware.touchscreen" android:required="false"/>
<uses-feature android:name="android.hardware.touchscreen.multitouch" android:required="false"/>
<uses-sdk android:minSdkVersion="3"/>
+1 -1
View File
@@ -10,7 +10,7 @@
# Indicates whether an apk should be generated for each density.
split.density=false
# Project target.
target=Google Inc.:Google APIs:9
target=Google Inc.:Google APIs:11
android.library.reference.1=../MyTracksLib/
# ProGuard is turned off while we investigate the removal of code that
+17
View File
@@ -0,0 +1,17 @@
The libraries contained here in binary format are licensed according to their
own licenses, which allow their usage for the My Tracks application. Any other
applications that wish to use these files should consult the appropriate
licenses or the JAR's authors.
References are provided to the libraries:
accounts.jar (Android accounts library):
http://code.google.com/p/libs-for-android/wiki/AccountsLibrary
google-api-client-*.jar (GData client):
http://code.google.com/p/google-api-java-client/
google-common.jar,
googleloginclient-helper.jar,
libmymaps.jar (Google My Maps upload library):
Licensed exclusively for use in My Tracks and derived Android applications.
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 676 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 766 B

+103
View File
@@ -0,0 +1,103 @@
<?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.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apl/res/com.google.android.maps"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="@drawable/list_bar"
android:layout_weight="0"
android:padding="3dip">
<TextView android:id="@+id/message"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="16dip"
android:textColor="#fff"
android:text="@string/select_map_message"
android:layout_weight="0"/>
</LinearLayout>
<ListView android:id="@+id/maplist"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"/>
<TextView android:id="@+id/mapslist_empty"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_gravity="center"
android:gravity="center"
android:padding="3dip"
android:textSize="16dip"
android:textColor="#c00"
android:textStyle="bold"
android:text="@string/mapslist_no_maps_available"
android:visibility="gone"/>
<TextView android:id="@+id/failed"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:padding="3dip"
android:textSize="16dip"
android:textColor="#c00"
android:textStyle="bold"
android:text="@string/maps_list_failed"
android:visibility="gone"/>
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="@drawable/list_bar"
android:layout_weight="0"
android:padding="3dip">
<LinearLayout android:id="@+id/loading"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="3dip"
android:layout_gravity="center">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"/>
<ProgressBar
android:layout_height="20dip"
android:layout_width="20dip"
android:layout_gravity="center"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:paddingLeft="3dip"
android:textSize="16dip"
android:textColor="#fff"
android:textStyle="bold"
android:text="@string/maps_list_loading"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"/>
</LinearLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"/>
</LinearLayout>
</LinearLayout>
@@ -41,6 +41,39 @@ limitations under the License.
android:stretchColumns="1"
android:layout_marginTop="5dip"
android:layout_marginLeft="5dip">
<!-- My Maps -->
<TableRow>
<ImageView android:src="@drawable/mymaps_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginLeft="10dip">
<CheckBox android:id="@+id/sendtogoogle_google_mymaps"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/sendtogoogle_google_mymaps"
android:textSize="20dip"
android:checked="true"/>
<RadioGroup android:id="@+id/sendtogoogle_group_mymaps"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<RadioButton android:id="@+id/sendtogoogle_create_new_map"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/sendtogoogle_create_new_map"/>
<RadioButton android:id="@+id/sendtogoogle_pick_existing_map"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/sendtogoogle_pick_existing_map"/>
</RadioGroup>
</LinearLayout>
</TableRow>
<!-- Fusion Tables -->
<TableRow>
<ImageView android:src="@drawable/googledocs_icon"
android:layout_width="wrap_content"
@@ -58,6 +91,8 @@ limitations under the License.
android:checked="true"/>
</LinearLayout>
</TableRow>
<!-- Google Docs -->
<TableRow>
<ImageView android:src="@drawable/googledocs_icon"
android:layout_width="wrap_content"
@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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 License for the specific language governing permissions and
limitations under the License.
-->
<!--
This layout is used as the content view for the send-to-Google result dialog.
It is used to summarize the results of uploading track data to one or more
services.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:paddingTop="5dip"
android:paddingBottom="5dip"
android:paddingLeft="14dip"
android:paddingRight="14dip"
android:orientation="vertical">
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/status_track_upload_status"
style="?android:attr/textAppearanceLarge"/>
<TableLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_horizontal">
<!-- We don't want a divider, so we set its color to transparent. -->
<!-- We do this explicitly, rather than with a color resource, because -->
<!-- an apparent bug causes the divider to be wildly misrendered on -->
<!-- a Mini X10 running 2.1. -->
<ListView
android:id="@+id/send_to_google_result_list"
android:clickable="false"
android:paddingTop="10dip"
android:paddingBottom="10dip"
android:divider="#00000000"/>
</TableLayout>
<TextView
android:id="@+id/send_to_google_result_comment"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/status_mymap_info"
android:visibility="gone"
style="?android:attr/textAppearanceSmall"/>
<TextView
android:id="@+id/send_to_google_result_error"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/error_please_try_again_later"
android:visibility="gone"
style="?android:attr/textAppearanceLarge"/>
</LinearLayout>
@@ -0,0 +1,49 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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 License for the specific language governing permissions and
limitations under the License.
-->
<!--
This layout represents the result of sending track data to a single service.
It will be instantiated by a custom ListAdapter - once for each service to
which track data was uploaded.
-->
<TableRow
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/send_to_google_result_icon"
android:src="@drawable/success"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_gravity="top"/>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/send_to_google_result_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Google Docs"
style="?android:attr/textAppearanceMedium"/>
<TextView
android:id="@+id/send_to_google_result_url"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="http://google.com"
style="?android:attr/textAppearanceSmall"/>
</LinearLayout>
</TableRow>
+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>
-2
View File
@@ -133,7 +133,6 @@ limitations under the License.
<string name="tracklist_all_tracks">Totes les rutes:</string>
<string name="tracklist_this_track">Aquesta ruta</string>
<string name="tracklist_share_track">Comparteix amb amics...</string>
<string name="tracklist_share_linkfusion">Un enllaç a Google Fusion Table</string>
<string name="tracklist_share_gpx_file">Un fitxer GPX</string>
<string name="tracklist_share_kml_file">Un fitxer KML</string>
<string name="tracklist_share_csv_file">Un fitxer CSV</string>
@@ -226,7 +225,6 @@ limitations under the License.
<string name="settings_backup_to_sd_summary">Escriu una còpia completa de totes les rutes i els paràmetres a la targeta SD</string>
<string name="settings_restore_from_sd">Restaura ara</string>
<string name="settings_restore_from_sd_summary">Restaura totes les rutes i els paràmetres des de la targeta SD.</string>
<string name="settings_no_backup_while_recording">No es poden gestionar les còpies de seguretat mentre s\'enregistra una ruta.</string>
<!-- Backups -->
<string name="restore_overwrites_warning">La restauració d\'una còpia de seguretat des de la targeta SD sobreescriurà totes les rutes i paràmetres. Esteu segur?</string>
+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>
+394 -369
View File
@@ -1,255 +1,259 @@
<?xml version="1.0" encoding="utf-8"?>
<?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">Track aufzeichnen</string>
<string name="stop_recording">Aufzeichnung anhalten</string>
<string name="switch_to_sat">Satellitenansicht</string>
<string name="switch_to_map">Kartenansicht</string>
<string name="mylocation">Mein Aufenthaltsort</string>
-->
<resources>
<!-- Used by the Menu -->
<string name="start_recording">Track aufzeichnen</string>
<string name="stop_recording">Aufzeichnung anhalten</string>
<string name="switch_to_sat">Satellitenansicht</string>
<string name="switch_to_map">Kartenansicht</string>
<string name="mylocation">Mein Aufenthaltsort</string>
<!--string name="list_tracks">Tracks</string-->
<string name="list_markers">Wegpunkte</string>
<string name="delete_all_tracks">Alle Tracks löschen</string>
<string name="settings">Einstellungen</string>
<string name="elevation">Höhe</string>
<string name="choose_track_message">Bitte wähle einen Track zur Ansicht aus</string>
<string name="current_track">Aktueller Track</string>
<string name="current_segment">Letztes Segment</string>
<string name="sensor_state">Sensorstatus</string>
<string name="aggregated_stats">Aggregierte Statistiken</string>
<!-- Error messages -->
<string name="error_no_location_manager">Es wurde kein Dienst zur Positionsermittlung auf diesem Gerät gefunden.</string>
<string name="error_no_gps_location_provider">Es wurde kein GPS-Empfänger auf diesem Gerät gefunden.</string>
<string name="error_sending_to_fusiontables">Beim Senden des Tracks an Google Fusion Tables ist ein Fehler aufgetreten. Bitte versuche es später noch einmal.</string>
<string name="error_sending_to_docs">Beim Senden des Tracks an Google Docs ist ein Fehler aufgetreten. Bitte versuche es später noch einmal.</string>
<string name="error_unable_to_start_recording">Start der Aufzeichnung fehlgeschlagen. Bitte versuche es noch einmal.</string>
<string name="error_unable_to_stop_recording">Anhalten unmöglich. Bitte versuche es noch einmal.</string>
<string name="error_unable_to_read_file">Konnte Datei nicht lesen.</string>
<string name="error_invalid_gpx_format">Datei ist nicht im GPX-Format.</string>
<string name="error_generic">Ein Fehler ist aufgetreten. Bitte versuche es noch einmal.</string>
<string name="error_track_does_not_exist">Track existiert nicht.</string>
<string name="error_out_of_memory">Die Datei ist zu groß (maximal 500 KB). Operation abgebrochen.</string>
<string name="error_unable_to_insert_marker">Der Wegpunkt kann nicht einfügt werden. Keine Positionsbestimmung möglich.</string>
<!-- Status messages -->
<string name="wait_for_fix">Warte auf ein besseres GPS-Signal. Bitte stelle sicher, dass der Himmel sichtbar ist.</string>
<string name="status_now_recording">Ein neuer Track wird aufgezeichnet.</string>
<string name="status_stopped_recording">Die Aufzeichnung wurde angehalten.</string>
<string name="status_new_fusiontable_has_been_created">Eine neue Tabelle wurde auf google.com/fusiontables erstellt.</string>
<string name="status_tracks_have_been_uploaded">Dein Track wurde auf maps.google.com gespeichert.</string>
<string name="status_tracks_have_been_uploaded_to_new_doc">Dein Track wurde in einer neuen Tabelle bei docs.google.com gespeichert.</string>
<string name="status_tracks_have_been_uploaded_to_docs">Dein Track wurde an docs.google.com gesendet.</string>
<string name="status_enable_gps">Hier berühren, um zu den Sicherheits- und Positionseinstellungen zu gelangen. Aktiviere \'GPS-Satelliten\'. Drücke dann den Zurück-Knopf, um hierher zurückzukehren.</string>
<string name="status_approximate_location">Anmerkung: Eine ungefähre Position wird angezeigt, bestimmt mittels Mobilfunkstationen und WiFi-Netzwerken.</string>
<string name="status_no_location">Die Position kann derzeit nicht bestimmt werden. Aktiviere mehr Positionsquellen (siehe Sicherheits- und Positionseinstellungen) und stelle sicher, dass der Himmel sichtbar ist.</string>
<string name="status_waypoint_inserted">Ein Wegpunkt wurde eingefügt.</string>
<string name="status_statistics_inserted">Ein Statistikwegpunkt wurde eingefügt.</string>
<!-- Progress dialog -->
<string name="progress_title">Bitte warten…</string>
<string name="progress_message">Dein Track wird an Google gesendet...</string>
<string name="progress_message_reading_track">Lese Track...</string>
<string name="progress_message_preparing_track">Bereite Track vor...</string>
<string name="progress_message_authenticating_fusiontables">Anmeldung bei Google Fusion Tables...</string>
<string name="progress_message_authenticating_docs">Anmeldung bei Google Docs...</string>
<string name="progress_message_sending_docs">Track wird an Google Docs gesendet...</string>
<string name="progress_message_sending_fusiontables">Track wird an Google Fusion Tables gesendet...</string>
<string name="progress_message_creating_fusiontable">Neue \'Fusion Tabelle\' wird erstellt...</string>
<string name="import_progress_message">Importiere GPS-Track. Das kann ein wenig dauern.</string>
<string name="write_progress_message">Schreibe Datei auf SD-Karte. Das kann ein wenig dauern.</string>
<string name="progress_message_updating_track">Aktualisiere Trackstatistik...</string>
<!-- Used by DeleteAllDataHandler -->
<string name="are_you_sure_question">Bist Du Dir wirklich sicher?</string>
<string name="all_data_will_be_permanently_deleted">Alle Tracks und Wegpunkte werden endgültig von diesem Gerät gelöscht.</string>
<string name="track_will_be_permanently_deleted">Dieser Track und seine Wegpunkte werden endgültig von diesem Gerät gelöscht.</string>
<string name="marker_will_be_permanently_deleted">Dieser Wegpunkt wird endgültig von diesem Gerät gelöscht.</string>
<!-- Text and links when uploading to Google Fusion Tables -->
<string name="new_map_description">Erstellt von My Tracks für Android.</string>
<string name="delete_all_tracks">Alle Tracks löschen</string>
<string name="settings">Einstellungen</string>
<string name="elevation">Höhe</string>
<string name="choose_track_message">Bitte wähle einen Track zur Ansicht aus</string>
<string name="current_track">Aktueller Track</string>
<string name="current_segment">Letztes Segment</string>
<string name="sensor_state">Sensorstatus</string>
<string name="aggregated_stats">Aggregierte Statistiken</string>
<!-- Error messages -->
<string name="error_no_location_manager">Es wurde kein Dienst zur Positionsermittlung auf diesem Gerät gefunden.</string>
<string name="error_no_gps_location_provider">Es wurde kein GPS-Empfänger auf diesem Gerät gefunden.</string>
<string name="error_sending_to_fusiontables">Beim Senden des Tracks an Google Fusion Tables ist ein Fehler aufgetreten. Bitte versuche es später noch einmal.</string>
<string name="error_sending_to_docs">Beim Senden des Tracks an Google Text &amp; Tabellen ist ein Fehler aufgetreten. Bitte versuche es später noch einmal.</string>
<string name="error_unable_to_start_recording">Start der Aufzeichnung fehlgeschlagen. Bitte versuche es noch einmal.</string>
<string name="error_unable_to_stop_recording">Anhalten unmöglich. Bitte versuche es noch einmal.</string>
<string name="error_unable_to_read_file">Konnte Datei nicht lesen.</string>
<string name="error_invalid_gpx_format">Datei ist nicht im GPX-Format.</string>
<string name="error_generic">Ein Fehler ist aufgetreten. Bitte versuche es noch einmal.</string>
<string name="error_track_does_not_exist">Track existiert nicht.</string>
<string name="error_out_of_memory">Die Datei ist zu groß (maximal 500 KB). Operation abgebrochen.</string>
<string name="error_unable_to_insert_marker">Der Wegpunkt kann nicht einfügt werden. Keine Positionsbestimmung möglich.</string>
<!-- Status messages -->
<string name="wait_for_fix">Warte auf ein besseres GPS-Signal. Bitte stelle sicher, dass der Himmel sichtbar ist.</string>
<string name="status_now_recording">Ein neuer Track wird aufgezeichnet.</string>
<string name="status_stopped_recording">Die Aufzeichnung wurde angehalten.</string>
<string name="status_new_fusiontable_has_been_created">Eine neue Tabelle wurde auf google.com/fusiontables erstellt.</string>
<string name="status_tracks_have_been_uploaded">Dein Track wurde auf maps.google.com gespeichert.</string>
<string name="status_tracks_have_been_uploaded_to_new_doc">Dein Track wurde in einer neuen Tabelle bei docs.google.com gespeichert.</string>
<string name="status_tracks_have_been_uploaded_to_docs">Dein Track wurde an docs.google.com gesendet.</string>
<string name="status_enable_gps">Hier berühren, um zu den Sicherheits- und Positionseinstellungen zu gelangen. Aktiviere \'GPS-Satelliten\'. Drücke dann den Zurück-Knopf, um hierher zurückzukehren.</string>
<string name="status_approximate_location">Anmerkung: Eine ungefähre Position wird angezeigt, bestimmt mittels Mobilfunkstationen und WiFi-Netzwerken.</string>
<string name="status_no_location">Die Position kann derzeit nicht bestimmt werden. Aktiviere mehr Positionsquellen (siehe Sicherheits- und Positionseinstellungen) und stelle sicher, dass der Himmel sichtbar ist.</string>
<string name="status_waypoint_inserted">Ein Wegpunkt wurde eingefügt.</string>
<string name="status_statistics_inserted">Ein Statistikwegpunkt wurde eingefügt.</string>
<!-- Progress dialog -->
<string name="progress_title">Bitte warten…</string>
<string name="progress_message">Dein Track wird an Google gesendet...</string>
<string name="progress_message_reading_track">Lese Track...</string>
<string name="progress_message_preparing_track">Bereite Track vor...</string>
<string name="progress_message_authenticating_fusiontables">Anmeldung bei Google Fusion Tables...</string>
<string name="progress_message_authenticating_docs">Anmeldung bei Google Text &amp; Tabellen...</string>
<string name="progress_message_sending_docs">Track wird an Google Text &amp; Tabellen gesendet...</string>
<string name="progress_message_sending_fusiontables">Track wird an Google Fusion Tables gesendet...</string>
<string name="progress_message_creating_fusiontable">Neue \'Fusion Tabelle\' wird erstellt...</string>
<string name="import_progress_message">Importiere GPS-Track. Das kann ein wenig dauern.</string>
<string name="write_progress_message">Schreibe Datei auf SD-Karte. Das kann ein wenig dauern.</string>
<string name="progress_message_updating_track">Aktualisiere Trackstatistik...</string>
<!-- Used by DeleteAllDataHandler -->
<string name="are_you_sure_question">Bist Du Dir wirklich sicher?</string>
<string name="all_data_will_be_permanently_deleted">Alle Tracks und Wegpunkte werden endgültig von diesem Gerät gelöscht.</string>
<string name="track_will_be_permanently_deleted">Dieser Track und seine Wegpunkte werden endgültig von diesem Gerät gelöscht.</string>
<string name="marker_will_be_permanently_deleted">Dieser Wegpunkt wird endgültig von diesem Gerät gelöscht.</string>
<!-- Text and links when uploading to Google Fusion Tables -->
<string name="new_map_description">Erstellt von My Tracks für Android.</string>
<string name="fusiontable_link">Erstellt von &lt;a href=\'http://mytracks.appspot.com\'&gt;My Tracks&lt;/a&gt; für Android.</string>
<!-- Formatting of track and marker descriptions -->
<string name="points">Punkte</string>
<string name="recorded_date">Aufgezeichnet am</string>
<string name="category">Aktivität</string>
<string name="waypoint_category">Art des Wegpunktes</string>
<string name="part">(Teil %d)</string>
<!-- Used by the track recording service -->
<!-- Formatting of track and marker descriptions -->
<string name="points">Punkte</string>
<string name="recorded_date">Aufgezeichnet am</string>
<string name="category">Aktivität</string>
<string name="waypoint_category">Art des Wegpunktes</string>
<string name="part">(Teil %d)</string>
<!-- Used by the track recording service -->
<string name="recording_your_track">Dein Track wird aufgezeichnet…</string>
<!-- Common -->
<string name="no">Nein</string>
<string name="yes">Ja</string>
<string name="error">Fehler</string>
<string name="success">Erfolgreich</string>
<string name="waypoint">Wegpunkt</string>
<!--string name="new_track">Track %d</string-->
<!-- Common -->
<string name="no">Nein</string>
<string name="yes">Ja</string>
<!--string name="ok">OK</string-->
<string name="error">Fehler</string>
<string name="success">Erfolgreich</string>
<string name="waypoint">Wegpunkt</string>
<string name="license">Lizenz</string>
<string name="cancel">Abbrechen</string>
<string name="close">Schließen</string>
<string name="edit">Bearbeiten</string>
<string name="save">Sichern</string>
<!-- Placemark labels for start and end of track -->
<string name="end">(Ende)</string>
<!-- TrackList -->
<string name="tracklist_show_track">Anzeigen</string>
<!-- Placemark labels for start and end of track -->
<!--string name="start">(Start)</string-->
<string name="end">(Ende)</string>
<!-- TrackList -->
<string name="tracklist_show_track">Anzeigen</string>
<string name="tracklist_send_to_fusiontables">An eine Google Fusion Tables-Karte senden</string>
<string name="tracklist_send_to_new_fusiontable">An eine neue Google Fusion Tables-Karte senden</string>
<string name="tracklist_send_to_docs">An Google Docs senden</string>
<string name="tracklist_send_to_google">An Google senden…</string>
<string name="tracklist_delete_track">Vom Gerät löschen…</string>
<string name="tracklist_edit_track">Bearbeiten</string>
<string name="tracklist_write_to_sd">Auf SD-Karte speichern…</string>
<string name="tracklist_save_as_gpx">GPX-Datei exportieren</string>
<string name="tracklist_save_as_kml">KML-Datei exportieren</string>
<string name="tracklist_save_as_csv">CSV-Datei exportieren</string>
<string name="tracklist_save_as_tcx">TCX-Datei exportieren</string>
<string name="tracklist_btn_send_all_to_fusiontables">An Google Fusion Tables senden</string>
<string name="tracklist_btn_delete_all">Alle Tracks löschen</string>
<string name="tracklist_send_to_new_fusiontable">An eine neue Google Fusion Tables-Karte senden</string>
<string name="tracklist_send_to_docs">An Google Text &amp; Tabellen senden</string>
<string name="tracklist_send_to_google">An Google senden…</string>
<string name="tracklist_delete_track">Vom Gerät löschen…</string>
<string name="tracklist_edit_track">Bearbeiten</string>
<string name="tracklist_write_to_sd">Auf SD-Karte speichern…</string>
<string name="tracklist_save_as_gpx">GPX-Datei exportieren</string>
<string name="tracklist_save_as_kml">KML-Datei exportieren</string>
<string name="tracklist_save_as_csv">CSV-Datei exportieren</string>
<string name="tracklist_save_as_tcx">TCX-Datei exportieren</string>
<string name="tracklist_btn_send_all_to_fusiontables">An Google Fusion Tables senden</string>
<string name="tracklist_btn_delete_all">Alle Tracks löschen</string>
<!-- Export All -->
<string name="tracklist_btn_export_all">Alle Tracks exportieren</string>
<string name="export_done">Exportieren beendet</string>
<string name="tracklist_pick_one">Einen Track auswählen. Lange berühren für mehr Optionen.</string>
<string name="tracklist_all_tracks">Alle Tracks</string>
<string name="tracklist_this_track">Dieser Track</string>
<string name="tracklist_share_track">Mit Freunden teilen…</string>
<string name="tracklist_share_linkfusion">Ein Link zur Google Fusion Tables-Karte</string>
<string name="tracklist_share_gpx_file">Eine GPX-Datei</string>
<string name="tracklist_share_kml_file">Eine KML-Datei</string>
<string name="tracklist_share_csv_file">Eine CSV-Datei</string>
<string name="tracklist_share_tcx_file">Eine TCX-Datei</string>
<string name="tracklist_clear_map">Karte zurücksetzen.</string>
<!-- Waypoints list -->
<string name="waypointslist_btn_delete_all">Alle Wegpunkte löschen</string>
<string name="waypointslist_this_waypoint">Dieser Wegpunkt</string>
<string name="waypointslist_delete_waypoint">Löschen</string>
<string name="waypointslist_edit_waypoint">Details bearbeiten</string>
<string name="waypointslist_show_waypoint">Auf der Karte zeigen</string>
<string name="waypointslist_btn_insert_waypoint">Wegpunkt einfügen</string>
<string name="waypointslist_btn_insert_statistics">Statistik einfügen</string>
<string name="waypointslist_pick_one">Wegpunkt auswählen. Lange berühren für mehr Optionen.</string>
<!-- MyTracks Details -->
<string name="trackdetails_title">Trackdetails</string>
<string name="trackdetails_name">Name</string>
<string name="trackdetails_description">Beschreibung</string>
<string name="trackdetails_category">Aktivität (z. B. Wandern, Fahrradfahren, Laufen, Klettern…)</string>
<!-- MyTracks Waypoint Details -->
<string name="waypointdetails_title">Wegpunktdetails</string>
<string name="waypointdetails_name">Wegpunktname</string>
<string name="waypointdetails_description">Wegpunktbeschreibung</string>
<string name="waypointdetails_category">Art des Wegpunktes (z. B. Gebäude, Schlagloch, Sehenswürdigkeit…)</string>
<!-- MyTracks Settings -->
<string name="mytracks_settings">Einstellungen für My Tracks</string>
<string name="settings_display">Anzeige</string>
<string name="settings_recording">Aufzeichnung</string>
<string name="settings_sharing">Mit Freunden teilen</string>
<string name="settings_not_available_summary">In dieser Android-Version nicht verfügbar</string>
<string name="settings_announcement_frequency">Dauer zwischen Ansagen</string>
<string name="settings_announcement_frequency_summary">Kürzeste Zeit zwischen zwei Ansagen</string>
<string name="settings_min_recording_distance">Kleinste Entfernung zwischen Punkten</string>
<string name="settings_min_recording_distance_summary">Kleinste Entfernung zwischen zwei Positionsaufzeichnungen</string>
<string name="settings_max_recording_distance">Neues Segment, wenn Punkte weiter entfernt als</string>
<string name="settings_max_recording_distance_summary">Der Track wird in zwei geteilt, wenn zwei folgende Punkte weiter entfernt sind als hier angegeben.</string>
<string name="settings_min_recording_interval">Aufzeichnungsfrequenz</string>
<string name="settings_min_recording_interval_summary">Kürzeste Zeit zwischen zwei Positionsaufzeichnungen</string>
<string name="settings_min_required_accuracy">Aufzeichnung pausieren, wenn Genauigkeit kleiner als</string>
<string name="settings_min_required_accuracy_summary">Die Aufzeichnung wird kurzfristig angehalten, wenn Deine Position nicht genauer als hier angegeben ermittelt werden kann.</string>
<string name="settings_metric_units">Entfernungen in metrischen Einheiten anzeigen</string>
<string name="settings_metric_units_summary_on">Alle Entfernungen werden in metrischen Einheiten angezeigt.</string>
<string name="settings_metric_units_summary_off">Alle Entfernungen werden in imperialen Längeneinheiten angezeigt.</string>
<string name="settings_map_public">Karten auf maps.google.com veröffentlichen</string>
<string name="settings_map_public_summary_on">Hochgeladene Karten auf maps.google.com sind für alle sichtbar.</string>
<string name="settings_map_public_summary_off">Hochgeladene Karten auf maps.google.com werden nicht öffentlich sichtbar aufgelistet.</string>
<string name="settings_report_speed_or_pace">Geschwindigkeitsanzeige</string>
<string name="settings_report_speed_or_pace_summary_on">Geschwindigkeit wird angezeigt.</string>
<string name="settings_report_speed_or_pace_summary_off">Pace wird angezeigt.</string>
<string name="settings_share_url_only">Nur URL als Einladung zum Teilen senden</string>
<string name="settings_share_url_only_summary_on">Beim Teilen mit Freunden wird nur die Karten-URL gesendet.</string>
<string name="settings_share_url_only_summary_off">Beim Teilen mit Freunden wird der GPS-Track selbst gesendet.</string>
<string name="settings_split_frequency">Zerteilungsfrequenz</string>
<string name="settings_split_frequency_summary">Längste Dauer oder Entfernung, nach der automatisch ein Marker eingefügt wird.</string>
<string name="settings_auto_resume_track_timeout">Zeitbegrenzung der Auto-Wiederaufnahme</string>
<string name="settings_auto_resume_track_timeout_summary">Maximale Zeit in Minuten, nach der eine abgebrochene Aufzeichnung nach einem Telefonneustart wiederaufgenommen wird.</string>
<string name="settings_timestamp_track_name">Zeitstempel als Trackname</string>
<string name="settings_timestamp_track_name_summary_on">Der Trackname wird aus Datum und Zeit zum Aufzeichnungsbeginn zusammengesetzt.</string>
<string name="settings_timestamp_track_name_summary_off">Tracknamen erhalten eine fortlaufende Nummer.</string>
<string name="pace_label">Pace</string>
<string name="eclair_required">Wird nur unter Android 2.0 oder höher unterstützt</string>
<string name="settings_sensor_type">Sensortyp</string>
<string name="tracklist_btn_export_all">Alle Tracks exportieren</string>
<string name="export_done">Exportieren beendet</string>
<string name="tracklist_pick_one">Einen Track auswählen. Lange berühren für mehr Optionen.</string>
<string name="tracklist_all_tracks">Alle Tracks</string>
<string name="tracklist_this_track">Dieser Track</string>
<string name="tracklist_share_track">Mit Freunden teilen…</string>
<string name="tracklist_share_linkfusion">Ein Link zur Google Fusion Tables-Karte</string>
<string name="tracklist_share_gpx_file">Eine GPX-Datei</string>
<string name="tracklist_share_kml_file">Eine KML-Datei</string>
<string name="tracklist_share_csv_file">Eine CSV-Datei</string>
<string name="tracklist_share_tcx_file">Eine TCX-Datei</string>
<string name="tracklist_clear_map">Karte zurücksetzen.</string>
<!-- Waypoints list -->
<string name="waypointslist_btn_delete_all">Alle Wegpunkte löschen</string>
<string name="waypointslist_this_waypoint">Dieser Wegpunkt</string>
<string name="waypointslist_delete_waypoint">Löschen</string>
<string name="waypointslist_edit_waypoint">Details bearbeiten</string>
<string name="waypointslist_show_waypoint">Auf der Karte zeigen</string>
<string name="waypointslist_btn_insert_waypoint">Wegpunkt einfügen</string>
<string name="waypointslist_btn_insert_statistics">Statistik einfügen</string>
<string name="waypointslist_pick_one">Wegpunkt auswählen. Lange berühren für mehr Optionen.</string>
<!-- MyTracks Details -->
<string name="trackdetails_title">Trackdetails</string>
<string name="trackdetails_name">Name</string>
<string name="trackdetails_description">Beschreibung</string>
<string name="trackdetails_category">Aktivität (z. B. Wandern, Fahrradfahren, Laufen, Klettern…)</string>
<!-- MyTracks Waypoint Details -->
<string name="waypointdetails_title">Wegpunktdetails</string>
<string name="waypointdetails_name">Wegpunktname</string>
<string name="waypointdetails_description">Wegpunktbeschreibung</string>
<string name="waypointdetails_category">Art des Wegpunktes (z. B. Gebäude, Schlagloch, Sehenswürdigkeit…)</string>
<!-- MyTracks Settings -->
<string name="mytracks_settings">Einstellungen für My Tracks</string>
<string name="settings_display">Anzeige</string>
<string name="settings_recording">Aufzeichnung</string>
<string name="settings_sharing">Mit Freunden teilen</string>
<string name="settings_not_available_summary">In dieser Android-Version nicht verfügbar</string>
<string name="settings_announcement_frequency">Dauer zwischen Ansagen</string>
<string name="settings_announcement_frequency_summary">Kürzeste Zeit zwischen zwei Ansagen</string>
<string name="settings_min_recording_distance">Kleinste Entfernung zwischen Punkten</string>
<string name="settings_min_recording_distance_summary">Kleinste Entfernung zwischen zwei Positionsaufzeichnungen</string>
<string name="settings_max_recording_distance">Neues Segment, wenn Punkte weiter entfernt als</string>
<string name="settings_max_recording_distance_summary">Der Track wird in zwei geteilt, wenn zwei folgende Punkte weiter entfernt sind als hier angegeben.</string>
<string name="settings_min_recording_interval">Aufzeichnungsfrequenz</string>
<string name="settings_min_recording_interval_summary">Kürzeste Zeit zwischen zwei Positionsaufzeichnungen</string>
<string name="settings_min_required_accuracy">Aufzeichnung pausieren, wenn Genauigkeit kleiner als</string>
<string name="settings_min_required_accuracy_summary">Die Aufzeichnung wird kurzfristig angehalten, wenn Deine Position nicht genauer als hier angegeben ermittelt werden kann.</string>
<string name="settings_metric_units">Entfernungen in metrischen Einheiten anzeigen</string>
<string name="settings_metric_units_summary_on">Alle Entfernungen werden in metrischen Einheiten angezeigt.</string>
<string name="settings_metric_units_summary_off">Alle Entfernungen werden in imperialen Längeneinheiten angezeigt.</string>
<string name="settings_map_public">Karten auf maps.google.com veröffentlichen</string>
<string name="settings_map_public_summary_on">Hochgeladene Karten auf maps.google.com sind für alle sichtbar.</string>
<string name="settings_map_public_summary_off">Hochgeladene Karten auf maps.google.com werden nicht öffentlich sichtbar aufgelistet.</string>
<string name="settings_report_speed_or_pace">Geschwindigkeitsanzeige</string>
<string name="settings_report_speed_or_pace_summary_on">Geschwindigkeit wird angezeigt.</string>
<string name="settings_report_speed_or_pace_summary_off">Pace wird angezeigt.</string>
<string name="settings_share_url_only">Nur URL als Einladung zum Teilen senden</string>
<string name="settings_share_url_only_summary_on">Beim Teilen mit Freunden wird nur die Karten-URL gesendet.</string>
<string name="settings_share_url_only_summary_off">Beim Teilen mit Freunden wird der GPS-Track selbst gesendet.</string>
<string name="settings_split_frequency">Zerteilungsfrequenz</string>
<string name="settings_split_frequency_summary">Längste Dauer oder Entfernung, nach der automatisch ein Marker eingefügt wird.</string>
<string name="settings_auto_resume_track_timeout">Zeitbegrenzung der Auto-Wiederaufnahme</string>
<string name="settings_auto_resume_track_timeout_summary">Maximale Zeit in Minuten, nach der eine abgebrochene Aufzeichnung nach einem Telefonneustart wiederaufgenommen wird.</string>
<string name="settings_timestamp_track_name">Zeitstempel als Trackname</string>
<string name="settings_timestamp_track_name_summary_on">Der Trackname wird aus Datum und Zeit zum Aufzeichnungsbeginn zusammengesetzt.</string>
<string name="settings_timestamp_track_name_summary_off">Tracknamen erhalten eine fortlaufende Nummer.</string>
<string name="pace_label">Pace</string>
<string name="eclair_required">Wird nur unter Android 2.0 oder höher unterstützt</string>
<string name="settings_sensor_type">Sensortyp</string>
<string name="settings_sensor_type_summary">Der Typ des zu verbindenden Sensors</string>
<string name="settings_heart_rate_ant_sensor_id">Verbindung mit ANT Herzqrequenzmesser aufheben</string>
<string name="settings_power_ant_sensor_id">Verbindung mit ANT Kraftmesser aufheben</string>
<string name="settings_srm_bridge_ant_sensor_id">Verbindung mit ANT srm bridge aufheben</string>
<string name="settings_ant_not_paired">ANT-Sensor nicht verbunden</string>
<string name="settings_ant_paired">ANT-Sensor verbunden mit: %d</string>
<string name="bluetooth_sensor_title">Bluetooth-Sensor</string>
<string name="bluetooth_sensor_summary">Der zu verbindende Bluetoothsensor</string>
<string name="settings_modular_stats_display_title">Art der Datenanzeige</string>
<!-- Backups -->
<string name="settings_backup">Datensicherung (BETA)</string>
<string name="settings_sd_backup">SD-Karten-Sicherung</string>
<string name="settings_backup_to_sd">Jetzt sichern</string>
<string name="settings_backup_to_sd_summary">Eine Kopie aller Deiner Tracks und Einstellungen auf die SD-Karte schreiben</string>
<string name="settings_restore_from_sd">Jetzt wiederherstellen</string>
<string name="settings_restore_from_sd_summary">Alle Tracks und Einstellungen von der SD-Karte holen.</string>
<string name="settings_no_backup_while_recording">Während ein Track aufgezeichnet wird, kann nicht mit der Datensicherung gearbeitet werden.</string>
<string name="restore_overwrites_warning">Eine Wiederherstellung von der SD-Karte ÜBERSCHREIBT alle vorhandenen Tracks und Einstellungen. Willst Du das wirklich?</string>
<string name="select_backup_to_restore">Wähle die wiederherzustellende Datensicherung aus</string>
<string name="no_backups">Keine Datensicherungen gefunden.</string>
<string name="backup_write_progress_message">Schreibe alle Tracks und Einstellungen auf die SD-Karte. Dies kann eine Weile dauern...</string>
<string name="backup_import_progress_message">Lese alle Tracks und Einstellungen von der SD-Karte. Dies kann eine Weile dauern...</string>
<!-- MyTracksSky -->
<string name="mytracks_sky">GPS-Satelliten</string>
<string name="bluetooth_sensor_title">Bluetooth-Sensor</string>
<string name="bluetooth_sensor_summary">Der zu verbindende Bluetoothsensor</string>
<string name="settings_modular_stats_display_title">Art der Datenanzeige</string>
<!-- Sharing -->
<!-- Backups -->
<string name="settings_backup">Datensicherung (BETA)</string>
<string name="settings_sd_backup">SD-Karten-Sicherung</string>
<string name="settings_backup_to_sd">Jetzt sichern</string>
<string name="settings_backup_to_sd_summary">Eine Kopie aller Deiner Tracks und Einstellungen auf die SD-Karte schreiben</string>
<string name="settings_restore_from_sd">Jetzt wiederherstellen</string>
<string name="settings_restore_from_sd_summary">Alle Tracks und Einstellungen von der SD-Karte holen.</string>
<string name="settings_no_backup_while_recording">Während ein Track aufgezeichnet wird, kann nicht mit der Datensicherung gearbeitet werden.</string>
<string name="restore_overwrites_warning">Eine Wiederherstellung von der SD-Karte ÜBERSCHREIBT alle vorhandenen Tracks und Einstellungen. Willst Du das wirklich?</string>
<string name="select_backup_to_restore">Wähle die wiederherzustellende Datensicherung aus</string>
<string name="no_backups">Keine Datensicherungen gefunden.</string>
<string name="backup_write_progress_message">Schreibe alle Tracks und Einstellungen auf die SD-Karte. Dies kann eine Weile dauern...</string>
<string name="backup_import_progress_message">Lese alle Tracks und Einstellungen von der SD-Karte. Dies kann eine Weile dauern...</string>
<!-- MyTracksSky -->
<string name="mytracks_sky">GPS-Satelliten</string>
<!-- Sharing -->
<string name="share_map">Karte mit Freunden teilen</string>
<string name="share_map_subject">Ich möchte gerne eine Karte mit Dir teilen.</string>
<string name="share_map_subject">Ich möchte gerne eine Karte mit Dir teilen.</string>
<string name="share_map_body_format">Vielleicht interessierst Du Dich für diese Karte:
%s</string>
<string name="send_track_subject">Ich möchte einen GPS-Track mit Dir teilen</string>
%s</string>
<string name="send_track_subject">Ich möchte einen GPS-Track mit Dir teilen</string>
<string name="send_track_body_format">Vielleicht interessierst Du Dich für diese Track:
%s.</string>
Der Track kann mit Google Earth oder anderer Karten-Software visualisiert werden.</string>
<string name="share_track">Track mit Freunden teilen</string>
<!-- Visibility -->
@@ -257,126 +261,145 @@ limitations under the License.
<string name="unlisted_map">Nicht in Suchergebnissen enthalten.</string>
<string name="mapslist_no_maps_available">Du hast noch keine Karten.</string>
<!-- Statistics View -->
<!-- Average Moving -->
<string name="average_moving_speed_label">Durchschnitt in Bew.</string>
<string name="average_moving_pace_label">Pace in Bew.</string>
<!-- Average -->
<string name="average_speed_label">Durchschnittsgeschw.</string>
<string name="average_pace_label">Durchschnitts-Pace</string>
<string name="elevation_chart_name">Höhenprofil</string>
<string name="elevation_gain_label">Höhengewinn</string>
<string name="elevation_label">Höhe</string>
<string name="latitude_label">Breitengrad</string>
<string name="longitude_label">Längengrad</string>
<!-- Min -->
<string name="min_elevation_label">Niedrigste Höhenlage</string>
<string name="min_grade_label">Minimale Steigung</string>
<string name="min_pace_label">Minimaler Pace</string>
<!-- Max -->
<string name="max_elevation_label">Höchste Höhenlage</string>
<string name="max_grade_label">Maximale Steigung</string>
<string name="max_speed_label">Max. Geschwindigkeit</string>
<string name="loading_track">Lade Track…</string>
<!-- Chart Settings -->
<string name="chart_settings">Diagramm-Einstellungen</string>
<!-- X Axis -->
<string name="x_axis">X-Achse</string>
<string name="by_distance">Nach Entfernung</string>
<string name="by_time">Nach Zeit</string>
<!-- Y Axis -->
<string name="y_axis">Y-Achse</string>
<!-- Units -->
<!-- Time -->
<string name="hour">Stunde</string>
<string name="hours">Stunden</string>
<string name="hr">Std</string>
<string name="minute">Minute</string>
<string name="minutes">Minuten</string>
<string name="second">Sekunde</string>
<string name="seconds">Sekunden</string>
<!-- Distance -->
<!-- Statistics View -->
<!-- Average Moving -->
<string name="average_moving_speed_label">Durchschnitt in Bew.</string>
<string name="average_moving_pace_label">Pace in Bew.</string>
<!-- Average -->
<string name="average_speed_label">Durchschnittsgeschw.</string>
<string name="average_pace_label">Durchschnitts-Pace</string>
<string name="elevation_chart_name">Höhenprofil</string>
<string name="elevation_gain_label">Höhengewinn</string>
<string name="elevation_label">Höhe</string>
<string name="latitude_label">Breitengrad</string>
<string name="longitude_label">Längengrad</string>
<!-- Min -->
<string name="min_elevation_label">Niedrigste Höhenlage</string>
<string name="min_grade_label">Minimale Steigung</string>
<string name="min_pace_label">Minimaler Pace</string>
<!-- Max -->
<string name="max_elevation_label">Höchste Höhenlage</string>
<string name="max_grade_label">Maximale Steigung</string>
<string name="max_speed_label">Max. Geschwindigkeit</string>
<string name="loading_track">Lade Track…</string>
<!-- Chart Settings -->
<string name="chart_settings">Diagramm-Einstellungen</string>
<!-- X Axis -->
<string name="x_axis">X-Achse</string>
<string name="by_distance">Nach Entfernung</string>
<string name="by_time">Nach Zeit</string>
<!-- Y Axis -->
<string name="y_axis">Y-Achse</string>
<!-- Units -->
<!-- Time -->
<string name="hour">Stunde</string>
<string name="hours">Stunden</string>
<string name="hr">Std</string>
<string name="min">Min</string>
<string name="minute">Minute</string>
<string name="minutes">Minuten</string>
<string name="second">Sekunde</string>
<string name="seconds">Sekunden</string>
<!--string name="milliseconds">ms</string-->
<!-- Distance -->
<!--string name="meter">m</string-->
<!--string name="kilometer">km</string-->
<string name="kilometers_long">Kilometer</string>
<string name="feet">Fuß</string>
<string name="miles_long">Meilen</string>
<!-- Speed and Pace -->
<string name="kilometer_per_hour_long">Kilometer pro Stunde</string>
<string name="per_kilometer">pro Kilometer</string>
<string name="mile_per_hour_long">Meilen pro Stunde</string>
<string name="per_mile">pro Meile</string>
<!--string name="mile">mi</string-->
<string name="miles_long">Meilen</string>
<!-- Stats Labels -->
<string name="moving_time_label">Zeit in Bewegung</string>
<string name="total_time_label">Gesamtzeit</string>
<string name="time_label">Zeit</string>
<string name="sd_unavail">SD-Karte nicht verfügbar</string>
<string name="speed">Geschwindigkeit</string>
<string name="start_trip">Du musst erst eine Aufzeichnung beginnen.</string>
<string name="statistics">Statistik</string>
<string name="total_distance_label">Gesamtentfernung</string>
<string name="distance_label">Entfernung</string>
<string name="power">Kraft</string>
<string name="cadence">Kadenz</string>
<string name="heart_rate">Herzfrequenz</string>
<string name="max_heart_rate">Höchste Herzfrequenz</string>
<string name="waiting">Bitte warten…</string>
<!-- End User License Agreement -->
<string name="eula_title">Lizenzvereinbarung für Endverbraucher</string>
<string name="accept">Akzeptieren</string>
<string name="decline">Ablehnen</string>
<!-- About -->
<string name="about">Über</string>
<string name="help">Hilfe</string>
<!-- Speed and Pace -->
<!--string name="kilometer_per_hour">km/h</string-->
<string name="kilometer_per_hour_long">Kilometer pro Stunde</string>
<!--string name="min_per_kilometer">min/km</string-->
<string name="per_kilometer">pro Kilometer</string>
<!--string name="mile_per_hour">mi/h</string-->
<string name="mile_per_hour_long">Meilen pro Stunde</string>
<!--string name="min_per_mile">min/mi</string-->
<string name="per_mile">pro Meile</string>
<!-- Sensors -->
<!--string name="watts">W</string-->
<!--string name="revolutions_per_minute">rpm</string-->
<!--string name="bpm">bpm</string-->
<!-- Stats Labels -->
<string name="moving_time_label">Zeit in Bewegung</string>
<string name="total_time_label">Gesamtzeit</string>
<string name="time_label">Zeit</string>
<string name="sd_unavail">SD-Karte nicht verfügbar</string>
<string name="speed">Geschwindigkeit</string>
<string name="start_trip">Du musst erst eine Aufzeichnung beginnen.</string>
<string name="statistics">Statistik</string>
<string name="total_distance_label">Gesamtentfernung</string>
<string name="distance_label">Entfernung</string>
<string name="power">Kraft</string>
<string name="cadence">Kadenz</string>
<string name="heart_rate">Herzfrequenz</string>
<string name="max_heart_rate">Höchste Herzfrequenz</string>
<!--string name="unknown">-</string-->
<string name="waiting">Bitte warten…</string>
<!-- End User License Agreement -->
<string name="eula_title">Lizenzvereinbarung für Endverbraucher</string>
<string name="accept">Akzeptieren</string>
<string name="decline">Ablehnen</string>
<!-- About -->
<string name="about">Über</string>
<string name="help">Hilfe</string>
<!--string name="about_team">Team:</string-->
<!--string name="about_version">Version:</string-->
<string name="about_support">Unterstützung:</string>
<string name="about_privacy">Datenschutz:</string>
<!-- Send to Google -->
<string name="sendtogoogle_title">Senden an…</string>
<!--string name="sendtogoogle_google_fusiontables">Google Fusion Tables</string-->
<string name="sendtogoogle_google_docs">Google Text &amp; Tabellen</string>
<string name="sendtogoogle_send_now">Jetzt senden</string>
<string name="sendtogoogle_send_stats">Trackstatistik senden</string>
<string name="sendtogoogle_send_stats_and_points">Statistik und Punkte senden</string>
<!-- Getting the account to upload to. -->
<string name="no_account_found_title">Kein Konto vorhanden</string>
<string name="no_account_found">Kein Konto gefunden, um Tracks zu versenden.</string>
<string name="choose_account_title">Wähle ein Konto</string>
<!-- SD card -->
<string name="io_no_external_storage_found">Keine externes Speichermedium verfügbar. Stelle sicher, dass eine SD-Karte vorhanden ist und nicht bereits von einem Computer darauf zugegriffen wird.</string>
<string name="io_write_failed">Die Datei kann nicht geschrieben werden.</string>
<string name="io_read_failed">Die Datei konnte nicht gelesen werden.</string>
<string name="io_create_dir_failed">Das Verzeichnis auf der SD-Karte kann nicht erstellt werden.</string>
<string name="io_write_finished">Der Track wurde auf die SD-Karte geschrieben.</string>
<string name="io_read_finished">Lesen von der SD-Karte beendet.</string>
<!-- VersionChecker -->
<string name="version_check_title">Suche nach neuer Version</string>
<string name="version_check_upgrade_button">Jetzt aktualisieren</string>
<string name="version_check_continue_button">Fortfahren, ohne zu aktualisieren</string>
<string name="upgrade_required">Deine Version von %1$s funktioniert möglicherweise nicht mehr richtig und wird nicht mehr unterstützt. Bitte aktualisiere %1$s.</string>
<string name="upgrade_recommended">Deine Version von %1$s funktioniert möglicherweise nicht mehr richtig. Du kannst sie jetzt aktualisieren, oder auf sie auf eigene Gefahr weiterverwenden. Einige Funktionen wie Datenaustausch mit Google-Diensten werden möglicherweise nicht mehr funktionieren, solange Du die Software nicht aktualisierst.</string>
<string name="upgrade_available">Eine neue Version von %1$s ist jetzt verfügbar. Du kannst Deine installierte Version ohne Probleme weiterverwenden, aber um die neuesten Funktionen in Anspruch nehmen zu können, musst Du die Software aktualisieren.</string>
<!-- Welcome -->
<string name="welcome">Willkommen</string>
<string name="sendtogoogle_send_now">Jetzt senden</string>
<string name="sendtogoogle_send_stats">Trackstatistik senden</string>
<string name="sendtogoogle_send_stats_and_points">Statistik und Punkte senden</string>
<!-- Getting the account to upload to. -->
<string name="no_account_found_title">Kein Konto vorhanden</string>
<string name="no_account_found">Kein Konto gefunden, um Tracks zu versenden.</string>
<string name="choose_account_title">Wähle ein Konto</string>
<!-- SD card -->
<string name="io_no_external_storage_found">Keine externes Speichermedium verfügbar. Stelle sicher, dass eine SD-Karte vorhanden ist und nicht bereits von einem Computer darauf zugegriffen wird.</string>
<string name="io_write_failed">Die Datei kann nicht geschrieben werden.</string>
<string name="io_read_failed">Die Datei konnte nicht gelesen werden.</string>
<string name="io_create_dir_failed">Das Verzeichnis auf der SD-Karte kann nicht erstellt werden.</string>
<string name="io_write_finished">Der Track wurde auf die SD-Karte geschrieben.</string>
<string name="io_read_finished">Lesen von der SD-Karte beendet.</string>
<!-- VersionChecker -->
<string name="version_check_title">Suche nach neuer Version</string>
<string name="version_check_upgrade_button">Jetzt aktualisieren</string>
<string name="version_check_continue_button">Fortfahren, ohne zu aktualisieren</string>
<string name="upgrade_required">Deine Version von %1$s funktioniert möglicherweise nicht mehr richtig und wird nicht mehr unterstützt. Bitte aktualisiere %1$s.</string>
<string name="upgrade_recommended">Deine Version von %1$s funktioniert möglicherweise nicht mehr richtig. Du kannst sie jetzt aktualisieren, oder auf sie auf eigene Gefahr weiterverwenden. Einige Funktionen wie Datenaustausch mit Google-Diensten werden möglicherweise nicht mehr funktionieren, solange Du die Software nicht aktualisierst.</string>
<string name="upgrade_available">Eine neue Version von %1$s ist jetzt verfügbar. Du kannst Deine installierte Version ohne Probleme weiterverwenden, aber um die neuesten Funktionen in Anspruch nehmen zu können, musst Du die Software aktualisieren.</string>
<!-- Welcome -->
<string name="welcome">Willkommen</string>
<string name="welcome_read_later">OK</string>
<string name="welcome_about">Über My Tracks</string>
<!-- Announcement -->
<string name="announce_no_distance">My Tracks keine Entfernung</string>
<string name="welcome_about">Über My Tracks</string>
<!-- Announcement -->
<string name="announce_no_distance">My Tracks keine Entfernung</string>
<!-- Format:
$1 : Distance label
$2 : Distance value (5)
@@ -384,42 +407,44 @@ limitations under the License.
$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">My Tracks %1$s %2$.2f %3$s in %4$s mit %5$s %6$s</string>
<!-- Check Units -->
<string name="check_units_title">Einheitenbenachrichtigung</string>
<string name="check_units_message">Voreingestellt sind metrische Einheiten. Willst Du diese Einstellung ändern?</string>
-->
<string name="announce_template">My Tracks %1$s %2$.2f %3$s in %4$s mit %5$s %6$s</string>
<!-- Check Units -->
<string name="check_units_title">Einheitenbenachrichtigung</string>
<string name="check_units_message">Voreingestellt sind metrische Einheiten. Willst Du diese Einstellung ändern?</string>
<!-- Fake preference keys - never saved, but show options in the preferences screen -->
<string name="bluetooth_options">Bluetooth-Einstellungen</string>
<string name="bluetooth_pairing">Geräteverbindung</string>
<string name="bluetooth_pairing_summary">Öffnet Androids Bluetooth-Einstellungen, um Geräte zu verbinden.</string>
<string name="sensor_options">Sensor-Einstellungen</string>
<!-- Bluetooth Sensor -->
<string name="bluetooth_connected">Verbunden mit %s</string>
<string name="bluetooth_connecting">Verbinde mit Bluetooth-Sensor ...</string>
<string name="bluetooth_not_connected">Bluetooth-Sensor nicht verbunden.</string>
<!-- Sensor State -->
<string name="sensor_data_time">Uhrzeit</string>
<string name="power_meter_enabled">Kraftmesser aktiviert</string>
<string name="heart_rate_monitor_enabled">Herzfrequenzmessung aktiviert</string>
<string name="no_sensor_manager">Keine Sensoren verfügbar</string>
<string name="enabled">Aktiviert</string>
<string name="connecting">Verbinde...</string>
<string name="connected">Verbunden</string>
<string name="disconnected">Getrennt</string>
<string name="no_sensor_service">Kein Sensor-Dienst</string>
<string name="searching">Suche...</string>
<string name="sending">Sende...</string>
<!-- Manifest description (not seen inside the app) -->
<string name="notification_permission_label">Track-Aufzeichnungs-Benachrichtigungen empfangen</string>
<string name="read_tracks_permission_label">Aufgezeichnete Trackdaten lesen</string>
<string name="write_tracks_permission_label">Aufgezeichnete Trackdaten schreiben, Starten/Anhalten des Aufzeichnens von Tracks</string>
<string name="notification_permission_description">Werde benachrichtigt, wenn die Aufzeichnung eines Tracks beginnt oder anhält.</string>
<string name="read_tracks_permission_description">Ermöglicht das Lesen von Trackdaten wie Messpunkten oder Wegpunkten.</string>
<string name="write_tracks_permission_description">Ermöglicht das Schreiben von Trackdaten wie beim Starten der Aufzeichnung oder beim Hinzufügen von Wegpunkten.</string>
</resources>
<string name="method_bluetooth">Bluetooth</string>
<string name="bluetooth_options">Bluetooth-Einstellungen</string>
<string name="bluetooth_pairing">Geräteverbindung</string>
<string name="bluetooth_pairing_summary">Öffnet Androids Bluetooth-Einstellungen, um Geräte zu verbinden.</string>
<!--string name="sensor_bluetooth_options_key">bluetoothSensorsEnabled</string-->
<string name="sensor_options">Sensor-Einstellungen</string>
<!-- Bluetooth Sensor -->
<string name="bluetooth_connected">Verbunden mit %s</string>
<string name="bluetooth_connecting">Verbinde mit Bluetooth-Sensor ...</string>
<string name="bluetooth_not_connected">Bluetooth-Sensor nicht verbunden.</string>
<!-- Sensor State -->
<string name="sensor_data_time">Uhrzeit</string>
<string name="power_meter_enabled">Kraftmesser aktiviert</string>
<string name="heart_rate_monitor_enabled">Herzfrequenzmessung aktiviert</string>
<string name="no_sensor_manager">Keine Sensoren verfügbar</string>
<string name="enabled">Aktiviert</string>
<string name="connecting">Verbinde...</string>
<string name="connected">Verbunden</string>
<string name="disconnected">Getrennt</string>
<string name="no_sensor_service">Kein Sensor-Dienst</string>
<string name="searching">Suche...</string>
<string name="sending">Sende...</string>
<!-- Manifest description (not seen inside the app) -->
<string name="notification_permission_label">Track-Aufzeichnungs-Benachrichtigungen empfangen</string>
<string name="read_tracks_permission_label">Aufgezeichnete Trackdaten lesen</string>
<string name="write_tracks_permission_label">Aufgezeichnete Trackdaten schreiben, Starten/Anhalten des Aufzeichnens von Tracks</string>
<string name="notification_permission_description">Werde benachrichtigt, wenn die Aufzeichnung eines Tracks beginnt oder anhält.</string>
<string name="read_tracks_permission_description">Ermöglicht das Lesen von Trackdaten wie Messpunkten oder Wegpunkten.</string>
<string name="write_tracks_permission_description">Ermöglicht das Schreiben von Trackdaten wie beim Starten der Aufzeichnung oder beim Hinzufügen von Wegpunkten.</string>
</resources>
-1
View File
@@ -47,7 +47,6 @@ limitations under the License.
<string name="tracklist_save_as_tcx">Guardar en archivo TCX</string>
<string name="tracklist_btn_send_all_to_fusiontables">Enviar a Google Fusion Tables</string>
<!-- Export All -->
<string name="tracklist_share_linkfusion">Un enlace a Google Fusion Tables</string>
<string name="tracklist_share_csv_file">Un archivo CSV</string>
<string name="tracklist_share_tcx_file">Un archivo TCX</string>
+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>
+17 -19
View File
@@ -25,37 +25,37 @@ 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>
<!-- Error messages -->
<string name="error_no_location_manager">Ningún administrador de ubicación fue hallado en este aparato! </string>
<string name="error_no_gps_location_provider">Ningún proveedor GPS de ubicación fue hallado en este aparato.</string>
<string name="error_sending_to_fusiontables">Hubo un error al mandar su recorrido a Google Fusion Tables. Por favor inténtelo de nuevo más tarde.</string>
<string name="error_sending_to_docs">Hubo un error al mandar su recorrido a Google Docs. Por favor inténtelo de nuevo más tarde.</string>
<string name="error_unable_to_start_recording">No pude empezar a grabar. Por favor inténtelo de nuevo. </string>
<string name="error_unable_to_stop_recording">No pude dejar de grabar. Por favor inténtelo de nuevo.</string>
<string name="error_no_location_manager">Ningún administrador de ubicación fue hallado en este dispositivo! </string>
<string name="error_no_gps_location_provider">Ningún proveedor de ubicación GPS fue hallado en este dispositivo.</string>
<string name="error_sending_to_fusiontables">Se produjo un error al enviar su recorrido a Google Fusion Tables.</string>
<string name="error_sending_to_docs">Se produjo un error al enviar su recorrido a Google Docs.</string>
<string name="error_unable_to_start_recording">No se puede iniciar la grabación. Inténtelo de nuevo. </string>
<string name="error_unable_to_stop_recording">No se puede detener la grabación. Inténtelo de nuevo.</string>
<string name="error_unable_to_read_file">No pude leer del archivo.</string>
<string name="error_invalid_gpx_format">El archivo no tiene un format GPX válido.</string>
<string name="error_generic">Error. Por favor inténtelo de nuevo.</string>
<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 pude insertar la señal. 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>
@@ -121,7 +121,6 @@ limitations under the License.
<string name="tracklist_all_tracks">Todos los recorridos:"</string>
<string name="tracklist_this_track">Este recorrido"</string>
<string name="tracklist_share_track">Compartir con amigos..."</string>
<string name="tracklist_share_linkfusion">Un enlace a Google Fusion Tables</string>
<string name="tracklist_share_gpx_file">Un archivo GPX"</string>
<string name="tracklist_share_kml_file">Un archivo KML"</string>
<string name="tracklist_clear_map">"Limpiar mapa"</string>
@@ -213,7 +212,6 @@ limitations under the License.
<string name="settings_backup_to_sd_summary">Hacer una copia total de sus recorridos y configuraciones a la tarjeta SD</string>
<string name="settings_restore_from_sd">Restaurar</string>
<string name="settings_restore_from_sd_summary">Restaurar todos los recorridos y configuraciones desde la tarjeta SD</string>
<string name="settings_no_backup_while_recording">No se pueden manejar backups mientras se está registrando un recorrido.</string>
<string name="restore_overwrites_warning">Restaurar un backup desde la tarjeta SD SOBREESCRIBIRÁ todos sus recorridos y configuraciones actuales. ¿Está usted seguro?</string>
<string name="select_backup_to_restore">Seleccionar el backup para restaurar</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>
+1 -4
View File
@@ -127,7 +127,6 @@ limitations under the License.
<string name="tracklist_all_tracks">Tous les parcours:</string>
<string name="tracklist_this_track">Ce parcours</string>
<string name="tracklist_share_track">Partager...</string>
<string name="tracklist_share_linkfusion">Lien sur Google Fusion Tables</string>
<string name="tracklist_share_gpx_file">Fichier GPX</string>
<string name="tracklist_share_kml_file">Fichier KML</string>
<string name="tracklist_clear_map">Effacer la carte</string>
@@ -161,7 +160,7 @@ limitations under the License.
<string name="settings_sharing">Partage</string>
<string name="settings_announcement_frequency">Fréquence des annonces</string>
<string name="settings_announcement_frequency_summary">Temps minimum entre eux annonces vocales</string>
<string name="settings_announcement_frequency_summary">Temps minimum entre deux annonces vocales</string>
<string name="settings_min_recording_distance">Distance min. entre 2 points</string>
<string name="settings_min_recording_distance_summary">Plus petite distance entre deux enregistrements de votre position</string>
@@ -214,8 +213,6 @@ limitations under the License.
<string name="settings_backup_to_sd_summary">Copier tous vos parcours et paramètres sur la carte SD</string>
<string name="settings_restore_from_sd">Restaurer</string>
<string name="settings_restore_from_sd_summary">Restaurer tous les parcours et paramètres depuis la carte SD</string>
<string name="settings_no_backup_while_recording">Sauvegarde impossible lors de l\'enregistrement d\'un parcours.</string>
<string name="restore_overwrites_warning">Restaurer une sauvegarde depuis la carte SD écrasera tous vos parcours et paramètres actuels.</string>
<string name="select_backup_to_restore">Choisissez la sauvegarde à restaurer</string>
+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>
+1 -1
View File
@@ -129,7 +129,7 @@ limitations under the License.
<string name="tracklist_all_tracks">Tutti i percorsi:</string>
<string name="tracklist_this_track">Questo percorso</string>
<string name="tracklist_share_track">Condividi con amici...</string>
<!-- <string name="tracklist_share_linkfusion">Un link alla mappa in «Le mie mappe» di Google</string> -->
<string name="tracklist_share_link">Un link alla mappa</string>
<string name="tracklist_share_gpx_file">Un file GPX</string>
<string name="tracklist_share_kml_file">Un file KML</string>
<string name="tracklist_clear_map">Cancella la mappa</string>
+14 -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>
@@ -287,4 +271,12 @@ limitations under the License.
<item>噴水</item>
<item>ウェイポイント</item>
</array>
<array name="sensor_type_options">
<item>なし</item>
<item>ANT+ センサー</item>
<item>SRM ANT+ ブリッジ</item>
<item>Zephyr Bluetooth</item>
</array>
</resources>
+61 -20
View File
@@ -35,6 +35,7 @@ limitations under the License.
<!-- 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 Docsへのトラック送信でエラーが発生しました.しばらく待って試して下さい.</string>
<string name="error_unable_to_start_recording">記録作成開始できません.もう一度試して下さい.</string>
@@ -50,11 +51,13 @@ limitations under the License.
<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">新しいマイマップをmap.google.comに作成しました.</string>
<string name="status_new_fusiontable_has_been_created">新しいGoogle Fusion Tableを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_enable_gps">ここをタップして「位置情報とセキュリティの設定」を開いて「GPS機能を使用」にチェックして下さい.バックボタンで戻ってください.</string>
<string name="status_mymap_info">新しいトラックが表示されるまでに数分かかることがあります.</string>
<string name="status_enable_gps">ここをタップして「位置情報とセキュリティの設定」を開いて「GPS機能を使用」にチェックを入れて下さい.バックボタンで戻ってください.</string>
<string name="status_approximate_location">ご注意: 携帯電話中継局とWi-Fiネットワークから大まかな位置を特定します.</string>
<string name="status_no_location">現在位置決定ができません.位置取得源を増やし(位置情報とセキュリティの設定 をご覧ください)、空が見えるようにして下さい.もう一度試して下さい.</string>
<string name="status_waypoint_inserted">ウェイポイントマーカーを挿入しました.</string>
@@ -62,14 +65,17 @@ limitations under the License.
<!-- Progress dialog -->
<string name="progress_title">お待ちください...</string>
<string name="progress_message">トラックをGoogleに送信しました.</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 Docsへの認証を行っています...</string>
<string name="progress_message_sending_docs">トラックをGoogle Docsに送信しています...</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 Tablesを生成しています...</string>
<string name="progress_message_creating_fusiontable">新しいFusionテーブルを生成しています...</string>
<string name="import_progress_message">GPSトラックをインポートしています.若干時間がかかります.</string>
<string name="write_progress_message">SDカードにデータを書き込んでいます.若干時間がかかります.</string>
<string name="progress_message_updating_track">トラック統計情報を更新しています...</string>
@@ -84,6 +90,10 @@ limitations under the License.
<string name="new_map_description">Android用My Tracksで作成</string>
<string name="fusiontable_link">Android用&lt;a href=\'http://mytracks.appspot.com\'&gt;My Tracks&lt;/a&gt;で作成しました.</string>
<!-- Text and links when uploading to Google My Maps -->
<string name="my_map_link">Android用&lt;a href=\'http://mytracks.appspot.com\'&gt;My Tracks&lt;/a&gt;で作成しました.</string>
<string name="new_map_title">新規マップ</string>
<!-- Formatting of track and marker descriptions -->
<string name="points">ポイント</string>
<string name="recorded_date">記録日</string>
@@ -113,10 +123,12 @@ limitations under the License.
<!-- TrackList -->
<string name="tracklist_show_track">表示</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 Docsへ送信</string>
<string name="tracklist_send_to_google">Googleへ送信...</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 Docsに送信</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>
@@ -124,21 +136,33 @@ limitations under the License.
<string name="tracklist_save_as_kml">KMLファイルの保存</string>
<string name="tracklist_save_as_csv">CVSファイルの保存</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_delete_all">全トラックの削除</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="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_all_tracks">全トラック:</string>
<string name="tracklist_this_track">このトラック</string>
<string name="tracklist_share_track">共有...</string>
<string name="tracklist_share_linkfusion">Google Fusion Tablesへのリンク</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>
<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">%3$s からGPXファイル %2$d件のうち %1$d件をインポートしました</string>
<string name="import_empty">%s ではGPXファイルがありません.SDカードを読み込めないかディレクトリにGPXファイルが無いかも知れません.</string>
<string name="import_error">ファイル %s のインポートエラー</string>
<!-- Waypoints list -->
<string name="waypointslist_btn_delete_all">全てのマーカーの削除</string>
@@ -191,7 +215,7 @@ limitations under the License.
<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_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>
@@ -232,7 +256,6 @@ limitations under the License.
<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="settings_no_backup_while_recording">トラック記録中はバックアップ操作はできません.</string>
<string name="restore_overwrites_warning">SDカードからの復元を実行すると、現在のトラックと設定は *全て上書き* されてしまいます.よろしいですか?</string>
<string name="select_backup_to_restore">復元するバックアップの選択</string>
@@ -243,6 +266,23 @@ limitations under the License.
<!-- 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>
@@ -333,7 +373,6 @@ limitations under the License.
<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 -->
@@ -351,8 +390,10 @@ limitations under the License.
<!-- Send to Google -->
<string name="sendtogoogle_title">送信...</string>
<string name="sendtogoogle_google_fusiontables">Googleマイマップ</string>
<string name="sendtogoogle_google_mymaps">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>
@@ -365,7 +406,7 @@ limitations under the License.
<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_create_dir_failed">SDカード上でディレクトリを作成できません.</string>
<string name="io_write_finished">SDカードへの書き込み終了.</string>
<string name="io_read_finished">SDカードからの読み込み終了.</string>
@@ -398,11 +439,11 @@ limitations under the License.
<string name="check_units_message">デフォルトの単位はメートルです.設定を変更しますか?</string>
<!-- Fake preference keys - never saved, but show options in the preferences screen -->
<!-- string name="method_bluetooth">Bluetooth</string --> <!-- duplicate -->
<string name="bluetooth_options">Bluetoothオプション</string>
<string name="bluetooth_pairing">ペアリング</string>
<string name="bluetooth_pairing_summary">ペアリングを行うには「Bluetooth設定」を開いて下さい</string>
<string name="sensor_bluetooth_options_key">bluetoothSensorsEnabled</string>
<string name="ant_options">ANTオプション</string>
<string name="sensor_options">センサーオプション</string>
<!-- Bluetooth Sensor -->
@@ -426,7 +467,7 @@ limitations under the License.
<!-- 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="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>
+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>
-2
View File
@@ -131,7 +131,6 @@ limitations under the License.
<string name="tracklist_all_tracks">Wszystkie trasy:</string>
<string name="tracklist_this_track">Ta trasa</string>
<string name="tracklist_share_track">Podziel się z przyjaciółmi...</string>
<!-- <string name="tracklist_share_linkfusion">Link do Moich Map Google</string> -->
<string name="tracklist_share_gpx_file">Plik GPX</string>
<string name="tracklist_share_kml_file">PLik KML</string>
<string name="tracklist_share_csv_file">Plik CSV</string>
@@ -218,7 +217,6 @@ limitations under the License.
<string name="settings_backup_to_sd_summary">Tworzy kopię zapasową wszystkich tras i ustawień i zapisuje je na karcie SD</string>
<string name="settings_restore_from_sd">Odtwórz z kopii</string>
<string name="settings_restore_from_sd_summary">Odtwarza wszystkie trasy i ustawienia z kopii zapasowej z karty SD</string>
<string name="settings_no_backup_while_recording">Nie można tworzyć/odtwarzać kopii zapasowej podczas rejestrowania trasy.</string>
<!-- Backups -->
<string name="restore_overwrites_warning">Odtworzenie z kopii zapasowej z karty SD zastąpi wszystkie bieżące trasy i ustawienia. Jesteś tego pewien?</string>
+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>
+30 -27
View File
@@ -18,9 +18,9 @@ limitations under the License.
<!-- Used by the Menu -->
<string name="start_recording">Gravar caminho</string>
<string name="stop_recording">Para gravação</string>
<string name="switch_to_sat">Modo do satélite"</string>
<string name="switch_to_map">Modo do mapa"</string>
<string name="mylocation">Minha Localização"</string>
<string name="switch_to_sat">Modo do satélite</string>
<string name="switch_to_map">Modo do mapa</string>
<string name="mylocation">Minha Localização</string>
<string name="list_tracks">Caminhos</string>
<string name="list_markers">Marcadores</string>
<string name="delete_all_tracks">Apagar todos os caminhos</string>
@@ -31,10 +31,10 @@ limitations under the License.
<string name="current_segment">Último segmento</string>
<!-- Error messages -->
<string name="error_no_location_manager">Gerenciador de localização não encontrado neste dispositivo!"</string>
<string name="error_no_gps_location_provider">"Provedor de posição de GPS não encontrado neste dispositivo."</string>
<string name="error_sending_to_fusiontables">Ocorreu um erro ao enviar seu caminho para o Google Fusion Tables. Por favor tente novamente mais tarde."</string>
<string name="error_sending_to_docs">Ocorreu um erro ao enviar seu caminho para o Google Docs. Por favor tente novamente mais tarde."</string>
<string name="error_no_location_manager">Gerenciador de localização não encontrado neste dispositivo!</string>
<string name="error_no_gps_location_provider">"Provedor de posição de GPS não encontrado neste dispositivo.</string>
<string name="error_sending_to_fusiontables">Ocorreu um erro ao enviar seu caminho para o Google Fusion Tables. Por favor tente novamente mais tarde.</string>
<string name="error_sending_to_docs">Ocorreu um erro ao enviar seu caminho para o Google Docs. Por favor tente novamente mais tarde.</string>
<string name="error_unable_to_start_recording">Impossível iniciar a gravação. Tente novamente.</string>
<string name="error_unable_to_stop_recording">Impossível interromper a gravação. Tente novamente.</string>
<string name="error_unable_to_read_file">Impossível ler do arquivo.</string>
@@ -52,7 +52,7 @@ limitations under the License.
<string name="status_tracks_have_been_uploaded">Seu caminho foi enviado para maps.google.com.</string>
<string name="status_tracks_have_been_uploaded_to_new_doc">Seu caminho foi enviado para uma nova planilha em docs.google.com.</string>
<string name="status_tracks_have_been_uploaded_to_docs">Seu caminho foi enviado para docs.google.com.</string>
<string name="status_enable_gps">"Por favor pressione aqui para ir aos ajustes de segurança e localização e verifique que o GPS esteja habilitado. Pressione o botão de voltar para retornar."</string>
<string name="status_enable_gps">"Por favor pressione aqui para ir aos ajustes de segurança e localização e verifique que o GPS esteja habilitado. Pressione o botão de voltar para retornar.</string>
<string name="status_approximate_location">Nota: Uma localização aproximada, determinada por torres de telefonia celular, está sendo mostrada.</string>
<string name="status_no_location">Sua localização não pôde ser determinada. Habilite fontes adicionais de localização (veja configurações de Segurança e Localização) e assegure-se de que o céu está visível.</string>
<string name="status_waypoint_inserted">Um marcador de ponto de passagem foi inserido.</string>
@@ -79,23 +79,24 @@ limitations under the License.
<string name="marker_will_be_permanently_deleted">O marcador será permanentemente apagado deste telefone.</string>
<!-- Text and links when uploading to Google My Maps -->
<string name="new_map_description">"Criado por My Tracks no Android."</string>
<string name="fusiontable_link">"Criado por &lt;a href='http://mytracks.appspot.com'&gt;My Tracks&lt;/a&gt; no Android."</string>
<string name="new_map_description">"Criado por My Tracks no Android.</string>
<string name="fusiontable_link">"Criado por &lt;a href='http://mytracks.appspot.com'&gt;My Tracks&lt;/a&gt; no Android.</string>
<!-- Formatting of track and marker descriptions -->
<string name="points">Pontos</string>
<string name="recorded_date">Gravado"</string>
<string name="category">"Tipo de atividade"</string>
<string name="waypoint_category">"Tipo de marcador"</string>
<string name="part">"(Parte %d)"</string>
<string name="recorded_date">Gravado</string>
<string name="category">"Tipo de atividade</string>
<string name="waypoint_category">"Tipo de marcador</string>
<string name="part">"(Parte %d)</string>
<!-- Used by the track recording service -->
<string name="recording_your_track">"Gravando seu caminho..."</string>
<string name="new_track">"Caminho %d"</string>
<string name="recording_your_track">"Gravando seu caminho...</string>
<string name="new_track">"Caminho %d</string>
<!-- Common -->
<string name="no">Não</string>
<string name="yes">Sim</string>
<!-- KEEP_PARENT name="ok" rev="7cbb95c69f35" -->
<string name="error">Erro</string>
<string name="success">Successo</string>
<string name="waypoint">Ponto de passagem</string>
@@ -122,22 +123,22 @@ limitations under the License.
<string name="tracklist_btn_send_all_to_fusiontables">Enviar para o Google Fusion Tables</string>
<string name="tracklist_btn_delete_all">Apagar todos os caminhos</string>
<string name="tracklist_pick_one">Escolha um caminho. Pressione&amp;segure para mais opções.</string>
<string name="tracklist_all_tracks">Todos os Caminhos:"</string>
<string name="tracklist_this_track">Este Caminho"</string>
<string name="tracklist_share_track">Compartilhar com amigos..."</string>
<string name="tracklist_share_linkfusion">Um link para a Google Fusion Table"</string>
<string name="tracklist_share_gpx_file">Um arquivo GPX"</string>
<string name="tracklist_share_kml_file">Um arquivo KML"</string>
<string name="tracklist_clear_map">"Limpar mapa"</string>
<string name="tracklist_all_tracks">Todos os Caminhos:</string>
<string name="tracklist_this_track">Este Caminho</string>
<string name="tracklist_share_track">Compartilhar com amigos...</string>
<string name="tracklist_share_link">Um link para a mapa</string>
<string name="tracklist_share_gpx_file">Um arquivo GPX</string>
<string name="tracklist_share_kml_file">Um arquivo KML</string>
<string name="tracklist_clear_map">Limpar mapa</string>
<!-- Waypoints list -->
<string name="waypointslist_btn_delete_all">Apagar todos os marcadores</string>
<string name="waypointslist_this_waypoint">Este Marcador</string>
<string name="waypointslist_delete_waypoint">Apagar</string>
<string name="waypointslist_edit_waypoint">Editar detalhes"</string>
<string name="waypointslist_show_waypoint">Mostrar no mapa"</string>
<string name="waypointslist_btn_insert_waypoint">Inserir ponto no caminho"</string>
<string name="waypointslist_btn_insert_statistics">Inserir estatísticas"</string>
<string name="waypointslist_edit_waypoint">Editar detalhes</string>
<string name="waypointslist_show_waypoint">Mostrar no mapa</string>
<string name="waypointslist_btn_insert_waypoint">Inserir ponto no caminho</string>
<string name="waypointslist_btn_insert_statistics">Inserir estatísticas</string>
<string name="waypointslist_pick_one">Escolha um marcador. Pressione&amp;segure para mais opções.</string>
<!-- MyTracks Details -->
@@ -157,6 +158,8 @@ limitations under the License.
<string name="settings_display">Exibição</string>
<string name="settings_recording">Gravação</string>
<string name="settings_sharing">Compartilhamento</string>
<string name="settings_not_available_summary">Não disponível na sua versão do Android</string>
<string name="settings_not_while_recording">Não disponível durante a gravação de uma trilha</string>
<string name="settings_announcement_frequency">Tempo entre anúncios</string>
<string name="settings_announcement_frequency_summary">Tempo mínimo entre dois anúncios de voz</string>
<string name="settings_min_recording_distance">Dist. mín. entre pontos</string>
+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>
-1
View File
@@ -131,7 +131,6 @@ limitations under the License.
<string name="tracklist_all_tracks">Alla spår:</string>
<string name="tracklist_this_track">Det här spåret</string>
<string name="tracklist_share_track">Dela med vänner...</string>
<!-- <string name="tracklist_share_linkfusion">En länk till Google Mina Kartor</string> -->
<string name="tracklist_share_gpx_file">En GPX-fil</string>
<string name="tracklist_share_kml_file">En KML-fil</string>
<string name="tracklist_share_csv_file">En CSV-fil</string>
+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>
-2
View File
@@ -132,7 +132,6 @@ limitations under the License.
<string name="tracklist_all_tracks">全部轨迹:</string>
<string name="tracklist_this_track">此轨迹</string>
<string name="tracklist_share_track">与朋友分享...</string>
<string name="tracklist_share_linkfusion">链接到 Google Fusion Table</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>
@@ -220,7 +219,6 @@ limitations under the License.
<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="settings_no_backup_while_recording">在记录轨迹时无法处理备份数据.</string>
<!-- Backups -->
<string name="restore_overwrites_warning">从 SD 存储卡恢复备份数据将覆盖掉你当前的所有轨迹和设置. 确定要继续吗?</string>
+5 -132
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,12 +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>
</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>
+5
View File
@@ -34,4 +34,9 @@ limitations under the License.
<string name="ant_sensor_type">ANT</string>
<string name="srm_ant_bridge_sensor_type">SRM_ANT_BRIDGE</string>
<string name="zephyr_sensor_type">ZEPHYR</string>
<!-- Send to Google URLs -->
<string name="sendtogoogle_google_fusiontables_url">google.com/fusiontables</string>
<string name="sendtogoogle_google_mymaps_url">maps.google.com</string>
<string name="sendtogoogle_google_docs_url">docs.google.com</string>
</resources>
+4
View File
@@ -36,6 +36,7 @@ limitations under the License.
<string name="send_stats_and_points_key">sendStatsAndPoints</string>
<string name="send_to_docs_key">sendToDocs</string>
<string name="send_to_my_maps_key">sendToMyMaps</string>
<string name="send_to_fusion_tables_key">sendToFusionTables</string>
<string name="sensor_type_key">sensorType</string>
<string name="share_url_only_key">shareUrlOnly</string>
<string name="split_frequency_key">splitFrequency</string>
@@ -49,4 +50,7 @@ limitations under the License.
<!-- Keys for non-persisted preferences - DO NOT TRANSLATE -->
<string name="backup_to_sd_key">backupToSd</string>
<string name="restore_from_sd_key">restoreFromSd</string>
<string name="reset_key">resetToDefaults</string>
<string name="sensor_options_key">sensorOptions</string>
<string name="ant_options_key">antOptions</string>
</resources>
+48 -6
View File
@@ -35,14 +35,17 @@ limitations under the License.
<!-- Error messages -->
<string name="error_no_location_manager">No location manager was found on this device!</string>
<string name="error_no_gps_location_provider">No GPS location provider was found on this device.</string>
<string name="error_sending_to_fusiontables">There was an error while sending your track to Google Fusion Tables. Please try again later.</string>
<string name="error_sending_to_docs">There was an error while sending your track to Google Docs. Please try again later.</string>
<string name="error_sending_to_mymap">There was an error while sending your track to Google My Map.</string>
<string name="error_sending_to_fusiontables">There was an error while sending your track to Google Fusion Tables.</string>
<string name="error_sending_to_docs">There was an error while sending your track to Google Docs.</string>
<string name="error_please_try_again_later">Please try again later.</string>
<string name="error_unable_to_start_recording">Unable to start recording. Try again.</string>
<string name="error_unable_to_stop_recording">Unable to stop recording. Try again.</string>
<string name="error_unable_to_read_file">Unable to read from file.</string>
<string name="error_invalid_gpx_format">File does not have a valid GPX format.</string>
<string name="error_generic">An error occurred. Please try again.</string>
<string name="error_track_does_not_exist">Track does not exist.</string>
<string name="error_operation_cancelled">The operation was cancelled.</string>
<string name="error_out_of_memory">This file is too big (must be less than 500 KB). Aborting.</string>
<string name="error_unable_to_insert_marker">Unable to insert marker. No location fix available.</string>
@@ -50,23 +53,30 @@ limitations under the License.
<string name="wait_for_fix">Waiting for a better GPS fix. Make sure the sky is visible.</string>
<string name="status_now_recording">Now recording a new track.</string>
<string name="status_stopped_recording">Stopped recording your track.</string>
<string name="status_new_mymap_has_been_created">A new Google My Map has been created at maps.google.com.</string>
<string name="status_new_fusiontable_has_been_created">A new Google Fusion table has been created at google.com/fusiontables.</string>
<string name="status_tracks_have_been_uploaded">Your track has been sent to maps.google.com.</string>
<string name="status_tracks_have_been_uploaded_to_new_doc">Your track has been sent to a new spreadsheet at docs.google.com.</string>
<string name="status_tracks_have_been_uploaded_to_docs">Your track has been sent to docs.google.com.</string>
<string name="status_mymap_info">It may take a few minutes before new tracks appear.</string>
<string name="status_enable_gps">Please tap here to go to Security and Location Settings and check \'enable GPS satellites\'. Press back button to return.</string>
<string name="status_approximate_location">Note: An approximate location as determined from cell towers and WIFI networks is shown.</string>
<string name="status_no_location">A location can currently not be determined. Enable more location sources (see Security and Location Settings) and make sure the sky is visible. Try again later.</string>
<string name="status_waypoint_inserted">A way point marker was inserted.</string>
<string name="status_statistics_inserted">A statistics marker was inserted.</string>
<string name="status_track_upload_status">Upload status:</string>
<!-- Progress dialog -->
<string name="progress_title">Please wait...</string>
<string name="progress_message">Sending your track to Google.</string>
<string name="progress_message_reading_track">Reading track...</string>
<string name="progress_message_preparing_track">Preparing track...</string>
<string name="progress_message_authenticating_fusiontables">Authenticating to Google Fusion Tables...</string>
<string name="progress_message_authenticating_mymaps">Authenticating to Google Maps...</string>
<string name="progress_message_authenticating_docs">Authenticating to Google Docs...</string>
<string name="progress_message_sending_docs">Sending track to Google Docs...</string>
<string name="progress_message_sending_mymaps">Sending track to Google Maps...</string>
<string name="progress_message_creating_map">Creating new My Map...</string>
<string name="progress_message_sending_fusiontables">Sending track to Fusion Tables...</string>
<string name="progress_message_creating_fusiontable">Creating new Fusion table...</string>
<string name="import_progress_message">Importing a GPS track. This may take a while.</string>
@@ -83,6 +93,10 @@ limitations under the License.
<string name="new_map_description">Created by My Tracks on Android.</string>
<string name="fusiontable_link">Created by &lt;a href=\'http://mytracks.appspot.com\'&gt;My Tracks&lt;/a&gt; on Android.</string>
<!-- Text and links when uploading to Google My Maps -->
<string name="my_map_link">Created by &lt;a href=\'http://mytracks.appspot.com\'&gt;My Tracks&lt;/a&gt; on Android.</string>
<string name="new_map_title">New map</string>
<!-- Formatting of track and marker descriptions -->
<string name="points">Points</string>
<string name="recorded_date">Recorded</string>
@@ -113,6 +127,8 @@ limitations under the License.
<!-- TrackList -->
<string name="tracklist_show_track">Show</string>
<string name="tracklist_send_to_mymaps">Send to Google My Maps</string>
<string name="tracklist_send_to_new_mymap">Send to New Google My Map</string>
<string name="tracklist_send_to_fusiontables">Send to Google Fusion Tables</string>
<string name="tracklist_send_to_new_fusiontable">Send to New Google Fusion Table</string>
<string name="tracklist_send_to_docs">Send to Google Docs</string>
@@ -125,6 +141,7 @@ limitations under the License.
<string name="tracklist_save_as_csv">Save a CSV file</string>
<string name="tracklist_save_as_tcx">Save a TCX file</string>
<string name="tracklist_btn_send_all_to_fusiontables">Send to Google Fusion Tables</string>
<string name="tracklist_btn_send_all_to_mymaps">Send to Google My Maps</string>
<string name="tracklist_btn_delete_all">Delete all</string>
<!-- Export All -->
<string name="tracklist_btn_export_all">Export all</string>
@@ -133,7 +150,7 @@ limitations under the License.
<string name="tracklist_all_tracks">All Tracks:</string>
<string name="tracklist_this_track">This Track</string>
<string name="tracklist_share_track">Share with Friends...</string>
<string name="tracklist_share_linkfusion">A link to Google Fusion Tables</string>
<string name="tracklist_share_link">A link to the map</string>
<string name="tracklist_share_gpx_file">A GPX file</string>
<string name="tracklist_share_kml_file">A KML file</string>
<string name="tracklist_share_csv_file">A CSV file</string>
@@ -180,6 +197,7 @@ limitations under the License.
<string name="settings_sharing">Sharing</string>
<string name="settings_not_available_summary">Not available in your version of Android</string>
<string name="settings_not_while_recording">Not available while recording a track</string>
<string name="settings_announcement_frequency">Announcement frequency</string>
<string name="settings_announcement_frequency_summary">Minimum time between two voice announcements</string>
@@ -222,6 +240,11 @@ limitations under the License.
<string name="settings_timestamp_track_name_summary_on">The default track name will be the date and time at the start of the track</string>
<string name="settings_timestamp_track_name_summary_off">Track names will have numbers which increment for each new track.</string>
<string name="settings_reset">Reset to defaults</string>
<string name="settings_reset_summary">Revert all your settings to the default values</string>
<string name="settings_reset_dialog_message">All your settings will be erased and reverted to the default values. Saved tracks will be preserved. Are you sure?</string>
<string name="settings_reset_done">All settings have been reverted to their defaults.</string>
<string name="pace_label">Pace</string>
<string name="eclair_required">Only supported in Android 2.0 or above</string>
@@ -229,7 +252,7 @@ limitations under the License.
<string name="settings_sensor_type_summary">The type of sensor to connect to</string>
<string name="settings_heart_rate_ant_sensor_id">Clear ANT heart rate sensor pairing</string>
<string name="settings_power_ant_sensor_id">Clear ANT power sensor pairing</string>
<string name="settings_srm_bridge_ant_sensor_id">Clear ANT srm bridge sensor pairing</string>
<string name="settings_srm_bridge_ant_sensor_id">Clear ANT SRM bridge sensor pairing</string>
<string name="settings_ant_not_paired">ANT sensor not paired</string>
<string name="settings_ant_paired">ANT sensor paired with: %d</string>
<string name="bluetooth_sensor_title">Bluetooth sensor</string>
@@ -243,7 +266,6 @@ limitations under the License.
<string name="settings_backup_to_sd_summary">Write a full copy of all your tracks and settings to the SD card</string>
<string name="settings_restore_from_sd">Restore now</string>
<string name="settings_restore_from_sd_summary">Restore all tracks and settings from the SD card</string>
<string name="settings_no_backup_while_recording">Cannot manipulate backups while recording a track.</string>
<string name="restore_overwrites_warning">Restoring a backup from the SD card will OVERWRITE all your current tracks and settings. Are you sure?</string>
<string name="select_backup_to_restore">Select the backup to restore</string>
@@ -254,6 +276,23 @@ limitations under the License.
<!-- MyTracksSky -->
<string name="mytracks_sky">GPS Satellites</string>
<!-- My Maps -->
<string name="select_map_message">Pick a map from your account:</string>
<string name="create_new_map">Create new map...</string>
<string name="map_list_title">Send to Google My Maps</string>
<string name="maps_list_loading">Loading maps...</string>
<string name="maps_list_failed">Your maps could not be loaded at this time!</string>
<string name="open_map">Select this Map</string>
<string name="edit_map_details">Edit Map Details</string>
<string name="share_track">Share Track</string>
<string name="delete_map">Delete Map from your Account</string>
<string name="map_title">Map Title:</string>
<string name="map_description">Map Description:</string>
<string name="map_searchable_edit">Make this map and its contents show up in search results</string>
<string name="map_not_searchable_edit">Do not let this map or its contents show up in search results, though they may still be viewed be others through the direct URL</string>
<string name="map_searchable">This map and its contents will show in search results</string>
<string name="map_not_searchable">Neither this map nor its contents will show in search results, but they may still be viewed by others through a direct link</string>
<!-- Sharing -->
<string name="share_map">Share map with friends</string>
<string name="share_map_subject">I would like to share a track with you</string>
@@ -264,7 +303,6 @@ limitations under the License.
<string name="send_track_body_format">I think you might be interested in this track.
To view this track use Google Earth or other mapping software.</string>
<string name="share_track">Share track with friends</string>
<!-- Visibility -->
<string name="public_map">Public</string>
@@ -377,8 +415,11 @@ limitations under the License.
<!-- Send to Google -->
<string name="sendtogoogle_title">Send to...</string>
<string name="sendtogoogle_google_fusiontables">Google Fusion Tables</string>
<string name="sendtogoogle_google_mymaps">Google My Maps</string>
<string name="sendtogoogle_google_docs">Google Docs</string>
<string name="sendtogoogle_send_now">Send now</string>
<string name="sendtogoogle_create_new_map">Create a new map</string>
<string name="sendtogoogle_pick_existing_map">Pick an existing map</string>
<string name="sendtogoogle_send_stats">Send track statistics</string>
<string name="sendtogoogle_send_stats_and_points">Send statistics and points</string>
@@ -430,6 +471,7 @@ limitations under the License.
<string name="bluetooth_pairing">Device pairing</string>
<string name="bluetooth_pairing_summary">Open Android\'s bluetooth settings to pair a device</string>
<string name="sensor_bluetooth_options_key">bluetoothSensorsEnabled</string>
<string name="ant_options">ANT options</string>
<string name="sensor_options">Sensor Options</string>
<!-- Bluetooth Sensor -->
+24 -14
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
@@ -102,7 +102,8 @@ limitations under the License.
</PreferenceScreen>
<!-- Sensors -->
<PreferenceScreen android:title="@string/sensor_options">
<PreferenceScreen android:title="@string/sensor_options"
android:key="@string/sensor_options_key">
<ListPreference android:key="@string/sensor_type_key"
android:title="@string/settings_sensor_type"
android:summary="@string/settings_sensor_type_summary"
@@ -122,20 +123,22 @@ limitations under the License.
android:summary="@string/bluetooth_pairing_summary"
android:persistent="false" />
</PreferenceCategory>
<com.google.android.apps.mytracks.AntPreference
android:key="@string/ant_heart_rate_sensor_id_key"
android:title="@string/settings_heart_rate_ant_sensor_id"/>
<PreferenceCategory android:title="@string/ant_options"
android:key="@string/ant_options_key">
<com.google.android.apps.mytracks.AntPreference
android:key="@string/ant_heart_rate_sensor_id_key"
android:title="@string/settings_heart_rate_ant_sensor_id"/>
<!--
<com.google.android.apps.mytracks.AntPreference
android:key="@string/ant_power_sensor_id_key"
android:title="@string/settings_power_ant_sensor_id"/>
<com.google.android.apps.mytracks.AntPreference
android:key="@string/ant_power_sensor_id_key"
android:title="@string/settings_power_ant_sensor_id"/>
-->
<com.google.android.apps.mytracks.AntPreference
android:key="@string/ant_srm_bridge_sensor_id_key"
android:title="@string/settings_srm_bridge_ant_sensor_id"/>
<com.google.android.apps.mytracks.AntPreference
android:key="@string/ant_srm_bridge_sensor_id_key"
android:title="@string/settings_srm_bridge_ant_sensor_id"/>
</PreferenceCategory>
</PreferenceScreen>
<!-- Sharing settings -->
@@ -170,4 +173,11 @@ limitations under the License.
android:persistent="false" />
</PreferenceCategory>
</PreferenceScreen>
<!-- Reset to defaults -->
<Preference
android:title="@string/settings_reset"
android:key="@string/reset_key"
android:summary="@string/settings_reset_summary"
android:persistent="false" />
</PreferenceScreen>
+1 -1
View File
@@ -45,7 +45,7 @@ public class AntInterface {
public static final String TAG = "ANTInterface";
/** Enable debug logging. */
public static boolean DEBUG = true;
public static boolean DEBUG = false;
/** Search string to find ANT Radio Proxy Service in the Android Marketplace */
private static final String MARKET_SEARCH_TEXT_DEFAULT = "ANT Radio Service Dynastream Innovations Inc";
@@ -59,7 +59,7 @@ public class AccountChooser {
public void chooseAccount(final Activity activity,
final AccountHandler handler) {
final Account[] accounts = AccountManager.get(activity)
.getAccountsByType(MyTracksConstants.ACCOUNT_TYPE);
.getAccountsByType(Constants.ACCOUNT_TYPE);
if (accounts.length < 1) {
alertNoAccounts(activity, handler);
return;
@@ -76,7 +76,7 @@ public class AccountChooser {
}
// Let the user choose.
Log.e(MyTracksConstants.TAG, "Multiple matching accounts found.");
Log.e(Constants.TAG, "Multiple matching accounts found.");
final AlertDialog.Builder builder = new AlertDialog.Builder(activity);
builder.setTitle(R.string.choose_account_title);
builder.setCancelable(false);
@@ -112,7 +112,7 @@ public class AccountChooser {
*/
private void alertNoAccounts(final Activity activity,
final AccountHandler handler) {
Log.e(MyTracksConstants.TAG, "No matching accounts found.");
Log.e(Constants.TAG, "No matching accounts found.");
final AlertDialog.Builder builder = new AlertDialog.Builder(activity);
builder.setTitle(R.string.no_account_found_title);
builder.setMessage(R.string.no_account_found);
@@ -40,7 +40,7 @@ public class AggregatedStatsActivity extends Activity implements
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
String key) {
Log.d(MyTracksConstants.TAG, "StatsActivity: onSharedPreferences changed "
Log.d(Constants.TAG, "StatsActivity: onSharedPreferences changed "
+ key);
if (key != null) {
if (key.equals(R.string.metric_units_key)) {
@@ -67,7 +67,7 @@ public class AggregatedStatsActivity extends Activity implements
sv.setScrollBarStyle(ScrollView.SCROLLBARS_OUTSIDE_INSET);
SharedPreferences preferences = getSharedPreferences(
MyTracksSettings.SETTINGS_NAME, 0);
Constants.SETTINGS_NAME, 0);
if (preferences != null) {
metricUnits = preferences.getBoolean(getString(R.string.metric_units_key), true);
preferences.registerOnSharedPreferenceChangeListener(this);
@@ -16,8 +16,8 @@
package com.google.android.apps.mytracks;
import static android.content.Intent.ACTION_BOOT_COMPLETED;
import static com.google.android.apps.mytracks.MyTracksConstants.RESUME_TRACK_EXTRA_NAME;
import static com.google.android.apps.mytracks.MyTracksConstants.TAG;
import static com.google.android.apps.mytracks.Constants.RESUME_TRACK_EXTRA_NAME;
import static com.google.android.apps.mytracks.Constants.TAG;
import com.google.android.apps.mytracks.services.TrackRecordingService;
@@ -41,17 +41,17 @@ import android.util.Log;
*
* @author Bartlomiej Niechwiej
*/
public class MyTracksReceiver extends BroadcastReceiver {
public class BootReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "MyTracksReceiver.onReceive: " + intent.getAction());
Log.d(TAG, "BootReceiver.onReceive: " + intent.getAction());
if (ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
Intent startIntent = new Intent(context, TrackRecordingService.class);
startIntent.putExtra(RESUME_TRACK_EXTRA_NAME, true);
context.startService(startIntent);
} else {
Log.w(TAG, "MyTracksReceiver: unsupported action");
Log.w(TAG, "BootReceiver: unsupported action");
}
}
}
@@ -15,31 +15,26 @@
*/
package com.google.android.apps.mytracks;
import static com.google.android.apps.mytracks.Constants.TAG;
import com.google.android.apps.mytracks.ChartView.Mode;
import com.google.android.apps.mytracks.TrackDataHub.ListenerDataType;
import com.google.android.apps.mytracks.content.MyTracksLocation;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.content.Sensor;
import com.google.android.apps.mytracks.content.Track;
import com.google.android.apps.mytracks.content.TrackPointsColumns;
import com.google.android.apps.mytracks.content.Waypoint;
import com.google.android.apps.mytracks.content.WaypointsColumns;
import com.google.android.apps.mytracks.content.Sensor.SensorDataSet;
import com.google.android.apps.mytracks.services.StatusAnnouncerFactory;
import com.google.android.apps.mytracks.content.Track;
import com.google.android.apps.mytracks.content.Waypoint;
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;
import com.google.android.apps.mytracks.util.MyTracksUtils;
import com.google.android.apps.mytracks.util.LocationUtils;
import com.google.android.apps.mytracks.util.UnitConversions;
import com.google.android.maps.mytracks.R;
import android.app.Activity;
import android.content.SharedPreferences;
import android.database.ContentObserver;
import android.database.Cursor;
import android.location.Location;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
@@ -51,53 +46,34 @@ import android.widget.LinearLayout;
import android.widget.ZoomControls;
import java.util.ArrayList;
import java.util.EnumSet;
/**
* An activity that displays a chart from the track point provider.
*
* @author Sandor Dornbush
* @author Rodrigo Damazio
*/
public class ChartActivity extends Activity implements
SharedPreferences.OnSharedPreferenceChangeListener {
private final static int BUFFER_SIZE = 1024;
private double profileLength = 0;
private boolean metricUnits = true;
private boolean reportSpeed = true;
/**
* The track id that is displayed.
*/
private long selectedTrackId = -1;
/**
* Id of the last location that was seen when reading tracks from the
* provider. This is used to determine which locations are new compared to the
* last time the chart was updated.
*/
private long lastSeenLocationId = -1;
private long startTime = -1;
private Location lastLocation;
/**
* The id of the track currently being recorded.
*/
private long recordingTrackId = -1;
public class ChartActivity extends Activity implements TrackDataListener {
private final DoubleBuffer elevationBuffer =
new DoubleBuffer(MyTracksConstants.ELEVATION_SMOOTHING_FACTOR);
new DoubleBuffer(Constants.ELEVATION_SMOOTHING_FACTOR);
private final DoubleBuffer speedBuffer =
new DoubleBuffer(MyTracksConstants.SPEED_SMOOTHING_FACTOR);
new DoubleBuffer(Constants.SPEED_SMOOTHING_FACTOR);
private final ArrayList<double[]> pendingPoints = new ArrayList<double[]>();
private TrackDataHub dataHub;
// Stats gathered from received data.
private double profileLength = 0;
private long startTime = -1;
private Location lastLocation;
private double trackMaxSpeed;
// Modes of operation
private Mode mode = Mode.BY_DISTANCE;
/**
* Utilities to deal with the database.
*/
private MyTracksProviderUtils providerUtils;
private boolean metricUnits;
private boolean reportSpeed;
/*
* UI elements:
@@ -107,9 +83,6 @@ public class ChartActivity extends Activity implements
private LinearLayout busyPane;
private ZoomControls zoomControls;
/** Handler for callbacks to the UI thread */
private final Handler uiHandler = new Handler();
/**
* A runnable that can be posted to the UI thread. It will remove the spinner
* (if any), enable/disable zoom controls and orange pointer as appropriate
@@ -121,89 +94,17 @@ public class ChartActivity extends Activity implements
busyPane.setVisibility(View.GONE);
zoomControls.setIsZoomInEnabled(chartView.canZoomIn());
zoomControls.setIsZoomOutEnabled(chartView.canZoomOut());
chartView.setShowPointer(selectedTrackIsRecording());
chartView.setShowPointer(dataHub.isRecordingSelected());
chartView.invalidate();
}
};
/**
* A runnable that can be posted to the UI thread. It will show the spinner.
*/
private final Runnable showSpinner = new Runnable() {
@Override
public void run() {
busyPane.setVisibility(View.VISIBLE);
}
};
/**
* An observer for the tracks provider. Will listen to new track points being
* added and update the chart if necessary.
*/
private ContentObserver observer;
/**
* An observer for the waypoints provider. Will listen to new way points being
* added and update the chart if necessary.
*/
private ContentObserver waypointObserver;
/**
* A thread with a looper. Post to updateTrackHandler to execute Runnables on
* this thread.
*/
private final HandlerThread updateTrackThread =
new HandlerThread("updateTrackThread");
/** Handler for updateTrackThread */
private Handler updateTrackHandler;
/**
* A runnable that updates the profile from the provider.
*/
private final Runnable updateTrackRunnable = new Runnable() {
@Override
public void run() {
readNewTrackPoints();
}
};
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
String key) {
if (key != null) {
if (key.equals(getString(R.string.selected_track_key))) {
selectedTrackId =
sharedPreferences.getLong(getString(R.string.selected_track_key),
-1);
readProfileAsync();
} else if (key.equals(getString(R.string.metric_units_key))) {
metricUnits =
sharedPreferences.getBoolean(getString(R.string.metric_units_key),
true);
chartView.setMetricUnits(metricUnits);
readProfileAsync();
} else if (key.equals(getString(R.string.report_speed_key))) {
reportSpeed =
sharedPreferences.getBoolean(getString(R.string.report_speed_key),
true);
chartView.setReportSpeed(reportSpeed, this);
readProfileAsync();
} else if (key.equals(getString(R.string.recording_track_key))) {
recordingTrackId =
sharedPreferences.getLong(getString(R.string.recording_track_key),
-1);
runOnUiThread(updateChart);
}
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
Log.w(MyTracksConstants.TAG, "ChartActivity.onCreate");
Log.w(TAG, "ChartActivity.onCreate");
super.onCreate(savedInstanceState);
MyTracks.getInstance().setChartActivity(this);
providerUtils = MyTracksProviderUtils.Factory.get(this);
dataHub = MyTracks.getInstance().getDataHub();
// The volume we want to control is the Text-To-Speech volume
int volumeStream =
@@ -219,22 +120,6 @@ public class ChartActivity extends Activity implements
new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT);
layout.addView(chartView, params);
SharedPreferences preferences =
getSharedPreferences(MyTracksSettings.SETTINGS_NAME, 0);
if (preferences != null) {
selectedTrackId =
preferences.getLong(getString(R.string.selected_track_key), -1);
recordingTrackId =
preferences.getLong(getString(R.string.recording_track_key), -1);
metricUnits = preferences.getBoolean(getString(R.string.metric_units_key),
true);
chartView.setMetricUnits(metricUnits);
reportSpeed = preferences.getBoolean(getString(R.string.report_speed_key),
true);
chartView.setReportSpeed(reportSpeed, this);
preferences.registerOnSharedPreferenceChangeListener(this);
}
busyPane = (LinearLayout) findViewById(R.id.elevation_busypane);
zoomControls = (ZoomControls) findViewById(R.id.elevation_zoom);
zoomControls.setOnZoomInClickListener(new View.OnClickListener() {
@@ -249,97 +134,25 @@ public class ChartActivity extends Activity implements
zoomOut();
}
});
updateTrackThread.start();
updateTrackHandler = new Handler(updateTrackThread.getLooper());
// Register observer for the track point provider:
Handler contentHandler = new Handler();
observer = new ContentObserver(contentHandler) {
@Override
public void onChange(boolean selfChange) {
Log.d(MyTracksConstants.TAG, "ChartActivity: ContentObserver.onChange");
// Check for any new locations and append them to the currently
// recording track.
if (recordingTrackId < 0) {
// No track is being recorded. We should not be here.
return;
}
if (selectedTrackId != recordingTrackId) {
// No track, or one other than the recording track is selected, don't
// bother.
return;
}
// Update can potentially be lengthy, put it in its own thread:
updateTrackHandler.post(updateTrackRunnable);
super.onChange(selfChange);
}
};
waypointObserver = new ContentObserver(contentHandler) {
@Override
public void onChange(boolean selfChange) {
Log.d(MyTracksConstants.TAG,
"MyTracksMap: ContentObserver.onChange waypoints");
if (selectedTrackId < 0) {
return;
}
Thread t = new Thread() {
@Override
public void run() {
readWaypoints();
ChartActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
chartView.invalidate();
}
});
}
};
t.start();
super.onChange(selfChange);
}
};
readProfileAsync();
}
@Override
protected void onPause() {
super.onPause();
unregisterContentObservers();
protected void onStart() {
super.onStart();
dataHub.registerTrackDataListener(this, EnumSet.of(
ListenerDataType.SELECTED_TRACK_CHANGED,
ListenerDataType.POINT_UPDATES,
ListenerDataType.SAMPLED_OUT_POINT_UPDATES,
ListenerDataType.WAYPOINT_UPDATES,
ListenerDataType.DISPLAY_PREFERENCES));
}
@Override
protected void onResume() {
super.onResume();
// Make sure any updates that might have happened are propagated to this
// activity:
observer.onChange(false);
waypointObserver.onChange(false);
registerContentObservers();
}
protected void onStop() {
dataHub.unregisterTrackDataListener(this);
/**
* Register the content observer for the map overlay.
*/
private void registerContentObservers() {
getContentResolver().registerContentObserver(TrackPointsColumns.CONTENT_URI,
false/* notifyForDescendents */, observer);
getContentResolver().registerContentObserver(WaypointsColumns.CONTENT_URI,
false/* notifyForDescendents */, waypointObserver);
}
/**
* Unregister the content observer for the map overlay.
*/
private void unregisterContentObservers() {
getContentResolver().unregisterContentObserver(observer);
getContentResolver().unregisterContentObserver(waypointObserver);
}
private boolean selectedTrackIsRecording() {
return selectedTrackId == recordingTrackId;
super.onStop();
}
private void zoomIn() {
@@ -358,7 +171,7 @@ public class ChartActivity extends Activity implements
if (this.mode != newMode) {
this.mode = newMode;
chartView.setMode(this.mode);
readProfileAsync();
dataHub.reloadDataForListener(this);
}
}
@@ -375,39 +188,11 @@ public class ChartActivity extends Activity implements
return chartView.getChartValueSeries(index).isEnabled();
}
private void readWaypoints() {
if (selectedTrackId < 0) {
return;
}
Cursor cursor = null;
chartView.clearWaypoints();
try {
// We will silently drop extra waypoints to make the app responsive.
cursor =
providerUtils.getWaypointsCursor(selectedTrackId, 0,
MyTracksConstants.MAX_DISPLAYED_TRACK_POINTS);
if (cursor != null) {
if (cursor.moveToFirst()) {
do {
Waypoint wpt = providerUtils.createWaypoint(cursor);
chartView.addWaypoint(wpt);
} while (cursor.moveToNext());
}
}
} catch (RuntimeException e) {
Log.w(MyTracksConstants.TAG, "Caught an unexpected exception.", e);
} finally {
if (cursor != null) {
cursor.close();
}
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
chartSettingsMenuItem =
menu.add(0, MyTracksConstants.MENU_CHART_SETTINGS, 0,
menu.add(0, Constants.MENU_CHART_SETTINGS, 0,
R.string.chart_settings);
chartSettingsMenuItem.setIcon(R.drawable.chart_settings);
return true;
@@ -416,7 +201,7 @@ public class ChartActivity extends Activity implements
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case MyTracksConstants.MENU_CHART_SETTINGS:
case Constants.MENU_CHART_SETTINGS:
MyTracks.getInstance().getDialogManager().showDialogSafely(
DialogManager.DIALOG_CHART_SETTINGS);
return true;
@@ -438,43 +223,41 @@ public class ChartActivity extends Activity implements
* This must be called in order for each point.
*
* @param location the location to get data for (this method takes ownership of that location)
* @param track the track to get data from
* @param result the resulting point to fill out
* @return the previous location, now available for reuse
*/
private Location getDataPoint(Location location, Track track, double[] result) {
private void fillDataPoint(Location location, double result[]) {
double timeOrDistance = Double.NaN,
elevation = Double.NaN,
speed = Double.NaN,
power = Double.NaN,
cadence = Double.NaN,
heartRate = Double.NaN;
if (location instanceof MyTracksLocation &&
((MyTracksLocation) location).getSensorDataSet() != null) {
SensorDataSet sensorData = ((MyTracksLocation) location).getSensorDataSet();
if (sensorData.hasPower()
&& sensorData.getPower().getState() == Sensor.SensorState.SENDING
&& sensorData.getPower().hasValue()) {
result[3] = sensorData.getPower().getValue();
} else {
result[3] = Double.NaN;
power = sensorData.getPower().getValue();
}
if (sensorData.hasCadence()
&& sensorData.getCadence().getState() == Sensor.SensorState.SENDING
&& sensorData.getCadence().hasValue()) {
result[4] = sensorData.getCadence().getValue();
} else {
result[4] = Double.NaN;
cadence = sensorData.getCadence().getValue();
}
if (sensorData.hasHeartRate()
&& sensorData.getHeartRate().getState() == Sensor.SensorState.SENDING
&& sensorData.getHeartRate().hasValue()) {
result[5] = sensorData.getHeartRate().getValue();
} else {
result[5] = Double.NaN;
heartRate = sensorData.getHeartRate().getValue();
}
} else {
result[3] = Double.NaN;
result[4] = Double.NaN;
result[5] = Double.NaN;
}
// TODO: Account for segment splits?
switch (mode) {
case BY_DISTANCE:
result[0] = profileLength;
timeOrDistance = profileLength;
if (lastLocation != null) {
double d = lastLocation.distanceTo(location);
if (metricUnits) {
@@ -489,16 +272,16 @@ public class ChartActivity extends Activity implements
// Base case
startTime = location.getTime();
}
result[0] = (location.getTime() - startTime);
timeOrDistance = (location.getTime() - startTime);
break;
default:
Log.w(MyTracksConstants.TAG, "ChartActivity unknown mode: " + mode);
Log.w(TAG, "ChartActivity unknown mode: " + mode);
}
elevationBuffer.setNext(metricUnits
? location.getAltitude()
: location.getAltitude() * UnitConversions.M_TO_FT);
result[1] = elevationBuffer.getAverage();
elevation = elevationBuffer.getAverage();
if (lastLocation == null) {
if (Math.abs(location.getSpeed() - 128) > 1) {
@@ -507,151 +290,134 @@ public class ChartActivity extends Activity implements
} else if (TripStatisticsBuilder.isValidSpeed(
location.getTime(), location.getSpeed(), lastLocation.getTime(),
lastLocation.getSpeed(), speedBuffer)
&& (location.getSpeed() <= track.getStatistics().getMaxSpeed())) {
&& (location.getSpeed() <= trackMaxSpeed)) {
speedBuffer.setNext(location.getSpeed());
}
result[2] = speedBuffer.getAverage() * 3.6;
speed = speedBuffer.getAverage() * 3.6;
if (!metricUnits) {
result[2] *= UnitConversions.KM_TO_MI;
speed *= UnitConversions.KM_TO_MI;
}
if (!reportSpeed && (result[2] != 0)) {
// Format as hours per unit
result[2] = (60.0 / result[2]);
if (!reportSpeed) {
if (speed != 0) {
// Format as hours per unit
speed = (60.0 / speed);
} else {
speed = Double.NaN;
}
}
Location oldLastLocation = lastLocation;
// Keep a copy so the location can be reused.
lastLocation = location;
if (oldLastLocation == null) {
// No previous location, but return a blank one for reuse
return new MyTracksLocation("");
if (result != null) {
result[0] = timeOrDistance;
result[1] = elevation;
result[2] = speed;
result[3] = power;
result[4] = cadence;
result[5] = heartRate;
}
return oldLastLocation;
}
/**
* Sets the chart data points reading from the provider. This is non-blocking.
*/
private void readProfileAsync() {
chartView.reset();
updateTrackHandler.post(new Runnable() {
@Override
public void onProviderStateChange(ProviderState state) {
// We don't care.
}
@Override
public void onCurrentLocationChanged(Location loc) {
// We don't care.
}
@Override
public void onCurrentHeadingChanged(double heading) {
// We don't care.
}
@Override
public void onSelectedTrackChanged(Track track, boolean isRecording) {
Log.e(TAG, "Visible", new Throwable());
runOnUiThread(new Runnable() {
@Override
public void run() {
runOnUiThread(showSpinner);
readProfile();
readWaypoints();
runOnUiThread(updateChart);
busyPane.setVisibility(View.VISIBLE);
}
});
}
/**
* Reads the track profile from the provider. This is a blocking function and
* should not be run from the UI thread.
*/
private void readProfile() {
@Override
public void onTrackUpdated(Track track) {
trackMaxSpeed = track.getStatistics().getMaxSpeed();
}
@Override
public void clearTrackPoints() {
profileLength = 0;
lastLocation = null;
startTime = -1;
if (selectedTrackId < 0) {
return;
}
Track track = providerUtils.getTrack(selectedTrackId);
if (track == null) {
return;
}
lastSeenLocationId = track.getStartId();
final ArrayList<double[]> theData = readPointsToList(track);
runOnUiThread(new Runnable() {
public void run() {
chartView.setDataPoints(theData);
}
});
elevationBuffer.reset();
speedBuffer.reset();
chartView.reset();
pendingPoints.clear();
}
/**
* Read all new track points.
*/
private void readNewTrackPoints() {
Log.i(MyTracksConstants.TAG, "MyTracks: Updating chart last seen: " + lastSeenLocationId);
Track track = providerUtils.getTrack(recordingTrackId);
if (track == null) {
Log.w(MyTracksConstants.TAG, "MyTracks: track not found");
return;
@Override
public void onNewTrackPoint(Location loc) {
if (LocationUtils.isValidLocation(loc)) {
double[] point = new double[6];
fillDataPoint(loc, point);
pendingPoints.add(point);
}
chartView.addDataPoints(readPointsToList(track));
uiHandler.post(new Runnable() {
public void run() {
chartView.invalidate();
}
});
Log.i(MyTracksConstants.TAG, "MyTracks: Updated chart last seen: " + lastSeenLocationId);
}
/**
* Get the frequency at which points should be displayed.
* Limit the number of chart readings. Ideally we would want around 1024.
* @param track The track which will be displayed.
* @return The inverse of the frequency of points to be displayed.
*/
private int getSamplingFrequency(Track track) {
long totalLocations = track.getStopId() - track.getStartId();
return Math.max(1, (int) (totalLocations / 1024.0));
@Override
public void onSampledOutTrackPoint(Location loc) {
// Still account for the point in the smoothing buffers.
fillDataPoint(loc, null);
}
private Cursor getLocationsCursor(long lastLocationRead) {
return providerUtils.getLocationsCursor(selectedTrackId, lastLocationRead, BUFFER_SIZE, false);
@Override
public void onSegmentSplit() {
// Do nothing.
}
/**
* Read all of the points to a list.
* @param track The track which will be displayed.
* @return
*/
private ArrayList<double[]> readPointsToList(Track track) {
Cursor cursor = null;
long lastLocationRead = lastSeenLocationId;
int points = 0;
int chartSamplingFrequency = getSamplingFrequency(track);
ArrayList<double[]> result = new ArrayList<double[]>();
// Need two locations so we can keep track of the last location.
Location location = new MyTracksLocation("");
try {
while (lastSeenLocationId < track.getStopId()) {
cursor = getLocationsCursor(lastLocationRead);
if (cursor != null) {
elevationBuffer.reset();
speedBuffer.reset();
if (cursor.moveToFirst()) {
final int idColumnIdx = cursor.getColumnIndexOrThrow(TrackPointsColumns._ID);
while (cursor.moveToNext()) {
points++;
providerUtils.fillLocation(cursor, location);
if (MyTracksUtils.isValidLocation(location)) {
lastLocationRead = lastSeenLocationId =
cursor.getLong(idColumnIdx);
// TODO Can we be smarter about choosing 3 or 6 entries?
double[] point = new double[6];
location = getDataPoint(location, track, point);
if (points % chartSamplingFrequency == 0) {
result.add(point);
}
}
}
} else {
lastLocationRead += BUFFER_SIZE;
}
} else {
lastLocationRead += BUFFER_SIZE;
}
cursor.close();
cursor = null;
}
return result;
} finally {
if (cursor != null) {
cursor.close();
}
}
@Override
public void onNewTrackPointsDone() {
chartView.addDataPoints(pendingPoints);
pendingPoints.clear();
runOnUiThread(updateChart);
}
@Override
public void clearWaypoints() {
chartView.clearWaypoints();
}
@Override
public void onNewWaypoint(Waypoint wpt) {
chartView.addWaypoint(wpt);
}
@Override
public void onNewWaypointsDone() {
runOnUiThread(updateChart);
}
@Override
public boolean onUnitsChanged(boolean metric) {
this.metricUnits = metric;
chartView.setMetricUnits(metric);
return true; // Reload data
}
@Override
public boolean onReportSpeedChanged(boolean reportSpeed) {
this.reportSpeed = reportSpeed;
chartView.setReportSpeed(reportSpeed, this);
return true; // Reload data
}
}
@@ -527,8 +527,8 @@ public class ChartView extends View {
}
if (nearestWaypoint != null && dmin < 100) {
Intent intent =
new Intent(getContext(), MyTracksWaypointDetails.class);
intent.putExtra("waypointid", nearestWaypoint.getId());
new Intent(getContext(), WaypointDetails.class);
intent.putExtra(WaypointDetails.WAYPOINT_ID_EXTRA, nearestWaypoint.getId());
getContext().startActivity(intent);
return true;
}
@@ -728,7 +728,7 @@ public class ChartView extends View {
}
}
float density = getContext().getResources().getDisplayMetrics().density;
// TODO: This should be function of the number of variables displayed.
maxLength = Math.max(maxLength, 1);
leftBorder = (int) (density * (4 + 8 * maxLength));
effectiveWidth = w - leftBorder - RIGHT_BORDER;
bottomBorder = (int) (density * BOTTOM_BORDER);
@@ -78,7 +78,7 @@ class CheckUnits {
private static void accept(Context context, SharedPreferences preferences) {
recordCheckPerformed(preferences);
Intent startIntent = new Intent(context, MyTracksSettings.class);
Intent startIntent = new Intent(context, SettingsActivity.class);
context.startActivity(startIntent);
}
@@ -20,18 +20,13 @@ package com.google.android.apps.mytracks;
*
* @author Leif Hendrik Wilden
*/
public abstract class MyTracksConstants {
public abstract class Constants {
/**
* Should be used by all log statements
*/
public static final String TAG = "MyTracks";
/**
* Name of the gps location provider:
*/
public static final String GPS_PROVIDER = "gps";
/**
* Name of the top-level directory inside the SD card where our files will
* be read from/written to.
@@ -50,26 +45,26 @@ public abstract class MyTracksConstants {
public static final int FEATURE_DETAILS = 5;
public static final int START_RECORDING = 6;
public static final int STOP_RECORDING = 7;
public static final int AUTHENTICATE_TO_DOCLIST = 8;
public static final int AUTHENTICATE_TO_TRIX = 9;
public static final int SEND_TO_DOCS = 10;
public static final int DELETE_TRACK = 11;
public static final int SEND_TO_GOOGLE = 12;
public static final int SEND_TO_GOOGLE_DIALOG = 13;
public static final int SHARE_LINK = 14;
public static final int SHARE_GPX_FILE = 15;
public static final int SHARE_KML_FILE = 16;
public static final int SHARE_CSV_FILE = 17;
public static final int SHARE_TCX_FILE = 18;
public static final int EDIT_DETAILS = 19;
public static final int SAVE_GPX_FILE = 20;
public static final int SAVE_KML_FILE = 21;
public static final int SAVE_CSV_FILE = 22;
public static final int SAVE_TCX_FILE = 23;
public static final int CLEAR_MAP = 24;
public static final int SHOW_WAYPOINT = 25;
public static final int EDIT_WAYPOINT = 26;
public static final int WELCOME = 27;
public static final int AUTHENTICATE_TO_MY_MAPS = 8;
public static final int AUTHENTICATE_TO_FUSION_TABLES = 9;
public static final int AUTHENTICATE_TO_DOCLIST = 10;
public static final int AUTHENTICATE_TO_TRIX = 11;
public static final int DELETE_TRACK = 13;
public static final int SEND_TO_GOOGLE_DIALOG = 14;
public static final int SHARE_LINK = 15;
public static final int SHARE_GPX_FILE = 16;
public static final int SHARE_KML_FILE = 17;
public static final int SHARE_CSV_FILE = 18;
public static final int SHARE_TCX_FILE = 19;
public static final int EDIT_DETAILS = 20;
public static final int SAVE_GPX_FILE = 21;
public static final int SAVE_KML_FILE = 22;
public static final int SAVE_CSV_FILE = 23;
public static final int SAVE_TCX_FILE = 24;
public static final int CLEAR_MAP = 25;
public static final int SHOW_WAYPOINT = 26;
public static final int EDIT_WAYPOINT = 27;
public static final int WELCOME = 28;
/*
* Menu ids:
@@ -140,6 +135,12 @@ public abstract class MyTracksConstants {
*/
public static final int MAX_LOADED_TRACK_POINTS = 20000;
/**
* Maximum number of track points ever loaded at once from the provider into
* memory in a single call to read points.
*/
public static final int MAX_LOADED_TRACK_POINTS_PER_BATCH = 1000;
/**
* Maximum number of way points displayed by the map overlay.
*/
@@ -168,6 +169,12 @@ public abstract class MyTracksConstants {
*/
public static final double MAX_ACCELERATION = 0.02;
/** Maximum age of a GPS location to be considered current. */
public static final long MAX_LOCATION_AGE_MS = 60 * 1000; // 1 minute
/** Maximum age of a network location to be considered current. */
public static final long MAX_NETWORK_AGE_MS = 1000 * 60 * 10; // 10 minutes
/**
* The type of account that we can use for gdata uploads.
*/
@@ -182,32 +189,32 @@ public abstract class MyTracksConstants {
public static int getActionFromMenuId(int menuId) {
switch (menuId) {
case MyTracksConstants.MENU_SEND_TO_GOOGLE:
return MyTracksConstants.SEND_TO_GOOGLE_DIALOG;
case MyTracksConstants.MENU_EDIT:
return MyTracksConstants.EDIT_DETAILS;
case MyTracksConstants.MENU_DELETE:
return MyTracksConstants.DELETE_TRACK;
case MyTracksConstants.MENU_SHARE_LINK:
return MyTracksConstants.SHARE_LINK;
case MyTracksConstants.MENU_SHARE_KML_FILE:
return MyTracksConstants.SHARE_KML_FILE;
case MyTracksConstants.MENU_SHARE_GPX_FILE:
return MyTracksConstants.SHARE_GPX_FILE;
case MyTracksConstants.MENU_SHARE_CSV_FILE:
return MyTracksConstants.SHARE_CSV_FILE;
case MyTracksConstants.MENU_SHARE_TCX_FILE:
return MyTracksConstants.SHARE_TCX_FILE;
case MyTracksConstants.MENU_SAVE_GPX_FILE:
return MyTracksConstants.SAVE_GPX_FILE;
case MyTracksConstants.MENU_SAVE_KML_FILE:
return MyTracksConstants.SAVE_KML_FILE;
case MyTracksConstants.MENU_SAVE_CSV_FILE:
return MyTracksConstants.SAVE_CSV_FILE;
case MyTracksConstants.MENU_SAVE_TCX_FILE:
return MyTracksConstants.SAVE_TCX_FILE;
case MyTracksConstants.MENU_CLEAR_MAP:
return MyTracksConstants.CLEAR_MAP;
case Constants.MENU_SEND_TO_GOOGLE:
return Constants.SEND_TO_GOOGLE_DIALOG;
case Constants.MENU_EDIT:
return Constants.EDIT_DETAILS;
case Constants.MENU_DELETE:
return Constants.DELETE_TRACK;
case Constants.MENU_SHARE_LINK:
return Constants.SHARE_LINK;
case Constants.MENU_SHARE_KML_FILE:
return Constants.SHARE_KML_FILE;
case Constants.MENU_SHARE_GPX_FILE:
return Constants.SHARE_GPX_FILE;
case Constants.MENU_SHARE_CSV_FILE:
return Constants.SHARE_CSV_FILE;
case Constants.MENU_SHARE_TCX_FILE:
return Constants.SHARE_TCX_FILE;
case Constants.MENU_SAVE_GPX_FILE:
return Constants.SAVE_GPX_FILE;
case Constants.MENU_SAVE_KML_FILE:
return Constants.SAVE_KML_FILE;
case Constants.MENU_SAVE_CSV_FILE:
return Constants.SAVE_CSV_FILE;
case Constants.MENU_SAVE_TCX_FILE:
return Constants.SAVE_TCX_FILE;
case Constants.MENU_CLEAR_MAP:
return Constants.CLEAR_MAP;
default:
return -1;
}
@@ -216,8 +223,22 @@ public abstract class MyTracksConstants {
public static final String MAPSHOP_BASE_URL =
"http://maps.google.com/maps/ms";
/*
* Default values - keep in sync with those in preferences.xml.
*/
public static final int DEFAULT_ANNOUNCEMENT_FREQUENCY = -1;
public static final int DEFAULT_AUTO_RESUME_TRACK_TIMEOUT = 10; // In min.
public static final int DEFAULT_MAX_RECORDING_DISTANCE = 200;
public static final int DEFAULT_MIN_RECORDING_DISTANCE = 5;
public static final int DEFAULT_MIN_RECORDING_INTERVAL = 0;
public static final int DEFAULT_MIN_REQUIRED_ACCURACY = 200;
public static final int DEFAULT_SPLIT_FREQUENCY = 0;
public static final String SETTINGS_NAME = "SettingsActivity";
/**
* This is an abstract utility class.
*/
protected MyTracksConstants() { }
protected Constants() { }
}
@@ -34,12 +34,12 @@ import android.util.Log;
*
* @author Leif Hendrik Wilden
*/
public class MyTracksDeleteAllTracks extends Handler {
public class DeleteAllTracks extends Handler {
private final Context context;
private final Runnable done;
public MyTracksDeleteAllTracks(Context context, Runnable done) {
public DeleteAllTracks(Context context, Runnable done) {
this.context = context;
this.done = done;
}
@@ -58,11 +58,12 @@ public class MyTracksDeleteAllTracks extends Handler {
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int i) {
dialog.dismiss();
Log.w(MyTracksConstants.TAG, "deleting all!");
Log.w(Constants.TAG, "deleting all!");
MyTracksProviderUtils.Factory.get(context).deleteAllTracks();
SharedPreferences prefs =
context.getSharedPreferences(MyTracksSettings.SETTINGS_NAME, 0);
context.getSharedPreferences(Constants.SETTINGS_NAME, 0);
SharedPreferences.Editor editor = prefs.edit();
// TODO: Go through data manager
editor.putLong(context.getString(R.string.selected_track_key), -1);
ApiFeatures.getInstance().getApiPlatformAdapter().applyPreferenceChanges(editor);
if (done != null) {
@@ -1,12 +1,12 @@
/*
* 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
@@ -15,20 +15,22 @@
*/
package com.google.android.apps.mytracks;
import static com.google.android.apps.mytracks.Constants.TAG;
import com.google.android.apps.mytracks.io.sendtogoogle.SendDialog;
import com.google.android.maps.mytracks.R;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.WindowManager.BadTokenException;
/**
* A class to handle all dialog related events for My Tracks.
*
*
* @author Sandor Dornbush
*/
public class DialogManager {
@@ -37,14 +39,10 @@ public class DialogManager {
public static final int DIALOG_IMPORT_PROGRESS = 2;
public static final int DIALOG_PROGRESS = 3;
public static final int DIALOG_SEND_TO_GOOGLE = 4;
public static final int DIALOG_SEND_TO_GOOGLE_RESULT = 5;
public static final int DIALOG_WRITE_PROGRESS = 6;
private ProgressDialog progressDialog;
private ProgressDialog importProgressDialog;
private ProgressDialog writeProgressDialog;
private SendToGoogleDialog sendToGoogleDialog;
private AlertDialog sendToGoogleResultDialog;
private SendDialog sendToGoogleDialog;
private ChartSettingsDialog chartSettingsDialog;
private MyTracks activity;
@@ -52,7 +50,7 @@ public class DialogManager {
public DialogManager(MyTracks activity) {
this.activity = activity;
}
protected Dialog onCreateDialog(int id, Bundle args) {
switch (id) {
case DIALOG_CHART_SETTINGS:
@@ -77,32 +75,8 @@ public class DialogManager {
progressDialog.setProgress(10);
return progressDialog;
case DIALOG_SEND_TO_GOOGLE:
sendToGoogleDialog = new SendToGoogleDialog(activity);
sendToGoogleDialog = new SendDialog(activity);
return sendToGoogleDialog;
case DIALOG_SEND_TO_GOOGLE_RESULT:
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
builder.setIcon(android.R.drawable.ic_dialog_info);
builder.setTitle("Title");
builder.setMessage("Message");
builder.setPositiveButton(activity.getString(R.string.ok), null);
builder.setNeutralButton(activity.getString(R.string.share_track),
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
activity.shareLinkToFusionTable(activity.sendToTrackId);
dialog.dismiss();
}
});
sendToGoogleResultDialog = builder.create();
return sendToGoogleResultDialog;
case DIALOG_WRITE_PROGRESS:
writeProgressDialog = new ProgressDialog(activity);
writeProgressDialog.setIcon(android.R.drawable.ic_dialog_info);
writeProgressDialog.setTitle(
activity.getString(R.string.progress_title));
writeProgressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
writeProgressDialog.setMessage(
activity.getString(R.string.write_progress_message));
return writeProgressDialog;
}
return null;
}
@@ -112,24 +86,8 @@ public class DialogManager {
case DIALOG_SEND_TO_GOOGLE:
activity.resetSendToGoogleStatus();
break;
case DIALOG_SEND_TO_GOOGLE_RESULT:
boolean success = activity.getSendToGoogleSuccess();
sendToGoogleResultDialog.setTitle(
success ? R.string.success : R.string.error);
sendToGoogleResultDialog.setIcon(success
? android.R.drawable.ic_dialog_info
: android.R.drawable.ic_dialog_alert);
sendToGoogleResultDialog.setMessage(activity.getFusionTablesResultMessage());
boolean canShare = activity.getSendToFusionTablesTableId() != null;
View share =
sendToGoogleResultDialog.findViewById(android.R.id.button3);
if (share != null) {
share.setVisibility(canShare ? View.VISIBLE : View.GONE);
}
break;
case DIALOG_CHART_SETTINGS:
Log.d(MyTracksConstants.TAG, "MyTracks.onPrepare chart dialog");
Log.d(TAG, "MyTracks.onPrepare chart dialog");
chartSettingsDialog.setup(activity.getChartActivity());
break;
}
@@ -146,7 +104,7 @@ public class DialogManager {
}
});
}
public void setProgressValue(final int percent) {
activity.runOnUiThread(new Runnable() {
public void run() {
@@ -162,7 +120,7 @@ public class DialogManager {
/**
* @return the sendToGoogleDialog
*/
public SendToGoogleDialog getSendToGoogleDialog() {
public SendDialog getSendToGoogleDialog() {
return sendToGoogleDialog;
}
@@ -191,9 +149,9 @@ public class DialogManager {
}
/**
* Just like showDialog, but will catch a BadTokenException that sometimes
* (very rarely) gets thrown. This might happen if the user hits the "back"
* button immediately after sending tracks to google.
* Just like showDialog, but will catch a {@link BadTokenException} that
* sometimes (very rarely) gets thrown. This might happen if the user hits
* the "back" button immediately after sending tracks to google.
*
* @param id the dialog id
*/
@@ -203,11 +161,27 @@ public class DialogManager {
try {
activity.showDialog(id);
} catch (BadTokenException e) {
Log.w(MyTracksConstants.TAG,
"Could not display dialog with id " + id, e);
Log.w(TAG, "Could not display dialog with id " + id, e);
} catch (IllegalStateException e) {
Log.w(MyTracksConstants.TAG,
"Could not display dialog with id " + id, e);
Log.w(TAG, "Could not display dialog with id " + id, e);
}
}
});
}
/**
* The equivalent of {@link #showDialogSafely(int)}, but for a specific
* dialog instance.
*/
public static void showDialogSafely(Activity activity, final Dialog dialog) {
activity.runOnUiThread(new Runnable() {
public void run() {
try {
dialog.show();
} catch (BadTokenException e) {
Log.w(TAG, "Could not display dialog", e);
} catch (IllegalStateException e) {
Log.w(TAG, "Could not display dialog", e);
}
}
});
@@ -228,4 +202,19 @@ public class DialogManager {
});
}
/**
* The equivalent of {@link #dismissDialogSafely(int)}, but for a specific
* dialog instance.
*/
public static void dismissDialogSafely(Activity activity, final Dialog dialog) {
activity.runOnUiThread(new Runnable() {
public void run() {
try {
dialog.dismiss();
} catch (IllegalArgumentException e) {
// This will be thrown if this dialog was not shown before.
}
}
});
}
}
@@ -98,7 +98,7 @@ class Eula {
ApiFeatures.getInstance().getApiPlatformAdapter().applyPreferenceChanges(
preferences.edit().putBoolean(PREFERENCE_EULA_ACCEPTED, true));
Intent startIntent = new Intent(activity, WelcomeActivity.class);
activity.startActivityForResult(startIntent, MyTracksConstants.WELCOME);
activity.startActivityForResult(startIntent, Constants.WELCOME);
}
private static void refuse(Activity activity) {
@@ -17,10 +17,10 @@ package com.google.android.apps.mytracks;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.content.TracksColumns;
import com.google.android.apps.mytracks.io.TrackWriter;
import com.google.android.apps.mytracks.io.TrackWriterFactory;
import com.google.android.apps.mytracks.io.TrackWriterFactory.TrackFileFormat;
import com.google.android.apps.mytracks.util.MyTracksUtils;
import com.google.android.apps.mytracks.io.file.TrackWriter;
import com.google.android.apps.mytracks.io.file.TrackWriterFactory;
import com.google.android.apps.mytracks.io.file.TrackWriterFactory.TrackFileFormat;
import com.google.android.apps.mytracks.util.SystemUtils;
import com.google.android.maps.mytracks.R;
import android.app.Activity;
@@ -71,14 +71,14 @@ public class ExportAllTracks {
format = TrackFileFormat.TCX;
break;
default:
Log.w(MyTracksConstants.TAG, "Unknown export format: " + which);
Log.w(Constants.TAG, "Unknown export format: " + which);
}
}
};
public ExportAllTracks(Activity activity) {
this.activity = activity;
Log.i(MyTracksConstants.TAG, "ExportAllTracks: Starting");
Log.i(Constants.TAG, "ExportAllTracks: Starting");
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
builder.setSingleChoiceItems(R.array.export_formats, 0, itemClick);
@@ -113,14 +113,14 @@ public class ExportAllTracks {
*/
private void aquireLocksAndExport() {
SharedPreferences prefs =
activity.getSharedPreferences(MyTracksSettings.SETTINGS_NAME, 0);
activity.getSharedPreferences(Constants.SETTINGS_NAME, 0);
long recordingTrackId = -1;
if (prefs != null) {
recordingTrackId =
prefs.getLong(activity.getString(R.string.recording_track_key), -1);
}
if (recordingTrackId != -1) {
wakeLock = MyTracksUtils.acquireWakeLock(activity, wakeLock);
wakeLock = SystemUtils.acquireWakeLock(activity, wakeLock);
}
// Now we can safely export everything.
@@ -130,9 +130,9 @@ public class ExportAllTracks {
// TODO check what happens if we started recording after getting this lock.
if (wakeLock != null && wakeLock.isHeld()) {
wakeLock.release();
Log.i(MyTracksConstants.TAG, "ExportAllTracks: Releasing wake lock.");
Log.i(Constants.TAG, "ExportAllTracks: Releasing wake lock.");
}
Log.i(MyTracksConstants.TAG, "ExportAllTracks: Done");
Log.i(Constants.TAG, "ExportAllTracks: Done");
Toast.makeText(activity, R.string.export_done, Toast.LENGTH_SHORT).show();
}
@@ -163,7 +163,7 @@ public class ExportAllTracks {
}
final int trackCount = cursor.getCount();
Log.i(MyTracksConstants.TAG,
Log.i(Constants.TAG,
"ExportAllTracks: Exporting: " + cursor.getCount() + " tracks.");
int idxTrackId = cursor.getColumnIndexOrThrow(TracksColumns._ID);
activity.runOnUiThread(new Runnable() {
@@ -186,7 +186,7 @@ public class ExportAllTracks {
});
long id = cursor.getLong(idxTrackId);
Log.i(MyTracksConstants.TAG, "ExportAllTracks: exporting: " + id);
Log.i(Constants.TAG, "ExportAllTracks: exporting: " + id);
TrackWriter writer =
TrackWriterFactory.newWriter(activity, providerUtils, id, format);
writer.writeTrack();
@@ -16,9 +16,9 @@
package com.google.android.apps.mytracks;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.io.GpxImporter;
import com.google.android.apps.mytracks.io.file.GpxImporter;
import com.google.android.apps.mytracks.util.FileUtils;
import com.google.android.apps.mytracks.util.MyTracksUtils;
import com.google.android.apps.mytracks.util.SystemUtils;
import com.google.android.maps.mytracks.R;
import android.app.Activity;
@@ -60,7 +60,7 @@ public class ImportAllTracks {
public ImportAllTracks(Activity activity) {
this.activity = activity;
Log.i(MyTracksConstants.TAG, "ImportAllTracks: Starting");
Log.i(Constants.TAG, "ImportAllTracks: Starting");
fileUtils = new FileUtils();
gpxPath = fileUtils.buildExternalDirectoryPath("gpx");
HandlerThread handlerThread;
@@ -82,13 +82,13 @@ public class ImportAllTracks {
* track. Acquire a wake lock if there is no current track.
*/
private void aquireLocksAndImport() {
SharedPreferences prefs = activity.getSharedPreferences(MyTracksSettings.SETTINGS_NAME, 0);
SharedPreferences prefs = activity.getSharedPreferences(Constants.SETTINGS_NAME, 0);
long recordingTrackId = -1;
if (prefs != null) {
recordingTrackId = prefs.getLong(activity.getString(R.string.recording_track_key), -1);
}
if (recordingTrackId != -1) {
wakeLock = MyTracksUtils.acquireWakeLock(activity, wakeLock);
wakeLock = SystemUtils.acquireWakeLock(activity, wakeLock);
}
// Now we can safely import everything.
@@ -98,10 +98,10 @@ public class ImportAllTracks {
// TODO check what happens if we started recording after getting this lock.
if (wakeLock != null && wakeLock.isHeld()) {
wakeLock.release();
Log.i(MyTracksConstants.TAG, "ImportAllTracks: Releasing wake lock.");
Log.i(Constants.TAG, "ImportAllTracks: Releasing wake lock.");
}
Log.i(MyTracksConstants.TAG, "ImportAllTracks: Done");
Log.i(Constants.TAG, "ImportAllTracks: Done");
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
if (gpxFileCount == 0) {
builder.setMessage(activity.getString(R.string.import_empty, gpxPath + "/"));
@@ -141,7 +141,7 @@ public class ImportAllTracks {
return;
}
Log.i(MyTracksConstants.TAG, "ImportAllTracks: Importing: " + gpxFileCount + " tracks.");
Log.i(Constants.TAG, "ImportAllTracks: Importing: " + gpxFileCount + " tracks.");
activity.runOnUiThread(new Runnable() {
public void run() {
makeProgressDialog(gpxFileCount);
@@ -180,19 +180,19 @@ public class ImportAllTracks {
* notifications and returns false on failure.
*/
private boolean importFile(File gpxFile, MyTracksProviderUtils providerUtils) {
Log.i(MyTracksConstants.TAG, "ImportAllTracks: importing: " + gpxFile.getName());
Log.i(Constants.TAG, "ImportAllTracks: importing: " + gpxFile.getName());
try {
GpxImporter.importGPXFile(new FileInputStream(gpxFile), providerUtils);
return true;
} catch (FileNotFoundException e) {
Log.w(MyTracksConstants.TAG, "GPX file wasn't found/went missing: "
Log.w(Constants.TAG, "GPX file wasn't found/went missing: "
+ gpxFile.getAbsolutePath(), e);
} catch (ParserConfigurationException e) {
Log.w(MyTracksConstants.TAG, "Error parsing file: " + gpxFile.getAbsolutePath(), e);
Log.w(Constants.TAG, "Error parsing file: " + gpxFile.getAbsolutePath(), e);
} catch (SAXException e) {
Log.w(MyTracksConstants.TAG, "Error parsing file: " + gpxFile.getAbsolutePath(), e);
Log.w(Constants.TAG, "Error parsing file: " + gpxFile.getAbsolutePath(), e);
} catch (IOException e) {
Log.w(MyTracksConstants.TAG, "Error reading file: " + gpxFile.getAbsolutePath(), e);
Log.w(Constants.TAG, "Error reading file: " + gpxFile.getAbsolutePath(), e);
}
Toast.makeText(activity, activity.getString(R.string.import_error, gpxFile.getName()),
Toast.LENGTH_LONG).show();
@@ -0,0 +1,580 @@
/*
* 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;
import static com.google.android.apps.mytracks.Constants.TAG;
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.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;
import com.google.android.apps.mytracks.util.LocationUtils;
import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapController;
import com.google.android.maps.MapView;
import com.google.android.maps.mytracks.R;
import android.content.Intent;
import android.location.Location;
import android.location.LocationManager;
import android.os.Bundle;
import android.provider.Settings;
import android.util.Log;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.SubMenu;
import android.view.View;
import android.view.View.OnCreateContextMenuListener;
import android.view.Window;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import java.util.EnumSet;
/**
* The map view activity of the MyTracks application.
*
* @author Leif Hendrik Wilden
* @author Rodrigo Damazio
*/
public class MapActivity extends com.google.android.maps.MapActivity
implements View.OnTouchListener, View.OnClickListener,
TrackDataListener {
// Saved instance state keys:
// ---------------------------
private static final String KEY_CURRENT_LOCATION = "currentLocation";
private static final String KEY_KEEP_MY_LOCATION_VISIBLE = "keepMyLocationVisible";
private TrackDataHub dataHub;
/**
* True if the map should be scrolled so that the pointer is always in the
* visible area.
*/
private boolean keepMyLocationVisible;
/**
* The current pointer location.
* This is kept to quickly center on it when the user requests.
*/
private Location currentLocation;
// UI elements:
// -------------
private RelativeLayout screen;
private MapView mapView;
private MapOverlay mapOverlay;
private LinearLayout messagePane;
private TextView messageText;
private LinearLayout busyPane;
private ImageButton optionsBtn;
private MenuItem myLocation;
private MenuItem toggleLayers;
/**
* We are not displaying driving directions. Just an arbitrary track that is
* not associated to any licensed mapping data. Therefore it should be okay to
* return false here and still comply with the terms of service.
*/
@Override
protected boolean isRouteDisplayed() {
return false;
}
/**
* We are displaying a location. This needs to return true in order to comply
* with the terms of service.
*/
@Override
protected boolean isLocationDisplayed() {
return true;
}
// Application life cycle:
// ------------------------
@Override
public void onCreate(Bundle bundle) {
Log.d(TAG, "MapActivity.onCreate");
super.onCreate(bundle);
// The volume we want to control is the Text-To-Speech volume
int volumeStream =
new StatusAnnouncerFactory(ApiFeatures.getInstance()).getVolumeStream();
setVolumeControlStream(volumeStream);
dataHub = MyTracks.getInstance().getDataHub();
// We don't need a window title bar:
requestWindowFeature(Window.FEATURE_NO_TITLE);
// Inflate the layout:
setContentView(R.layout.mytracks_layout);
// Remove the window's background because the MapView will obscure it
getWindow().setBackgroundDrawable(null);
// Set up a map overlay:
screen = (RelativeLayout) findViewById(R.id.screen);
mapView = (MapView) findViewById(R.id.map);
mapView.requestFocus();
mapOverlay = new MapOverlay(this);
mapView.getOverlays().add(mapOverlay);
mapView.setOnTouchListener(this);
mapView.setBuiltInZoomControls(true);
messagePane = (LinearLayout) findViewById(R.id.messagepane);
messageText = (TextView) findViewById(R.id.messagetext);
busyPane = (LinearLayout) findViewById(R.id.busypane);
optionsBtn = (ImageButton) findViewById(R.id.showOptions);
optionsBtn.setOnCreateContextMenuListener(contextMenuListener);
optionsBtn.setOnClickListener(this);
}
@Override
protected void onRestoreInstanceState(Bundle bundle) {
Log.d(TAG, "MapActivity.onRestoreInstanceState");
if (bundle != null) {
super.onRestoreInstanceState(bundle);
keepMyLocationVisible =
bundle.getBoolean(KEY_KEEP_MY_LOCATION_VISIBLE, false);
if (bundle.containsKey(KEY_CURRENT_LOCATION)) {
currentLocation = (Location) bundle.getParcelable(KEY_CURRENT_LOCATION);
if (currentLocation != null) {
showCurrentLocation();
}
} else {
currentLocation = null;
}
}
}
@Override
protected void onStart() {
Log.d(TAG, "MapActivity.onStart");
super.onStart();
dataHub.registerTrackDataListener(this, EnumSet.of(
ListenerDataType.SELECTED_TRACK_CHANGED,
ListenerDataType.POINT_UPDATES,
ListenerDataType.WAYPOINT_UPDATES,
ListenerDataType.LOCATION_UPDATES,
ListenerDataType.COMPASS_UPDATES));
}
@Override
protected void onSaveInstanceState(Bundle outState) {
Log.d(TAG, "MapActivity.onSaveInstanceState");
outState.putBoolean(KEY_KEEP_MY_LOCATION_VISIBLE, keepMyLocationVisible);
if (currentLocation != null) {
outState.putParcelable(KEY_CURRENT_LOCATION, currentLocation);
}
super.onSaveInstanceState(outState);
}
@Override
protected void onStop() {
Log.d(TAG, "MapActivity.onStop");
dataHub.unregisterTrackDataListener(this);
super.onStop();
}
// Utility functions:
// -------------------
/**
* Shows the options button if a track is selected, or hide it if not.
*/
private void updateOptionsButton(boolean trackSelected) {
optionsBtn.setVisibility(
trackSelected ? View.VISIBLE : View.INVISIBLE);
}
/**
* Tests if a location is visible.
*
* @param location a given location
* @return true if the given location is within the visible map area
*/
private boolean locationIsVisible(Location location) {
if (location == null || mapView == null) {
return false;
}
GeoPoint center = mapView.getMapCenter();
int latSpan = mapView.getLatitudeSpan();
int lonSpan = mapView.getLongitudeSpan();
// Bottom of map view is obscured by zoom controls/buttons.
// Subtract a margin from the visible area:
GeoPoint marginBottom = mapView.getProjection().fromPixels(
0, mapView.getHeight());
GeoPoint marginTop = mapView.getProjection().fromPixels(0,
mapView.getHeight()
- mapView.getZoomButtonsController().getZoomControls().getHeight());
int margin =
Math.abs(marginTop.getLatitudeE6() - marginBottom.getLatitudeE6());
GeoRect r = new GeoRect(center, latSpan, lonSpan);
r.top += margin;
GeoPoint geoPoint = LocationUtils.getGeoPoint(location);
return r.contains(geoPoint);
}
/**
* Moves the location pointer to the current location and center the map if
* the current location is outside the visible area.
*/
private void showCurrentLocation() {
if (currentLocation == null || mapOverlay == null || mapView == null) {
return;
}
mapOverlay.setMyLocation(currentLocation);
mapView.postInvalidate();
if (keepMyLocationVisible && !locationIsVisible(currentLocation)) {
GeoPoint geoPoint = LocationUtils.getGeoPoint(currentLocation);
MapController controller = mapView.getController();
controller.animateTo(geoPoint);
}
}
@Override
public void onTrackUpdated(Track track) {
// We don't care.
}
/**
* Zooms and pans the map so that the given track is visible.
*
* @param track the track
*/
private void zoomMapToBoundaries(Track track) {
if (mapView == null) {
return;
}
if (track == null || track.getNumberOfPoints() < 2) {
return;
}
TripStatistics stats = track.getStatistics();
int bottom = stats.getBottom();
int left = stats.getLeft();
int latSpanE6 = stats.getTop() - bottom;
int lonSpanE6 = stats.getRight() - left;
if (latSpanE6 > 0
&& latSpanE6 < 180E6
&& lonSpanE6 > 0
&& lonSpanE6 < 360E6) {
keepMyLocationVisible = false;
GeoPoint center = new GeoPoint(
bottom + latSpanE6 / 2,
left + lonSpanE6 / 2);
if (LocationUtils.isValidGeoPoint(center)) {
mapView.getController().setCenter(center);
mapView.getController().zoomToSpan(latSpanE6, lonSpanE6);
}
}
}
/**
* Zooms and pans the map so that the given waypoint is visible.
*/
public void showWaypoint(long waypointId) {
MyTracksProviderUtils providerUtils = MyTracksProviderUtils.Factory.get(this);
Waypoint wpt = providerUtils.getWaypoint(waypointId);
if (wpt != null && wpt.getLocation() != null) {
keepMyLocationVisible = false;
GeoPoint center = new GeoPoint(
(int) (wpt.getLocation().getLatitude() * 1E6),
(int) (wpt.getLocation().getLongitude() * 1E6));
mapView.getController().setCenter(center);
mapView.getController().setZoom(20);
mapView.invalidate();
}
}
@Override
public void onSelectedTrackChanged(final Track track, final boolean isRecording) {
runOnUiThread(new Runnable() {
@Override
public void run() {
boolean trackSelected = track != null;
updateOptionsButton(trackSelected);
mapOverlay.setTrackDrawingEnabled(trackSelected);
if (trackSelected) {
busyPane.setVisibility(View.VISIBLE);
zoomMapToBoundaries(track);
mapOverlay.setShowEndMarker(!isRecording);
busyPane.setVisibility(View.GONE);
}
mapView.invalidate();
}
});
}
private final OnCreateContextMenuListener contextMenuListener =
new OnCreateContextMenuListener() {
@Override
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenuInfo menuInfo) {
menu.setHeaderTitle(R.string.tracklist_this_track);
menu.add(0, Constants.MENU_EDIT, 0,
R.string.tracklist_edit_track);
if (!dataHub.isRecordingSelected()) {
menu.add(0, Constants.MENU_SEND_TO_GOOGLE, 0,
R.string.tracklist_send_to_google);
SubMenu share = menu.addSubMenu(0, Constants.MENU_SHARE, 0,
R.string.tracklist_share_track);
share.add(0, Constants.MENU_SHARE_LINK, 0,
R.string.tracklist_share_link);
share.add(0, Constants.MENU_SHARE_GPX_FILE, 0,
R.string.tracklist_share_gpx_file);
share.add(0, Constants.MENU_SHARE_KML_FILE, 0,
R.string.tracklist_share_kml_file);
share.add(0, Constants.MENU_SHARE_CSV_FILE, 0,
R.string.tracklist_share_csv_file);
share.add(0, Constants.MENU_SHARE_TCX_FILE, 0,
R.string.tracklist_share_tcx_file);
SubMenu save = menu.addSubMenu(0,
Constants.MENU_WRITE_TO_SD_CARD, 0,
R.string.tracklist_write_to_sd);
save.add(0, Constants.MENU_SAVE_GPX_FILE, 0,
R.string.tracklist_save_as_gpx);
save.add(0, Constants.MENU_SAVE_KML_FILE, 0,
R.string.tracklist_save_as_kml);
save.add(0, Constants.MENU_SAVE_CSV_FILE, 0,
R.string.tracklist_save_as_csv);
save.add(0, Constants.MENU_SAVE_TCX_FILE, 0,
R.string.tracklist_save_as_tcx);
menu.add(0, Constants.MENU_CLEAR_MAP, 0,
R.string.tracklist_clear_map);
menu.add(0, Constants.MENU_DELETE, 0,
R.string.tracklist_delete_track);
}
}
};
@Override
public boolean onMenuItemSelected(int featureId, MenuItem item) {
if (!super.onMenuItemSelected(featureId, item)) {
MyTracks.getInstance().onActivityResult(
Constants.getActionFromMenuId(item.getItemId()), RESULT_OK,
new Intent());
return true;
}
return false;
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
myLocation = menu.add(0, Constants.MENU_MY_LOCATION, 0,
R.string.mylocation);
myLocation.setIcon(android.R.drawable.ic_menu_mylocation);
toggleLayers = menu.add(0, Constants.MENU_TOGGLE_LAYERS, 0,
R.string.switch_to_sat);
toggleLayers.setIcon(android.R.drawable.ic_menu_mapmode);
return true;
}
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
toggleLayers.setTitle(mapView.isSatellite() ?
R.string.switch_to_map : R.string.switch_to_sat);
return super.onPrepareOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case Constants.MENU_MY_LOCATION: {
dataHub.forceUpdateLocation();
keepMyLocationVisible = true;
if (mapView.getZoomLevel() < 18) {
mapView.getController().setZoom(18);
}
return true;
}
case Constants.MENU_TOGGLE_LAYERS: {
mapView.setSatellite(!mapView.isSatellite());
return true;
}
}
return super.onOptionsItemSelected(item);
}
@Override
public void onClick(View v) {
if (v == messagePane) {
startActivity(new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS));
} else if (v == optionsBtn) {
optionsBtn.performLongClick();
}
}
/**
* We want the pointer to become visible again in case of the next location
* update:
*/
@Override
public boolean onTouch(View view, MotionEvent event) {
if (keepMyLocationVisible && event.getAction() == MotionEvent.ACTION_MOVE) {
if (!locationIsVisible(currentLocation)) {
keepMyLocationVisible = false;
}
}
return false;
}
@Override
public void onProviderStateChange(ProviderState state) {
final int messageId;
final boolean bindClick;
switch (state) {
case DISABLED:
messageId = R.string.status_enable_gps;
bindClick = true;
break;
case NO_FIX:
case BAD_FIX:
messageId = R.string.wait_for_fix;
bindClick = false;
break;
case GOOD_FIX:
// Nothing to show.
messageId = -1;
bindClick = false;
break;
default:
throw new IllegalArgumentException("Unexpected state: " + state);
}
runOnUiThread(new Runnable() {
@Override
public void run() {
if (messageId != -1) {
messageText.setText(messageId);
messagePane.setVisibility(View.VISIBLE);
if (bindClick) {
messagePane.setOnClickListener(MapActivity.this);
} else {
messagePane.setOnClickListener(null);
}
} else {
messagePane.setVisibility(View.GONE);
}
screen.requestLayout();
}
});
}
@Override
public void onCurrentLocationChanged(Location location) {
if (!location.getProvider().equals(LocationManager.GPS_PROVIDER)) {
Log.d(TAG,
"MapActivity: Network location update received (provider '" + location.getProvider() + "'.");
}
currentLocation = location;
showCurrentLocation();
}
@Override
public void onCurrentHeadingChanged(double heading) {
synchronized (this) {
if (mapOverlay.setHeading((float) heading)) {
mapView.postInvalidate();
}
}
}
@Override
public void clearWaypoints() {
mapOverlay.clearWaypoints();
}
@Override
public void onNewWaypoint(Waypoint waypoint) {
if (LocationUtils.isValidLocation(waypoint.getLocation())) {
// TODO: Optimize locking inside addWaypoint
mapOverlay.addWaypoint(waypoint);
}
}
@Override
public void onNewWaypointsDone() {
mapView.postInvalidate();
}
@Override
public void clearTrackPoints() {
mapOverlay.clearPoints();
}
@Override
public void onNewTrackPoint(Location loc) {
mapOverlay.addLocation(loc);
}
@Override
public void onSegmentSplit() {
mapOverlay.addSegmentSplit();
}
@Override
public void onSampledOutTrackPoint(Location loc) {
// We don't care.
}
@Override
public void onNewTrackPointsDone() {
mapView.postInvalidate();
}
@Override
public boolean onUnitsChanged(boolean metric) {
// We don't care.
return false;
}
@Override
public boolean onReportSpeedChanged(boolean reportSpeed) {
// We don't care.
return false;
}
}
@@ -16,7 +16,7 @@
package com.google.android.apps.mytracks;
import com.google.android.apps.mytracks.content.Waypoint;
import com.google.android.apps.mytracks.util.MyTracksUtils;
import com.google.android.apps.mytracks.util.LocationUtils;
import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapView;
import com.google.android.maps.Overlay;
@@ -45,7 +45,7 @@ import java.util.concurrent.BlockingQueue;
*
* @author Leif Hendrik Wilden
*/
public class MyTracksOverlay extends Overlay {
public class MapOverlay extends Overlay {
private final Drawable[] arrows;
private final int arrowWidth, arrowHeight;
@@ -79,20 +79,31 @@ public class MyTracksOverlay extends Overlay {
private static class CachedLocation {
public final boolean valid;
public final GeoPoint geoPoint;
/**
* Constructor for an invalid cached location.
*/
public CachedLocation() {
this.valid = false;
this.geoPoint = null;
}
/**
* Constructor for a potentially valid cached location.
*/
public CachedLocation(Location location) {
this.valid = MyTracksUtils.isValidLocation(location);
this.geoPoint = valid ? MyTracksUtils.getGeoPoint(location) : null;
this.valid = LocationUtils.isValidLocation(location);
this.geoPoint = valid ? LocationUtils.getGeoPoint(location) : null;
}
};
public MyTracksOverlay(Context context) {
public MapOverlay(Context context) {
this.context = context;
this.waypoints = new ArrayList<Waypoint>();
this.points = new ArrayList<CachedLocation>(1024);
this.pendingPoints = new ArrayBlockingQueue<CachedLocation>(
MyTracksConstants.MAX_DISPLAYED_TRACK_POINTS, true);
Constants.MAX_DISPLAYED_TRACK_POINTS, true);
// TODO: Can we use a FrameAnimation or similar here rather
// than individual resources for each arrow direction?
@@ -164,6 +175,13 @@ public class MyTracksOverlay extends Overlay {
pendingPoints.offer(new CachedLocation(l));
}
/**
* Adds a segment split to the map overlay.
*/
public void addSegmentSplit() {
pendingPoints.offer(new CachedLocation());
}
public void addWaypoint(Waypoint wpt) {
// Note: We don't cache waypoints, because it's not worth the effort.
if (wpt != null && wpt.getLocation() != null) {
@@ -172,7 +190,7 @@ public class MyTracksOverlay extends Overlay {
}
}
}
public int getNumLocations() {
synchronized (points) {
return points.size() + pendingPoints.size();
@@ -260,7 +278,7 @@ public class MyTracksOverlay extends Overlay {
synchronized (waypoints) {;
for (Waypoint wpt : waypoints) {
Location loc = wpt.getLocation();
drawElement(canvas, projection, MyTracksUtils.getGeoPoint(loc),
drawElement(canvas, projection, LocationUtils.getGeoPoint(loc),
wpt.getType() == Waypoint.TYPE_STATISTICS ? statsMarker
: waypointMarker, -(markerWidth / 2) + 3, -markerHeight);
}
@@ -274,7 +292,7 @@ public class MyTracksOverlay extends Overlay {
}
Point pt = drawElement(canvas, projection,
MyTracksUtils.getGeoPoint(myLocation), arrows[lastHeading],
LocationUtils.getGeoPoint(myLocation), arrows[lastHeading],
-(arrowWidth / 2) + 3, -(arrowHeight / 2));
// Draw the error circle.
float radius = projection.metersToEquatorPixels(myLocation.getAccuracy());
@@ -423,7 +441,7 @@ public class MyTracksOverlay extends Overlay {
return false;
}
final Location tapLocation = MyTracksUtils.getLocation(p);
final Location tapLocation = LocationUtils.getLocation(p);
double dmin = Double.MAX_VALUE;
Waypoint waypoint = null;
synchronized (waypoints) {
@@ -442,8 +460,8 @@ public class MyTracksOverlay extends Overlay {
if (waypoint != null &&
dmin < 15000000 / Math.pow(2, mapView.getZoomLevel())) {
Intent intent = new Intent(context, MyTracksWaypointDetails.class);
intent.putExtra("waypointid", waypoint.getId());
Intent intent = new Intent(context, WaypointDetails.class);
intent.putExtra(WaypointDetails.WAYPOINT_ID_EXTRA, waypoint.getId());
context.startActivity(intent);
return true;
}
@@ -64,21 +64,21 @@ class MenuManager {
return true;
}
case R.id.menu_list_tracks: {
activity.startActivityForResult(new Intent(activity, MyTracksList.class),
MyTracksConstants.SHOW_TRACK);
activity.startActivityForResult(new Intent(activity, TrackList.class),
Constants.SHOW_TRACK);
return true;
}
case R.id.menu_list_markers: {
Intent startIntent = new Intent(activity, MyTracksWaypointsList.class);
Intent startIntent = new Intent(activity, WaypointsList.class);
startIntent.putExtra("trackid", activity.getSelectedTrackId());
activity.startActivityForResult(startIntent, MyTracksConstants.SHOW_WAYPOINT);
activity.startActivityForResult(startIntent, Constants.SHOW_WAYPOINT);
return true;
}
case R.id.menu_sensor_state: {
return startActivity(SensorStateActivity.class);
}
case R.id.menu_settings: {
return startActivity(MyTracksSettings.class);
return startActivity(SettingsActivity.class);
}
case R.id.menu_aggregated_stats: {
return startActivity(AggregatedStatsActivity.class);
@@ -86,8 +86,8 @@ class MenuManager {
case R.id.menu_help: {
return startActivity(WelcomeActivity.class);
}
case MyTracksConstants.MENU_CLEAR_MAP: {
activity.setSelectedTrackId(-1);
case Constants.MENU_CLEAR_MAP: {
activity.clearSelectedTrack();
return true;
}
}
@@ -0,0 +1,209 @@
/*
* 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
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks;
import com.google.android.accounts.Account;
import com.google.android.apps.mytracks.io.AuthManager;
import com.google.android.apps.mytracks.io.AuthManagerFactory;
import com.google.android.apps.mytracks.io.mymaps.MapsFacade;
import com.google.android.apps.mytracks.io.mymaps.MyMapsConstants;
import com.google.android.maps.mytracks.R;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnCreateContextMenuListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;
import android.widget.TextView;
/**
* Activity which displays the list of current My Maps tracks for the user.
* Returns RESULT_OK if the user picked a map, and returns "mapid" as an extra.
*
* @author Rodrigo Damazio
*/
public class MyMapsList extends Activity implements MapsFacade.MapsListCallback {
private static final int MENU_OPEN = 0;
private static final int MENU_SHARE = 2;
private static final int GET_LOGIN = 1;
private MapsFacade mapsClient;
private AuthManager auth;
private MyMapsListAdapter listAdapter;
private int contextPosition;
private final OnCreateContextMenuListener contextMenuListener =
new OnCreateContextMenuListener() {
@Override
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenuInfo menuInfo) {
AdapterView.AdapterContextMenuInfo info =
(AdapterView.AdapterContextMenuInfo) menuInfo;
contextPosition = info.position;
menu.add(0, MENU_OPEN, 0, R.string.open_map);
menu.add(0, MENU_SHARE, 0, R.string.share_map);
}
};
private final OnItemClickListener clickListener =
new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View v, int position,
long id) {
Intent result = new Intent();
result.putExtra("mapid", (String) listAdapter.getItem(position));
setResult(RESULT_OK, result);
finish();
}
};
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
auth = AuthManagerFactory.getAuthManager(this, GET_LOGIN, null, true,
MyMapsConstants.SERVICE_NAME);
setContentView(R.layout.list);
listAdapter = new MyMapsListAdapter(this);
ListView list = (ListView) findViewById(R.id.maplist);
list.setOnItemClickListener(clickListener);
list.setOnCreateContextMenuListener(contextMenuListener);
list.setAdapter(listAdapter);
startLogin();
}
private void startLogin() {
// Starts in the UI thread.
// TODO fix this for non-froyo devices.
if (AuthManagerFactory.useModernAuthManager()) {
MyTracks.getInstance().getAccountChooser().chooseAccount(
MyMapsList.this,
new AccountChooser.AccountHandler() {
@Override
public void handleAccountSelected(Account account) {
// Account selection happens in the UI thread.
if (account != null) {
// The user did not quit and there was a valid google
// account.
doLogin(account);
}
}
});
} else {
doLogin(null);
}
}
private void doLogin(final Account account) {
// Starts in the UI thread.
auth.doLogin(new Runnable() {
public void run() {
// Runs in UI thread.
mapsClient = new MapsFacade(MyMapsList.this, auth);
startLookup();
}
}, account);
}
private void startLookup() {
// Starts in the UI thread.
new Thread() {
@Override
public void run() {
// Communication with Maps happens in its own thread.
// This will call onReceivedMapListing below.
final boolean success = mapsClient.getMapsList(MyMapsList.this);
runOnUiThread(new Runnable() {
@Override
public void run() {
// Updating the UI when done happens in the UI thread.
onLookupDone(success);
}
});
}
}.start();
}
@Override
public void onReceivedMapListing(final String mapId, final String title,
final String description, final boolean isPublic) {
// Starts in the communication thread.
runOnUiThread(new Runnable() {
@Override
public void run() {
// Updating the list with new contents happens in the UI thread.
listAdapter.addMapListing(mapId, title, description, isPublic);
}
});
}
private void onLookupDone(boolean success) {
// Starts in the UI thread.
findViewById(R.id.loading).setVisibility(View.GONE);
if (!success) {
findViewById(R.id.failed).setVisibility(View.VISIBLE);
}
TextView emptyView = (TextView) findViewById(R.id.mapslist_empty);
ListView list = (ListView) findViewById(R.id.maplist);
list.setEmptyView(emptyView);
}
@Override
protected void onActivityResult(int requestCode, int resultCode,
Intent data) {
if (requestCode == GET_LOGIN) {
auth.authResult(resultCode, data);
}
super.onActivityResult(requestCode, resultCode, data);
}
@Override
public boolean onMenuItemSelected(int featureId, MenuItem item) {
switch (item.getItemId()) {
case MENU_OPEN:
clickListener.onItemClick(null, null, contextPosition, 0);
return true;
case MENU_SHARE:
Intent shareIntent = new Intent(Intent.ACTION_SEND);
shareIntent.setType("text/plain");
shareIntent.putExtra(Intent.EXTRA_SUBJECT,
getText(R.string.share_map_subject));
String[] listItem = (String[]) listAdapter.getMapListingArray(contextPosition);
shareIntent.putExtra(Intent.EXTRA_TEXT, String.format(
getText(R.string.share_map_body_format).toString(),
listItem[1],
MapsFacade.buildMapUrl(listItem[0])));
startActivity(Intent.createChooser(shareIntent,
getText(R.string.share_map).toString()));
return true;
}
return false;
}
}
@@ -0,0 +1,135 @@
package com.google.android.apps.mytracks;
import com.google.android.maps.mytracks.R;
import android.app.Activity;
import android.database.DataSetObserver;
import android.graphics.Color;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ListAdapter;
import android.widget.TextView;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.Vector;
public class MyMapsListAdapter implements ListAdapter {
private Vector<String[]> mapsList;
private Vector<Boolean> publicList;
private Set<DataSetObserver> observerSet;
private final Activity activity;
public MyMapsListAdapter(Activity activity) {
this.activity = activity;
mapsList = new Vector<String[]>();
publicList = new Vector<Boolean>();
observerSet = new HashSet<DataSetObserver>();
}
public void addMapListing(String mapId, String title,
String description, boolean isPublic) {
synchronized (mapsList) {
// Search through the maps list to see if it has the mapid and
// remove it if so, so that we can replace it with updated info
for (int i = 0; i < mapsList.size(); ++i) {
if (mapId.equals(mapsList.get(i)[0])) {
mapsList.remove(i);
publicList.remove(i);
--i;
}
}
mapsList.add(new String[] { mapId, title, description });
publicList.add(isPublic);
}
Iterator<DataSetObserver> iter = observerSet.iterator();
while (iter.hasNext()) {
iter.next().onChanged();
}
}
public String[] getMapListingArray(int position) {
return mapsList.get(position);
}
@Override
public boolean areAllItemsEnabled() {
return true;
}
@Override
public boolean isEnabled(int position) {
return true;
}
@Override
public int getCount() {
return mapsList.size();
}
@Override
public Object getItem(int position) {
return mapsList.get(position)[0];
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public int getItemViewType(int position) {
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView =
activity.getLayoutInflater().inflate(R.layout.listitem, parent, false);
}
String[] map = mapsList.get(position);
((TextView) convertView.findViewById(R.id.maplistitem)).setText(map[1]);
((TextView) convertView.findViewById(R.id.maplistdesc)).setText(map[2]);
TextView publicUnlisted =
(TextView) convertView.findViewById(R.id.maplistpublic);
if (publicList.get(position)) {
publicUnlisted.setTextColor(Color.RED);
publicUnlisted.setText(R.string.public_map);
} else {
publicUnlisted.setTextColor(Color.GREEN);
publicUnlisted.setText(R.string.unlisted_map);
}
return convertView;
}
@Override
public int getViewTypeCount() {
return 1;
}
@Override
public boolean hasStableIds() {
return false;
}
@Override
public boolean isEmpty() {
return mapsList.isEmpty();
}
@Override
public void registerDataSetObserver(DataSetObserver observer) {
observerSet.add(observer);
}
@Override
public void unregisterDataSetObserver(DataSetObserver observer) {
observerSet.remove(observer);
}
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -15,7 +15,7 @@
*/
package com.google.android.apps.mytracks;
import static com.google.android.apps.mytracks.MyTracksConstants.TAG;
import static com.google.android.apps.mytracks.Constants.TAG;
import com.google.android.apps.mytracks.content.Sensor;
import com.google.android.apps.mytracks.services.ITrackRecordingService;
import com.google.android.apps.mytracks.services.sensors.SensorUtils;
@@ -103,7 +103,7 @@ public class SensorStateActivity extends Activity {
ITrackRecordingService service =
mt == null ? null : mt.getTrackRecordingService();
if (service == null) {
Log.d(MyTracksConstants.TAG, "Could not get track recording service.");
Log.d(Constants.TAG, "Could not get track recording service.");
updateSensorState(Sensor.SensorState.NONE);
updateSensorData(null);
return;
@@ -116,9 +116,9 @@ public class SensorStateActivity extends Activity {
updateSensorData(sds);
}
} catch (RemoteException e) {
Log.e(MyTracksConstants.TAG, "Could not read sensor data.", e);
Log.e(Constants.TAG, "Could not read sensor data.", e);
} catch (InvalidProtocolBufferException e) {
Log.e(MyTracksConstants.TAG, "Could not read sensor data.", e);
Log.e(Constants.TAG, "Could not read sensor data.", e);
}
updateSensorData(sds);
@@ -126,7 +126,7 @@ public class SensorStateActivity extends Activity {
int i = service.getSensorState();
updateSensorState(Sensor.SensorState.valueOf(i));
} catch (RemoteException e) {
Log.e(MyTracksConstants.TAG, "Could not read sensor state.", e);
Log.e(Constants.TAG, "Could not read sensor state.", e);
updateSensorState(Sensor.SensorState.NONE);
}
}
@@ -15,27 +15,38 @@
*/
package com.google.android.apps.mytracks;
import java.util.ArrayList;
import java.util.List;
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;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.CheckBoxPreference;
import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.preference.PreferenceManager;
import android.preference.Preference.OnPreferenceChangeListener;
import android.preference.Preference.OnPreferenceClickListener;
import android.preference.PreferenceActivity;
import android.preference.PreferenceManager;
import android.preference.PreferenceScreen;
import android.provider.Settings;
import android.util.Log;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* An activity that let's the user see and edit the settings.
@@ -43,28 +54,14 @@ import android.provider.Settings;
* @author Leif Hendrik Wilden
* @author Rodrigo Damazio
*/
public class MyTracksSettings extends PreferenceActivity {
public static final String SETTINGS_NAME = "MyTracksSettings";
/*
* Default values - keep in sync with those in preferences.xml.
*/
public static final int DEFAULT_AUTO_RESUME_TRACK_TIMEOUT = 10; // In min.
public static final int DEFAULT_ANNOUNCEMENT_FREQUENCY = -1;
public static final int DEFAULT_MAX_RECORDING_DISTANCE = 200;
public static final int DEFAULT_MIN_RECORDING_DISTANCE = 5;
public static final int DEFAULT_MIN_RECORDING_INTERVAL = 0;
public static final int DEFAULT_MIN_REQUIRED_ACCURACY = 200;
public static final int DEFAULT_SPLIT_FREQUENCY = 0;
public class SettingsActivity extends PreferenceActivity {
private BackupPreferencesListener backupListener;
private SharedPreferences preferences;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle icicle) {
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
// The volume we want to control is the Text-To-Speech volume
@@ -75,7 +72,7 @@ public class MyTracksSettings extends PreferenceActivity {
// Tell it where to read/write preferences
PreferenceManager preferenceManager = getPreferenceManager();
preferenceManager.setSharedPreferencesName(SETTINGS_NAME);
preferenceManager.setSharedPreferencesName(Constants.SETTINGS_NAME);
preferenceManager.setSharedPreferencesMode(0);
// Set up automatic preferences backup
@@ -103,6 +100,31 @@ public class MyTracksSettings extends PreferenceActivity {
});
updatePreferenceUnits(metricUnitsPreference.isChecked());
customizeSensorOptionsPreferences();
// Disable TTS announcement preference if not available
if (!apiFeatures.hasTextToSpeech()) {
IntegerListPreference announcementFrequency =
(IntegerListPreference) findPreference(
getString(R.string.announcement_frequency_key));
announcementFrequency.setEnabled(false);
announcementFrequency.setValue("-1");
announcementFrequency.setSummary(
R.string.settings_not_available_summary);
}
// Hook up action for resetting all settings
Preference resetPreference = findPreference(getString(R.string.reset_key));
resetPreference.setOnPreferenceClickListener(new OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference arg0) {
onResetPreferencesClick();
return true;
}
});
}
private void customizeSensorOptionsPreferences() {
ListPreference sensorTypePreference =
(ListPreference) findPreference(getString(R.string.sensor_type_key));
sensorTypePreference.setOnPreferenceChangeListener(
@@ -115,16 +137,37 @@ public class MyTracksSettings extends PreferenceActivity {
}
});
updateSensorSettings(sensorTypePreference.getValue());
// Disable TTS announcement preference if not available
if (!apiFeatures.hasTextToSpeech()) {
IntegerListPreference announcementFrequency =
(IntegerListPreference) findPreference(
getString(R.string.announcement_frequency_key));
announcementFrequency.setEnabled(false);
announcementFrequency.setValue("-1");
announcementFrequency.setSummary(
R.string.settings_not_available_summary);
if (!AntUtils.hasAntSupport(this)) {
// The sensor options screen has a few ANT-specific options which we
// need to remove. First, we need to remove the ANT sensor types.
// Second, we need to remove the ANT unpairing options.
Set<Integer> toRemove = new HashSet<Integer>();
String[] antValues = getResources().getStringArray(R.array.ant_sensor_type_values);
for (String antValue : antValues) {
toRemove.add(sensorTypePreference.findIndexOfValue(antValue));
}
CharSequence[] entries = sensorTypePreference.getEntries();
CharSequence[] entryValues = sensorTypePreference.getEntryValues();
CharSequence[] filteredEntries = new CharSequence[entries.length - toRemove.size()];
CharSequence[] filteredEntryValues = new CharSequence[filteredEntries.length];
for (int i = 0, last = 0; i < entries.length; i++) {
if (!toRemove.contains(i)) {
filteredEntries[last] = entries[i];
filteredEntryValues[last++] = entryValues[i];
}
}
sensorTypePreference.setEntries(filteredEntries);
sensorTypePreference.setEntryValues(filteredEntryValues);
PreferenceScreen sensorOptionsScreen =
(PreferenceScreen) findPreference(getString(R.string.sensor_options_key));
sensorOptionsScreen.removePreference(findPreference(getString(R.string.ant_options_key)));
}
}
@@ -137,19 +180,24 @@ public class MyTracksSettings extends PreferenceActivity {
findPreference(getString(R.string.backup_to_sd_key));
Preference restoreNowPreference =
findPreference(getString(R.string.restore_from_sd_key));
Preference resetPreference = findPreference(getString(R.string.reset_key));
// If recording, disable backup/restore
// If recording, disable backup/restore/reset
// (we don't want to get to inconsistent states)
boolean recording =
preferences.getLong(getString(R.string.recording_track_key), -1) != -1;
backupNowPreference.setEnabled(!recording);
restoreNowPreference.setEnabled(!recording);
resetPreference.setEnabled(!recording);
backupNowPreference.setSummary(
recording ? R.string.settings_no_backup_while_recording
recording ? R.string.settings_not_while_recording
: R.string.settings_backup_to_sd_summary);
restoreNowPreference.setSummary(
recording ? R.string.settings_no_backup_while_recording
recording ? R.string.settings_not_while_recording
: R.string.settings_restore_from_sd_summary);
resetPreference.setSummary(
recording ? R.string.settings_not_while_recording
: R.string.settings_reset_summary);
// Add actions to the backup preferences
backupNowPreference.setOnPreferenceClickListener(
@@ -157,7 +205,7 @@ public class MyTracksSettings extends PreferenceActivity {
@Override
public boolean onPreferenceClick(Preference preference) {
BackupActivityHelper backupHelper =
new BackupActivityHelper(MyTracksSettings.this);
new BackupActivityHelper(SettingsActivity.this);
backupHelper.writeBackup();
return true;
}
@@ -167,7 +215,7 @@ public class MyTracksSettings extends PreferenceActivity {
@Override
public boolean onPreferenceClick(Preference preference) {
BackupActivityHelper backupHelper =
new BackupActivityHelper(MyTracksSettings.this);
new BackupActivityHelper(SettingsActivity.this);
backupHelper.restoreBackup();
return true;
}
@@ -192,10 +240,14 @@ public class MyTracksSettings extends PreferenceActivity {
// Update the ANT+ sensors.
// TODO: Only enable on phones that have ANT+.
findPreference(getString(R.string.ant_heart_rate_sensor_id_key))
.setEnabled(getString(R.string.ant_sensor_type).equals(sensorType));
findPreference(getString(R.string.ant_srm_bridge_sensor_id_key))
.setEnabled(getString(R.string.srm_ant_bridge_sensor_type).equals(sensorType));
Preference antHrm = findPreference(getString(R.string.ant_heart_rate_sensor_id_key));
Preference antSrm = findPreference(getString(R.string.ant_srm_bridge_sensor_id_key));
if (antHrm != null && antSrm != null) {
antHrm
.setEnabled(getString(R.string.ant_sensor_type).equals(sensorType));
antSrm
.setEnabled(getString(R.string.srm_ant_bridge_sensor_type).equals(sensorType));
}
}
/**
@@ -214,10 +266,7 @@ public class MyTracksSettings 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
: R.array.min_recording_distance_options_ft);
@@ -227,11 +276,20 @@ public class MyTracksSettings 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.
@@ -271,4 +329,53 @@ public class MyTracksSettings extends PreferenceActivity {
devicesPreference.setEntryValues(entryValuesArray);
devicesPreference.setEntries(entriesArray);
}
/** Callback for when user asks to reset all settings. */
private void onResetPreferencesClick() {
AlertDialog dialog = new AlertDialog.Builder(this)
.setCancelable(true)
.setTitle(R.string.settings_reset)
.setMessage(R.string.settings_reset_dialog_message)
.setPositiveButton(android.R.string.ok,
new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int button) {
onResetPreferencesConfirmed();
}
})
.setNegativeButton(android.R.string.cancel, null)
.create();
dialog.show();
}
/** Callback for when user confirms resetting all settings. */
private void onResetPreferencesConfirmed() {
// Change preferences in a separate thread.
new Thread() {
@Override
public void run() {
Log.i(TAG, "Resetting all settings");
// Actually wipe preferences (and save synchronously).
preferences.edit().clear().commit();
// Give UI feedback in the UI thread.
runOnUiThread(new Runnable() {
@Override
public void run() {
// Give feedback to the user.
Toast.makeText(
SettingsActivity.this,
R.string.settings_reset_done,
Toast.LENGTH_SHORT).show();
// Restart the settings activity so all changes are loaded.
Intent intent = getIntent();
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
}
});
}
}.start();
}
}
@@ -15,26 +15,18 @@
*/
package com.google.android.apps.mytracks;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.content.MyTracksProviderUtilsImpl;
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.TracksColumns;
import com.google.android.apps.mytracks.content.WaypointsColumns;
import com.google.android.apps.mytracks.services.StatusAnnouncerFactory;
import com.google.android.apps.mytracks.content.Waypoint;
import com.google.android.apps.mytracks.services.tasks.StatusAnnouncerFactory;
import com.google.android.apps.mytracks.util.ApiFeatures;
import com.google.android.maps.mytracks.R;
import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.database.ContentObserver;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.location.LocationProvider;
import android.os.Bundle;
import android.os.Handler;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Menu;
@@ -42,66 +34,41 @@ import android.view.MenuItem;
import android.view.Window;
import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.Toast;
import java.util.EnumSet;
/**
* An activity that displays track statistics to the user.
*
* @author Sandor Dornbush
* @author Rodrigo Damazio
*/
public class StatsActivity extends Activity
implements OnSharedPreferenceChangeListener {
public class StatsActivity extends Activity implements TrackDataListener {
private StatsUtilities utils;
private UIUpdateThread thread;
private ContentObserver observer;
/**
* The id of the currently selected track.
*/
private long selectedTrackId = -1;
/**
* The id of the currently recording track.
*/
private long recordingTrackId = -1;
/**
* The start time of the selected track.
*/
private long startTime = -1;
/**
* True if distances should be displayed in metric units (from shared
* preferences).
*/
private boolean metricUnits = true;
/**
* True if pace should be displayed as dist/time (from shared preferences).
*/
private boolean displaySpeed = true;
/**
* true if activity has resumed and is on top
*/
private boolean activityOnTop = false;
/**
* If true, the statistics for the current segment are shown, otherwise
* for the full track.
*/
private boolean showCurrentSegment = false;
private MyTracksProviderUtils providerUtils;
private TrackDataHub dataHub;
/**
* A runnable for posting to the UI thread. Will update the total time field.
*/
private final Runnable updateResults = new Runnable() {
public void run() {
updateTotalTime();
if (dataHub.isRecordingSelected()) {
utils.setTime(R.id.total_time_register,
System.currentTimeMillis() - startTime);
}
}
};
@@ -112,24 +79,22 @@ public class StatsActivity extends Activity
public UIUpdateThread() {
super();
Log.i(MyTracksConstants.TAG, "Created UI update thread");
Log.i(TAG, "Created UI update thread");
}
@Override
public void run() {
Log.i(MyTracksConstants.TAG, "Started UI update thread");
Log.i(TAG, "Started UI update thread");
while (MyTracks.getInstance().isRecording()) {
long sleeptime = 1000;
runOnUiThread(updateResults);
try {
Thread.sleep(sleeptime);
Thread.sleep(1000L);
} catch (InterruptedException e) {
Log.w(MyTracksConstants.TAG,
"StatsActivity: Caught exception on sleep.", e);
Log.w(TAG, "StatsActivity: Caught exception on sleep.", e);
break;
}
}
Log.w(MyTracksConstants.TAG, "UIUpdateThread finished.");
Log.w(TAG, "UIUpdateThread finished.");
}
}
@@ -138,9 +103,9 @@ public class StatsActivity extends Activity
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
dataHub = MyTracks.getInstance().getDataHub();
utils = new StatsUtilities(this);
providerUtils = new MyTracksProviderUtilsImpl(getContentResolver());
// The volume we want to control is the Text-To-Speech volume
int volumeStream =
new StatusAnnouncerFactory(ApiFeatures.getInstance()).getVolumeStream();
@@ -151,40 +116,10 @@ public class StatsActivity extends Activity
setContentView(R.layout.stats);
Handler contentHandler = new Handler();
observer = new ContentObserver(contentHandler) {
@Override
public void onChange(boolean selfChange) {
Log.d(MyTracksConstants.TAG, "StatsActivity: ContentObserver.onChange");
restoreStats();
super.onChange(selfChange);
}
};
ScrollView sv = ((ScrollView) findViewById(R.id.scrolly));
sv.setScrollBarStyle(ScrollView.SCROLLBARS_OUTSIDE_INSET);
SharedPreferences preferences =
getSharedPreferences(MyTracksSettings.SETTINGS_NAME, 0);
if (preferences != null) {
selectedTrackId = preferences.getLong(
getString(R.string.selected_track_key), -1);
recordingTrackId = preferences.getLong(
getString(R.string.recording_track_key), -1);
metricUnits = preferences.getBoolean(
getString(R.string.metric_units_key), true);
displaySpeed =
preferences.getBoolean(getString(R.string.report_speed_key), true);
checkLiveTrack();
restoreStats();
showUnknownLocation();
preferences.registerOnSharedPreferenceChangeListener(this);
}
utils.setMetricUnits(metricUnits);
utils.setReportSpeed(displaySpeed);
utils.updateUnits();
utils.setSpeedLabel(R.id.speed_label, R.string.speed, R.string.pace_label);
utils.setSpeedLabels();
showUnknownLocation();
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
@@ -194,88 +129,67 @@ public class StatsActivity extends Activity
}
@Override
protected void onPause() {
unregisterLocationListener();
protected void onStart() {
dataHub.registerTrackDataListener(this, EnumSet.of(
ListenerDataType.SELECTED_TRACK_CHANGED,
ListenerDataType.TRACK_UPDATES,
ListenerDataType.LOCATION_UPDATES,
ListenerDataType.DISPLAY_PREFERENCES));
super.onStart();
}
@Override
protected void onStop() {
dataHub.unregisterTrackDataListener(this);
if (thread != null) {
thread.interrupt();
thread = null;
}
getContentResolver().unregisterContentObserver(observer);
activityOnTop = false;
super.onPause();
super.onStop();
}
@Override
protected void onResume() {
activityOnTop = true;
checkLiveTrack();
restoreStats();
showUnknownLocation();
super.onResume();
public boolean onUnitsChanged(boolean metric) {
utils.setMetricUnits(metric);
updateLabels();
return true; // Reload data
}
@Override
public void onSharedPreferenceChanged(
final SharedPreferences sharedPreferences, final String key) {
Log.d(MyTracksConstants.TAG,
"StatsActivity: onSharedPreferences changed " + key);
if (key != null) {
runOnUiThread(new Runnable() {
@Override
public void run() {
if (key.equals(getString(R.string.selected_track_key))) {
selectedTrackId =
sharedPreferences.getLong(
getString(R.string.selected_track_key),
-1);
checkLiveTrack();
restoreStats();
showUnknownLocation();
} else if (key.equals(getString(R.string.recording_track_key))) {
recordingTrackId =
sharedPreferences.getLong(
getString(R.string.recording_track_key),
-1);
checkLiveTrack();
restoreStats();
showUnknownLocation();
} else if (key.equals(getString(R.string.metric_units_key))) {
metricUnits =
sharedPreferences.getBoolean(
getString(R.string.metric_units_key), true);
utils.setMetricUnits(metricUnits);
utils.updateUnits();
restoreStats();
} else if (key.equals(getString(R.string.report_speed_key))) {
displaySpeed =
sharedPreferences.getBoolean(
getString(R.string.report_speed_key),
true);
utils.setReportSpeed(displaySpeed);
utils.updateUnits();
utils.setSpeedLabel(
R.id.speed_label, R.string.speed, R.string.pace_label);
Log.w(MyTracksConstants.TAG, "Setting speed labels");
utils.setSpeedLabels();
restoreStats();
}
}
});
}
public boolean onReportSpeedChanged(boolean displaySpeed) {
utils.setReportSpeed(displaySpeed);
updateLabels();
return true; // Reload data
}
private void updateLabels() {
runOnUiThread(new Runnable() {
@Override
public void run() {
utils.updateUnits();
utils.setSpeedLabel(R.id.speed_label, R.string.speed, R.string.pace_label);
utils.setSpeedLabels();
}
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
MenuItem currentSegment = menu.add(0,
MyTracksConstants.MENU_CURRENT_SEGMENT, 0, R.string.current_segment);
Constants.MENU_CURRENT_SEGMENT, 0, R.string.current_segment);
currentSegment.setIcon(R.drawable.ic_menu_lastsegment);
return true;
}
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
MenuItem item = menu.findItem(MyTracksConstants.MENU_CURRENT_SEGMENT);
MenuItem item = menu.findItem(Constants.MENU_CURRENT_SEGMENT);
if (item != null) {
item.setTitle(showCurrentSegment
? getString(R.string.current_track)
@@ -287,139 +201,14 @@ public class StatsActivity extends Activity
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case MyTracksConstants.MENU_CURRENT_SEGMENT:
case Constants.MENU_CURRENT_SEGMENT:
showCurrentSegment = !showCurrentSegment;
restoreStats();
// TODO: Re-read only the data that interests us
return true;
}
return super.onOptionsItemSelected(item);
}
private final LocationListener locationListener = new LocationListener() {
@Override
public void onLocationChanged(Location l) {
if (selectedTrackIsRecording()) {
showLocation(l);
}
}
@Override
public void onProviderDisabled(String provider) {
// Do nothing
}
@Override
public void onProviderEnabled(String provider) {
// Do nothing
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
// Do nothing
}
};
/**
* Registers to receive location updates from the GPS location provider.
*/
private void registerLocationListener() {
LocationManager locationManager =
(LocationManager) getSystemService(Context.LOCATION_SERVICE);
if (locationManager != null) {
LocationProvider gpsProvider =
locationManager.getProvider(MyTracksConstants.GPS_PROVIDER);
if (gpsProvider == null) {
Toast.makeText(this, getString(R.string.error_no_gps_location_provider),
Toast.LENGTH_LONG).show();
return;
} else {
Log.d(MyTracksConstants.TAG, "StatsActivity: Using location provider "
+ gpsProvider.getName());
}
locationManager.requestLocationUpdates(gpsProvider.getName(),
0/*minTime*/, 0/*minDist*/, locationListener);
}
}
/**
* Unregisters all location listener.
*/
private void unregisterLocationListener() {
LocationManager locationManager =
(LocationManager) getSystemService(Context.LOCATION_SERVICE);
if (locationManager != null) {
locationManager.removeUpdates(locationListener);
}
}
/**
* @return true if the selected track is the currently recording track
*/
private boolean selectedTrackIsRecording() {
return MyTracks.getInstance().isRecording()
&& selectedTrackId == recordingTrackId;
}
/**
* Reads values for selected tracks from provider and update the UI.
*/
private void restoreStats() {
if (selectedTrackId < 0) {
utils.setAllToUnknown();
return;
}
Track track = providerUtils.getTrack(selectedTrackId);
if (track == null || track.getStatistics() == null) {
utils.setAllToUnknown();
return;
}
startTime = track.getStatistics().getStartTime();
if (!selectedTrackIsRecording()) {
utils.setTime(R.id.total_time_register,
track.getStatistics().getTotalTime());
}
utils.setAllStats(track.getStatistics());
}
/**
* Checks if this activity needs to update live track data or not.
* If so, make sure that:
* a) a thread keeps updating the total time
* b) a location listener is registered
* c) a content observer is registered
* Otherwise unregister listeners, observers, and kill update thread.
*/
private void checkLiveTrack() {
final boolean isRecording = selectedTrackIsRecording();
final boolean startThread =
(thread == null) && isRecording && activityOnTop;
final boolean killThread =
(thread != null) && (!isRecording || !activityOnTop);
if (startThread) {
thread = new UIUpdateThread();
thread.start();
getContentResolver().registerContentObserver(
TracksColumns.CONTENT_URI, false, observer);
getContentResolver().registerContentObserver(
WaypointsColumns.CONTENT_URI, false, observer);
registerLocationListener();
} else if (killThread) {
thread.interrupt();
thread = null;
getContentResolver().unregisterContentObserver(observer);
unregisterLocationListener();
}
}
public void updateTotalTime() {
if (selectedTrackIsRecording()) {
utils.setTime(R.id.total_time_register,
System.currentTimeMillis() - startTime);
}
}
/**
* Updates the given location fields (latitude, longitude, altitude) and all
* other fields.
@@ -439,4 +228,112 @@ public class StatsActivity extends Activity
utils.setUnknown(R.id.longitude_register);
utils.setUnknown(R.id.speed_register);
}
@Override
public void onSelectedTrackChanged(Track track, boolean isRecording) {
/*
* Checks if this activity needs to update live track data or not.
* If so, make sure that:
* a) a thread keeps updating the total time
* b) a location listener is registered
* c) a content observer is registered
* Otherwise unregister listeners, observers, and kill update thread.
*/
final boolean startThread = (thread == null) && isRecording;
final boolean killThread = (thread != null) && (!isRecording);
if (startThread) {
thread = new UIUpdateThread();
thread.start();
} else if (killThread) {
thread.interrupt();
thread = null;
}
if (track == null || track.getStatistics() == null) {
runOnUiThread(new Runnable() {
@Override
public void run() {
utils.setAllToUnknown();
}
});
}
}
@Override
public void onCurrentLocationChanged(Location loc) {
if (dataHub.isRecordingSelected()) {
showLocation(loc);
}
}
@Override
public void onCurrentHeadingChanged(double heading) {
// We don't care.
}
@Override
public void onProviderStateChange(ProviderState state) {
switch (state) {
case DISABLED:
case NO_FIX:
showUnknownLocation();
break;
}
}
@Override
public void onTrackUpdated(final Track track) {
runOnUiThread(new Runnable() {
@Override
public void run() {
startTime = track.getStatistics().getStartTime();
if (!dataHub.isRecordingSelected()) {
utils.setTime(R.id.total_time_register,
track.getStatistics().getTotalTime());
showUnknownLocation();
}
utils.setAllStats(track.getStatistics());
}
});
}
@Override
public void clearWaypoints() {
// We don't care.
}
@Override
public void onNewWaypoint(Waypoint wpt) {
// We don't care.
}
@Override
public void onNewWaypointsDone() {
// We don't care.
}
@Override
public void clearTrackPoints() {
// We don't care.
}
@Override
public void onNewTrackPoint(Location loc) {
// We don't care.
}
@Override
public void onSegmentSplit() {
// We don't care.
}
@Override
public void onSampledOutTrackPoint(Location loc) {
// We don't care.
}
@Override
public void onNewTrackPointsDone() {
// We don't care.
}
}
@@ -235,7 +235,7 @@ public class StatsUtilities {
}
public void setSpeedLabel(int id, int speedString, int paceString) {
Log.w(MyTracksConstants.TAG, "Setting view " + id +
Log.w(Constants.TAG, "Setting view " + id +
" to " + reportSpeed +
" speed: " + speedString +
" pace: " + paceString);
@@ -243,7 +243,7 @@ public class StatsUtilities {
if (tv != null) {
tv.setText(reportSpeed ? speedString : paceString);
} else {
Log.w(MyTracksConstants.TAG, "Could not find id: " + id);
Log.w(Constants.TAG, "Could not find id: " + id);
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,152 @@
/*
* 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
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks;
import com.google.android.apps.mytracks.content.Track;
import com.google.android.apps.mytracks.content.Waypoint;
import android.location.Location;
/**
* Listener for track data, for both initial and incremental loading.
*
* TODO: Allow listening to just part of the data received here.
*
* @author Rodrigo Damazio
*/
public interface TrackDataListener {
/** States for the GPS location provider. */
public enum ProviderState {
DISABLED,
NO_FIX,
BAD_FIX,
GOOD_FIX;
}
/**
* Called when the location provider changes state.
*/
void onProviderStateChange(ProviderState state);
/**
* Called when the current location changes.
* This is meant for immediate location display only - track point data is
* delivered by other methods below, such as {@link #onNewTrackPoint}.
*
* @param loc the last known location
*/
void onCurrentLocationChanged(Location loc);
/**
* Called when the current heading changes.
*
* @param heading the current heading, already accounting magnetic declination
*/
void onCurrentHeadingChanged(double heading);
/**
* Called when the currently-selected track changes.
* This will be followed by calls to data methods such as
* {@link #onTrackUpdated}, {@link #clearTrackPoints},
* {@link #onNewTrackPoint(Location)}, etc., even if no track is currently
* selected (in which case you'll only get calls to clear the current data).
*
* @param track the selected track, or null if no track is selected
* @param isRecording whether we're currently recording the selected track
*/
void onSelectedTrackChanged(Track track, boolean isRecording);
/**
* Called when the track and/or its statistics have been updated.
*
* @param track the updated version of the track
*/
void onTrackUpdated(Track track);
/**
* Called to clear any previously-sent track points.
* This can be called at any time that we decide the data needs to be
* reloaded, such as when it needs to be resampled.
*/
void clearTrackPoints();
/**
* Called when a new interesting track point is read.
* In this case, interesting means that the point has already undergone
* sampling and invalid point filtering.
*
* @param loc the new track point
*/
void onNewTrackPoint(Location loc);
/**
* Called when a uninteresting track point is read.
* Uninteresting points are all points that get sampled out of the track.
*
* @param loc the new track point
*/
void onSampledOutTrackPoint(Location loc);
/**
* Called when an invalid point (representing a segment split) is read.
*/
void onSegmentSplit();
/**
* Called when we're done (for the time being) sending new points.
* This gets called after every batch of calls to {@link #onNewTrackPoint},
* {@link #onSampledOutTrackPoint} and {@link #onSegmentSplit}.
*/
void onNewTrackPointsDone();
/**
* Called to clear any previously-sent waypoints.
* This can be called at any time that we decide the data needs to be
* reloaded.
*/
void clearWaypoints();
/**
* Called when a new waypoint is read.
*
* @param wpt the new waypoint
*/
void onNewWaypoint(Waypoint wpt);
/**
* Called when we're done (for the time being) sending new waypoints.
* This gets called after every batch of calls to {@link #clearWaypoints} and
* {@link #onNewWaypoint}.
*/
void onNewWaypointsDone();
/**
* Called when the display units are changed by the user.
*
* @param metric true if the units are metric, false if imperial
* @return true to reload all the data, false otherwise
*/
boolean onUnitsChanged(boolean metric);
/**
* Called when the speed/pace display unit is changed by the user.
*
* @param reportSpeed true to report speed, false for pace
* @return true to reload all the data, false otherwise
*/
boolean onReportSpeedChanged(boolean reportSpeed);
}
@@ -0,0 +1,54 @@
/*
* 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
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.database.ContentObserver;
import android.hardware.Sensor;
import android.hardware.SensorEventListener;
import android.location.Location;
import android.location.LocationListener;
import android.net.Uri;
/**
* Interface for abstracting external data sources.
*
* @author Rodrigo Damazio
*/
interface TrackDataSources {
// Preferences
void registerOnSharedPreferenceChangeListener(
OnSharedPreferenceChangeListener listener);
void unregisterOnSharedPreferenceChangeListener(
OnSharedPreferenceChangeListener listener);
// Content provider
void registerContentObserver(Uri contentUri, boolean descendents,
ContentObserver observer);
void unregisterContentObserver(ContentObserver observer);
// Sensors
Sensor getSensor(int type);
void registerSensorListener(SensorEventListener listener,
Sensor sensor, int sensorDelay);
void unregisterSensorListener(SensorEventListener listener);
// Location
boolean isLocationProviderEnabled(String provider);
void requestLocationUpdates(LocationListener listener);
void removeLocationUpdates(LocationListener listener);
Location getLastKnownLocation();
}
@@ -0,0 +1,165 @@
/*
* 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
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks;
import static com.google.android.apps.mytracks.Constants.MAX_LOCATION_AGE_MS;
import static com.google.android.apps.mytracks.Constants.MAX_NETWORK_AGE_MS;
import com.google.android.maps.mytracks.R;
import android.content.ContentResolver;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.database.ContentObserver;
import android.hardware.Sensor;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.location.LocationProvider;
import android.net.Uri;
import android.util.Log;
import android.widget.Toast;
/**
* Real implementation of the data sources, which talks to system services.
*
* @author Rodrigo Damazio
*/
class TrackDataSourcesImpl implements TrackDataSources {
// System services
private final SensorManager sensorManager;
private final LocationManager locationManager;
private final ContentResolver contentResolver;
private final SharedPreferences sharedPreferences;
private final Context context;
TrackDataSourcesImpl(Context context, SharedPreferences sharedPreferences) {
this.context = context;
this.sensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
this.locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
this.contentResolver = context.getContentResolver();
this.sharedPreferences = sharedPreferences;
}
@Override
public void registerOnSharedPreferenceChangeListener(
OnSharedPreferenceChangeListener listener) {
sharedPreferences.registerOnSharedPreferenceChangeListener(listener);
}
@Override
public void unregisterOnSharedPreferenceChangeListener(
OnSharedPreferenceChangeListener listener) {
sharedPreferences.unregisterOnSharedPreferenceChangeListener(listener);
}
@Override
public void registerContentObserver(Uri contentUri, boolean descendents,
ContentObserver observer) {
contentResolver.registerContentObserver(contentUri, descendents, observer);
}
@Override
public void unregisterContentObserver(ContentObserver observer) {
contentResolver.unregisterContentObserver(observer);
}
@Override
public Sensor getSensor(int type) {
return sensorManager.getDefaultSensor(type);
}
@Override
public void registerSensorListener(SensorEventListener listener,
Sensor sensor, int sensorDelay) {
sensorManager.registerListener(listener, sensor, sensorDelay);
}
@Override
public void unregisterSensorListener(SensorEventListener listener) {
sensorManager.unregisterListener(listener);
}
@Override
public boolean isLocationProviderEnabled(String provider) {
return locationManager.isProviderEnabled(provider);
}
@Override
public void requestLocationUpdates(LocationListener listener) {
// Check if the provider exists.
LocationProvider gpsProvider = locationManager.getProvider(LocationManager.GPS_PROVIDER);
if (gpsProvider == null) {
listener.onProviderDisabled(LocationManager.GPS_PROVIDER);
locationManager.removeUpdates(listener);
return;
}
// Listen to GPS location.
String providerName = gpsProvider.getName();
Log.d(Constants.TAG, "TrackDataHub: Using location provider " + providerName);
locationManager.requestLocationUpdates(providerName,
0 /*minTime*/, 0 /*minDist*/, listener);
// Give an initial update on provider state.
if (locationManager.isProviderEnabled(providerName)) {
listener.onProviderEnabled(providerName);
} else {
listener.onProviderDisabled(providerName);
}
// Listen to network location
try {
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER,
1000 * 60 * 5 /*minTime*/, 0 /*minDist*/, listener);
} catch (RuntimeException e) {
// If anything at all goes wrong with getting a cell location do not
// abort. Cell location is not essential to this app.
Log.w(Constants.TAG, "Could not register network location listener.", e);
}
}
@Override
public Location getLastKnownLocation() {
// TODO: Let's look at more advanced algorithms to determine the best
// current location.
Location loc = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
final long now = System.currentTimeMillis();
if (loc == null || loc.getTime() < now - MAX_LOCATION_AGE_MS) {
// We don't have a recent GPS fix, just use cell towers if available
loc = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
int toastResId = R.string.status_approximate_location;
if (loc == null || loc.getTime() < now - MAX_NETWORK_AGE_MS) {
// We don't have a recent cell tower location, let the user know:
toastResId = R.string.status_no_location;
}
// Let the user know we have only an approximate location:
Toast.makeText(context, context.getString(toastResId), Toast.LENGTH_LONG).show();
}
return loc;
}
@Override
public void removeLocationUpdates(LocationListener listener) {
locationManager.removeUpdates(listener);
}
}
@@ -37,7 +37,7 @@ import android.widget.EditText;
*
* @author Leif Hendrik Wilden
*/
public class MyTracksDetails extends Activity implements OnClickListener {
public class TrackDetails extends Activity implements OnClickListener {
/**
* The id of the track being edited (taken from bundle, "trackid")
@@ -56,7 +56,7 @@ public class MyTracksDetails extends Activity implements OnClickListener {
// Required extra when launching this intent:
trackId = getIntent().getLongExtra("trackid", -1);
if (trackId < 0) {
Log.d(MyTracksConstants.TAG,
Log.d(Constants.TAG,
"MyTracksDetails intent was launched w/o track id.");
finish();
return;
@@ -45,7 +45,7 @@ import android.widget.TextView;
*
* @author Leif Hendrik Wilden
*/
public class MyTracksList extends ListActivity
public class TrackList extends ListActivity
implements SharedPreferences.OnSharedPreferenceChangeListener,
View.OnClickListener {
@@ -70,40 +70,40 @@ public class MyTracksList extends ListActivity
AdapterView.AdapterContextMenuInfo info =
(AdapterView.AdapterContextMenuInfo) menuInfo;
contextPosition = info.position;
trackId = MyTracksList.this.listView.getAdapter().getItemId(
trackId = TrackList.this.listView.getAdapter().getItemId(
contextPosition);
menu.add(0, MyTracksConstants.MENU_SHOW, 0,
menu.add(0, Constants.MENU_SHOW, 0,
R.string.tracklist_show_track);
menu.add(0, MyTracksConstants.MENU_EDIT, 0,
menu.add(0, Constants.MENU_EDIT, 0,
R.string.tracklist_edit_track);
if (!MyTracks.getInstance().isRecording()
|| trackId != recordingTrackId) {
menu.add(0, MyTracksConstants.MENU_SEND_TO_GOOGLE, 0,
menu.add(0, Constants.MENU_SEND_TO_GOOGLE, 0,
R.string.tracklist_send_to_google);
SubMenu share = menu.addSubMenu(0, MyTracksConstants.MENU_SHARE, 0,
SubMenu share = menu.addSubMenu(0, Constants.MENU_SHARE, 0,
R.string.tracklist_share_track);
share.add(0, MyTracksConstants.MENU_SHARE_LINK, 0,
R.string.tracklist_share_linkfusion);
share.add(0, MyTracksConstants.MENU_SHARE_GPX_FILE, 0,
share.add(0, Constants.MENU_SHARE_LINK, 0,
R.string.tracklist_share_link);
share.add(0, Constants.MENU_SHARE_GPX_FILE, 0,
R.string.tracklist_share_gpx_file);
share.add(0, MyTracksConstants.MENU_SHARE_KML_FILE, 0,
share.add(0, Constants.MENU_SHARE_KML_FILE, 0,
R.string.tracklist_share_kml_file);
share.add(0, MyTracksConstants.MENU_SHARE_CSV_FILE, 0,
share.add(0, Constants.MENU_SHARE_CSV_FILE, 0,
R.string.tracklist_share_csv_file);
share.add(0, MyTracksConstants.MENU_SHARE_TCX_FILE, 0,
share.add(0, Constants.MENU_SHARE_TCX_FILE, 0,
R.string.tracklist_share_tcx_file);
SubMenu save = menu.addSubMenu(0,
MyTracksConstants.MENU_WRITE_TO_SD_CARD, 0,
Constants.MENU_WRITE_TO_SD_CARD, 0,
R.string.tracklist_write_to_sd);
save.add(0, MyTracksConstants.MENU_SAVE_GPX_FILE, 0,
save.add(0, Constants.MENU_SAVE_GPX_FILE, 0,
R.string.tracklist_save_as_gpx);
save.add(0, MyTracksConstants.MENU_SAVE_KML_FILE, 0,
save.add(0, Constants.MENU_SAVE_KML_FILE, 0,
R.string.tracklist_save_as_kml);
save.add(0, MyTracksConstants.MENU_SAVE_CSV_FILE, 0,
save.add(0, Constants.MENU_SAVE_CSV_FILE, 0,
R.string.tracklist_save_as_csv);
save.add(0, MyTracksConstants.MENU_SAVE_TCX_FILE, 0,
save.add(0, Constants.MENU_SAVE_TCX_FILE, 0,
R.string.tracklist_save_as_tcx);
menu.add(0, MyTracksConstants.MENU_DELETE, 0,
menu.add(0, Constants.MENU_DELETE, 0,
R.string.tracklist_delete_track);
}
}
@@ -132,7 +132,7 @@ public class MyTracksList extends ListActivity
protected void onListItemClick(ListView l, View v, int position, long id) {
Intent result = new Intent();
result.putExtra("trackid", id);
setResult(MyTracksConstants.SHOW_TRACK, result);
setResult(Constants.SHOW_TRACK, result);
finish();
}
@@ -140,24 +140,24 @@ public class MyTracksList extends ListActivity
public boolean onMenuItemSelected(int featureId, MenuItem item) {
if (!super.onMenuItemSelected(featureId, item)) {
switch (item.getItemId()) {
case MyTracksConstants.MENU_SHOW: {
case Constants.MENU_SHOW: {
onListItemClick(null, null, 0, trackId);
return true;
}
case MyTracksConstants.MENU_EDIT: {
Intent intent = new Intent(this, MyTracksDetails.class);
case Constants.MENU_EDIT: {
Intent intent = new Intent(this, TrackDetails.class);
intent.putExtra("trackid", trackId);
startActivity(intent);
return true;
}
case MyTracksConstants.MENU_SHARE:
case MyTracksConstants.MENU_WRITE_TO_SD_CARD:
case Constants.MENU_SHARE:
case Constants.MENU_WRITE_TO_SD_CARD:
return false;
default: {
Intent result = new Intent();
result.putExtra("trackid", trackId);
setResult(
MyTracksConstants.getActionFromMenuId(item.getItemId()), result);
Constants.getActionFromMenuId(item.getItemId()), result);
finish();
return true;
}
@@ -170,7 +170,7 @@ public class MyTracksList extends ListActivity
public void onClick(View v) {
switch (v.getId()) {
case R.id.tracklist_btn_delete_all: {
Handler h = new MyTracksDeleteAllTracks(this, null);
Handler h = new DeleteAllTracks(this, null);
h.handleMessage(null);
break;
}
@@ -197,12 +197,17 @@ public class MyTracksList extends ListActivity
listView = getListView();
listView.setOnCreateContextMenuListener(contextMenuListener);
findViewById(R.id.tracklist_btn_delete_all).setOnClickListener(this);
findViewById(R.id.tracklist_btn_export_all).setOnClickListener(this);
View deleteAll = findViewById(R.id.tracklist_btn_delete_all);
View exportAll = findViewById(R.id.tracklist_btn_export_all);
boolean notRecording = !MyTracks.getInstance().isRecording();
deleteAll.setOnClickListener(this);
deleteAll.setEnabled(notRecording);
exportAll.setOnClickListener(this);
exportAll.setEnabled(notRecording);
findViewById(R.id.tracklist_btn_import_all).setOnClickListener(this);
SharedPreferences preferences =
getSharedPreferences(MyTracksSettings.SETTINGS_NAME, 0);
getSharedPreferences(Constants.SETTINGS_NAME, 0);
preferences.registerOnSharedPreferenceChangeListener(this);
metricUnits =
preferences.getBoolean(getString(R.string.metric_units_key), true);
@@ -39,7 +39,7 @@ import android.widget.ImageView;
*
* @author Leif Hendrik Wilden
*/
public class MyTracksWaypointDetails extends Activity
public class WaypointDetails extends Activity
implements OnClickListener {
public static final String WAYPOINT_ID_EXTRA = "com.google.android.apps.mytracks.WAYPOINT_ID";
@@ -65,7 +65,7 @@ public class MyTracksWaypointDetails extends Activity
utils = new StatsUtilities(this);
SharedPreferences preferences =
getSharedPreferences(MyTracksSettings.SETTINGS_NAME, 0);
getSharedPreferences(Constants.SETTINGS_NAME, 0);
if (preferences != null) {
boolean useMetric =
preferences.getBoolean(getString(R.string.metric_units_key), true);
@@ -82,7 +82,7 @@ public class MyTracksWaypointDetails extends Activity
// Required extra when launching this intent:
waypointId = getIntent().getLongExtra(WAYPOINT_ID_EXTRA, -1);
if (waypointId < 0) {
Log.d(MyTracksConstants.TAG,
Log.d(Constants.TAG,
"MyTracksWaypointsDetails intent was launched w/o waypoint id.");
finish();
return;
@@ -49,7 +49,7 @@ import android.widget.TextView;
*
* @author Leif Hendrik Wilden
*/
public class MyTracksWaypointsList extends ListActivity
public class WaypointsList extends ListActivity
implements View.OnClickListener {
private int contextPosition = -1;
@@ -59,7 +59,6 @@ public class MyTracksWaypointsList extends ListActivity
private Button insertWaypointButton = null;
private Button insertStatisticsButton = null;
private long recordingTrackId = -1;
private long selectedTrackId = -1;
private MyTracksProviderUtils providerUtils;
private Cursor waypointsCursor = null;
@@ -72,14 +71,14 @@ public class MyTracksWaypointsList extends ListActivity
AdapterView.AdapterContextMenuInfo info =
(AdapterView.AdapterContextMenuInfo) menuInfo;
contextPosition = info.position;
waypointId = MyTracksWaypointsList.this.listView.getAdapter()
waypointId = WaypointsList.this.listView.getAdapter()
.getItemId(contextPosition);
int type = providerUtils.getWaypoint(info.id).getType();
menu.add(0, MyTracksConstants.MENU_SHOW, 0,
menu.add(0, Constants.MENU_SHOW, 0,
R.string.waypointslist_show_waypoint);
menu.add(0, MyTracksConstants.MENU_EDIT, 0,
menu.add(0, Constants.MENU_EDIT, 0,
R.string.waypointslist_edit_waypoint);
menu.add(0, MyTracksConstants.MENU_DELETE, 0,
menu.add(0, Constants.MENU_DELETE, 0,
R.string.waypointslist_delete_waypoint).setEnabled(
recordingTrackId < 0 || type == Waypoint.TYPE_WAYPOINT ||
info.id != providerUtils.getLastWaypointId(recordingTrackId));
@@ -90,8 +89,8 @@ public class MyTracksWaypointsList extends ListActivity
protected void onListItemClick(ListView l, View v, int position, long id) {
Intent result = new Intent();
result.putExtra("trackid", trackId);
result.putExtra(MyTracksWaypointDetails.WAYPOINT_ID_EXTRA, id);
setResult(MyTracksConstants.EDIT_WAYPOINT, result);
result.putExtra(WaypointDetails.WAYPOINT_ID_EXTRA, id);
setResult(Constants.EDIT_WAYPOINT, result);
finish();
}
@@ -99,18 +98,18 @@ public class MyTracksWaypointsList extends ListActivity
public boolean onMenuItemSelected(int featureId, MenuItem item) {
if (!super.onMenuItemSelected(featureId, item)) {
switch (item.getItemId()) {
case MyTracksConstants.MENU_SHOW: {
case Constants.MENU_SHOW: {
onListItemClick(null, null, 0, waypointId);
return true;
}
case MyTracksConstants.MENU_EDIT: {
Intent intent = new Intent(this, MyTracksWaypointDetails.class);
case Constants.MENU_EDIT: {
Intent intent = new Intent(this, WaypointDetails.class);
intent.putExtra("trackid", trackId);
intent.putExtra(MyTracksWaypointDetails.WAYPOINT_ID_EXTRA, waypointId);
intent.putExtra(WaypointDetails.WAYPOINT_ID_EXTRA, waypointId);
startActivity(intent);
return true;
}
case MyTracksConstants.MENU_DELETE: {
case Constants.MENU_DELETE: {
deleteWaypoint(waypointId);
}
}
@@ -139,7 +138,10 @@ public class MyTracksWaypointsList extends ListActivity
(Button) findViewById(R.id.waypointslist_btn_insert_statistics);
insertStatisticsButton.setOnClickListener(this);
SharedPreferences preferences =
getSharedPreferences(MyTracksSettings.SETTINGS_NAME, 0);
getSharedPreferences(Constants.SETTINGS_NAME, 0);
// TODO: Get rid of selected and recording track IDs
long selectedTrackId = -1;
if (preferences != null) {
recordingTrackId =
preferences.getLong(getString(R.string.recording_track_key), -1);
@@ -183,18 +185,18 @@ public class MyTracksWaypointsList extends ListActivity
try {
id = MyTracks.getInstance().insertWaypoint(request);
} catch (RemoteException e) {
Log.e(MyTracksConstants.TAG, "Cannot insert marker.", e);
Log.e(Constants.TAG, "Cannot insert marker.", e);
return;
} catch (IllegalStateException e) {
Log.e(MyTracksConstants.TAG, "Cannot insert marker.", e);
Log.e(Constants.TAG, "Cannot insert marker.", e);
return;
}
if (id < 0) {
Log.e(MyTracksConstants.TAG, "Failed to insert marker.");
Log.e(Constants.TAG, "Failed to insert marker.");
return;
}
Intent intent = new Intent(this, MyTracksWaypointDetails.class);
intent.putExtra(MyTracksWaypointDetails.WAYPOINT_ID_EXTRA, id);
Intent intent = new Intent(this, WaypointDetails.class);
intent.putExtra(WaypointDetails.WAYPOINT_ID_EXTRA, id);
startActivity(intent);
}
@@ -259,7 +261,7 @@ public class MyTracksWaypointsList extends ListActivity
public void onClick(DialogInterface dialog, int i) {
dialog.dismiss();
providerUtils.deleteWaypoint(waypointId,
new StringUtils(MyTracksWaypointsList.this));
new StringUtils(WaypointsList.this));
}
});
builder.setNegativeButton(getString(R.string.no),
@@ -15,7 +15,7 @@
*/
package com.google.android.apps.mytracks;
import com.google.android.apps.mytracks.util.MyTracksUtils;
import com.google.android.apps.mytracks.util.SystemUtils;
import com.google.android.maps.mytracks.R;
import android.app.Activity;
@@ -82,6 +82,6 @@ public class WelcomeActivity extends Activity {
AlertDialog dialog = builder.create();
dialog.show();
((TextView) dialog.findViewById(R.id.about_version_register)).
setText(MyTracksUtils.getMyTracksVersion(this));
setText(SystemUtils.getMyTracksVersion(this));
}
}
@@ -0,0 +1,123 @@
/*
* 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
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks;
import com.google.android.apps.mytracks.io.file.TrackWriter;
import com.google.android.maps.mytracks.R;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.DialogInterface;
/**
* Given a {@link TrackWriter}, this class manages the process of writing the
* data in the track represented by the writer. This includes the display of
* a progress dialog, updating the progress bar in said dialog, and notifying
* interested parties when the write completes.
*
* @author Matthew Simmons
*/
class WriteProgressController {
/**
* This listener is used to notify interested parties when the write has
* completed.
*/
public interface OnCompletionListener {
/**
* When this method is invoked, the write has completed, and the progress
* dialog has been dismissed. Whether the write succeeded can be
* determined by examining the {@link TrackWriter}.
*/
public void onComplete(TrackWriter writer);
}
private final Activity activity;
private final TrackWriter writer;
private final ProgressDialog dialog;
private OnCompletionListener onCompletionListener;
/**
* @param activity the activity associated with this write
* @param writer the writer which writes the track to disk. Note that this
* class will use the writer's completion listener. If callers are
* interested in notification upon completion of the write, they should
* use {@link #setOnCompletionListener}.
*/
public WriteProgressController(Activity activity, TrackWriter writer) {
this.activity = activity;
this.writer = writer;
dialog = new ProgressDialog(activity);
dialog.setIcon(android.R.drawable.ic_dialog_info);
dialog.setTitle(activity.getString(R.string.progress_title));
dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
dialog.setMessage(activity.getString(R.string.write_progress_message));
dialog.setIndeterminate(true);
dialog.setOnCancelListener(dialogCancelListener);
writer.setOnCompletionListener(writerCompleteListener);
writer.setOnWriteListener(writerWriteListener);
}
/** Set a listener to be invoked when the write completes. */
public void setOnCompletionListener(OnCompletionListener onCompletionListener) {
this.onCompletionListener = onCompletionListener;
}
/** Initiate an asynchronous write. */
public void startWrite() {
DialogManager.showDialogSafely(activity, dialog);
writer.writeTrackAsync();
}
/** VisibleForTesting */
ProgressDialog getDialog() {
return dialog;
}
private final DialogInterface.OnCancelListener dialogCancelListener =
new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
writer.stopWriteTrack();
}
};
private final TrackWriter.OnCompletionListener writerCompleteListener =
new TrackWriter.OnCompletionListener() {
@Override
public void onComplete() {
DialogManager.dismissDialogSafely(activity, dialog);
if (onCompletionListener != null) {
onCompletionListener.onComplete(writer);
}
}
};
private final TrackWriter.OnWriteListener writerWriteListener =
new TrackWriter.OnWriteListener() {
@Override
public void onWrite(int number, int max) {
if (number % 500 == 0) {
dialog.setIndeterminate(false);
dialog.setMax(max);
dialog.setProgress(Math.min(number, max));
}
}
};
}
@@ -15,7 +15,7 @@
*/
package com.google.android.apps.mytracks.content;
import com.google.android.apps.mytracks.MyTracksConstants;
import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.util.ApiFeatures;
import android.content.ContentProvider;
@@ -193,12 +193,14 @@ public class MyTracksProvider extends ContentProvider {
@Override
public int delete(Uri url, String where, String[] selectionArgs) {
String table;
boolean shouldVacuum = false;
switch (urlMatcher.match(url)) {
case TRACKPOINTS:
table = TRACKPOINTS_TABLE;
break;
case TRACKS:
table = TRACKS_TABLE;
shouldVacuum = true;
break;
case WAYPOINTS:
table = WAYPOINTS_TABLE;
@@ -210,6 +212,13 @@ public class MyTracksProvider extends ContentProvider {
Log.w(MyTracksProvider.TAG, "provider delete in " + table + "!");
int count = db.delete(table, where, selectionArgs);
getContext().getContentResolver().notifyChange(url, null, true);
if (shouldVacuum) {
// If a potentially large amount of data was deleted, we want to reclaim its space.
Log.i(TAG, "Vacuuming the database");
db.execSQL("VACUUM");
}
return count;
}
@@ -373,7 +382,7 @@ public class MyTracksProvider extends ContentProvider {
}
if (ApiFeatures.getInstance().canReuseSQLiteQueryBuilder()) {
Log.i(MyTracksConstants.TAG,
Log.i(Constants.TAG,
"Build query: " + qb.buildQuery(projection, selection, selectionArgs,
null, null, sortOrder, null));
}
@@ -15,7 +15,7 @@
*/
package com.google.android.apps.mytracks.io;
import com.google.android.apps.mytracks.MyTracksConstants;
import com.google.android.apps.mytracks.Constants;
import android.app.Activity;
import android.os.Build;
@@ -46,11 +46,11 @@ public class AuthManagerFactory {
public static AuthManager getAuthManager(Activity activity, int code,
Bundle extras, boolean requireGoogle, String service) {
if (useModernAuthManager()) {
Log.i(MyTracksConstants.TAG,
Log.i(Constants.TAG,
"Creating modern auth manager: " + service);
return new ModernAuthManager(activity, code, extras, requireGoogle, service);
} else {
Log.i(MyTracksConstants.TAG,
Log.i(Constants.TAG,
"Creating legacy auth manager: " + service);
return new AuthManagerOld(activity, code, extras, requireGoogle, service);
}
@@ -23,7 +23,7 @@ import com.google.android.accounts.AuthenticatorException;
import com.google.android.accounts.OperationCanceledException;
import com.google.android.apps.mytracks.AccountChooser;
import com.google.android.apps.mytracks.MyTracks;
import com.google.android.apps.mytracks.MyTracksConstants;
import com.google.android.apps.mytracks.Constants;
import android.app.Activity;
import android.content.Intent;
@@ -104,20 +104,20 @@ public class ModernAuthManager implements AuthManager {
if (result.containsKey(AccountManager.KEY_INTENT)) {
Intent intent = (Intent) result.get(AccountManager.KEY_INTENT);
clearNewTaskFlag(intent);
activity.startActivityForResult(intent, MyTracksConstants.GET_LOGIN);
activity.startActivityForResult(intent, Constants.GET_LOGIN);
return;
}
authToken = result.getString(
AccountManager.KEY_AUTHTOKEN);
Log.e(MyTracksConstants.TAG, "Got auth token.");
Log.e(Constants.TAG, "Got auth token.");
runWhenFinished();
} catch (OperationCanceledException e) {
Log.e(MyTracksConstants.TAG, "Operation Canceled", e);
Log.e(Constants.TAG, "Operation Canceled", e);
} catch (IOException e) {
Log.e(MyTracksConstants.TAG, "IOException", e);
Log.e(Constants.TAG, "IOException", e);
} catch (AuthenticatorException e) {
Log.e(MyTracksConstants.TAG, "Authentication Failed", e);
Log.e(Constants.TAG, "Authentication Failed", e);
}
}
}, null /* handler */);
@@ -149,9 +149,9 @@ public class ModernAuthManager implements AuthManager {
if (results != null) {
authToken = results.getStringExtra(
AccountManager.KEY_AUTHTOKEN);
Log.w(MyTracksConstants.TAG, "authResult: " + authToken);
Log.w(Constants.TAG, "authResult: " + authToken);
} else {
Log.e(MyTracksConstants.TAG, "No auth result results!!");
Log.e(Constants.TAG, "No auth result results!!");
}
runWhenFinished();
return authToken != null;
@@ -181,7 +181,7 @@ public class ModernAuthManager implements AuthManager {
activity.runOnUiThread(new Runnable() {
public void run() {
accountManager.invalidateAuthToken(MyTracksConstants.ACCOUNT_TYPE,
accountManager.invalidateAuthToken(Constants.ACCOUNT_TYPE,
authToken);
MyTracks.getInstance().getAccountChooser().chooseAccount(activity,
new AccountChooser.AccountHandler() {
@@ -16,8 +16,7 @@
package com.google.android.apps.mytracks.io;
import com.google.android.apps.mytracks.MyTracks;
import com.google.android.apps.mytracks.MyTracksConstants;
import com.google.android.apps.mytracks.MyTracksSettings;
import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.content.Track;
import com.google.android.apps.mytracks.io.docs.DocsHelper;
@@ -28,7 +27,7 @@ import com.google.android.maps.mytracks.R;
import com.google.wireless.gdata.client.GDataClient;
import com.google.wireless.gdata.docs.DocumentsClient;
import com.google.wireless.gdata.docs.SpreadsheetsClient;
import com.google.wireless.gdata.maps.xml.XmlMapsGDataParserFactory;
import com.google.wireless.gdata.docs.XmlDocsGDataParserFactory;
import com.google.wireless.gdata.client.GDataServiceClient;
import android.app.Activity;
@@ -73,7 +72,7 @@ public class SendToDocs {
this.trackId = trackId;
SharedPreferences preferences = activity.getSharedPreferences(
MyTracksSettings.SETTINGS_NAME, 0);
Constants.SETTINGS_NAME, 0);
if (preferences != null) {
metricUnits =
preferences.getBoolean(activity.getString(R.string.metric_units_key),
@@ -82,7 +81,7 @@ public class SendToDocs {
metricUnits = true;
}
Log.d(MyTracksConstants.TAG,
Log.d(Constants.TAG,
"Sending to Google Docs: trackId = " + trackId);
handlerThread = new HandlerThread("SendToGoogleDocs");
handlerThread.start();
@@ -99,12 +98,13 @@ public class SendToDocs {
}
private void doUpload() {
// TODO
statusMessage = activity.getString(R.string.error_sending_to_fusiontables);
success = false;
try {
if (trackId == -1) {
Log.w(MyTracksConstants.TAG, "Cannot get track id.");
Log.w(Constants.TAG, "Cannot get track id.");
return;
}
@@ -112,14 +112,14 @@ public class SendToDocs {
Track track =
MyTracksProviderUtils.Factory.get(activity).getTrack(trackId);
if (track == null) {
Log.w(MyTracksConstants.TAG, "Cannot get track.");
Log.w(Constants.TAG, "Cannot get track.");
return;
}
// Transmit track stats via GData feed:
// -------------------------------
Log.d(MyTracksConstants.TAG, "SendToDocs: Uploading to spreadsheet");
Log.d(Constants.TAG, "SendToDocs: Uploading to spreadsheet");
success = uploadToDocs(track);
if (success) {
if (createdNewSpreadSheet) {
@@ -132,7 +132,7 @@ public class SendToDocs {
} else {
statusMessage = activity.getString(R.string.error_sending_to_docs);
}
Log.d(MyTracksConstants.TAG, "SendToDocs: Done.");
Log.d(Constants.TAG, "SendToDocs: Done.");
} finally {
if (onCompletion != null) {
activity.runOnUiThread(onCompletion);
@@ -173,9 +173,9 @@ public class SendToDocs {
try {
androidClient = GDataClientFactory.getGDataClient(activity);
SpreadsheetsClient gdataClient = new SpreadsheetsClient(androidClient,
new XmlMapsGDataParserFactory(new AndroidXmlParserFactory()));
new XmlDocsGDataParserFactory(new AndroidXmlParserFactory()));
trixWrapper.setClient(gdataClient);
Log.d(MyTracksConstants.TAG,
Log.d(Constants.TAG,
"GData connection prepared: " + this.docListAuth);
String sheetTitle = "My Tracks";
@@ -184,7 +184,7 @@ public class SendToDocs {
}
DocumentsClient docsGdataClient = new DocumentsClient(androidClient,
new XmlMapsGDataParserFactory(new AndroidXmlParserFactory()));
new XmlDocsGDataParserFactory(new AndroidXmlParserFactory()));
docListWrapper.setClient(docsGdataClient);
// First try to find the spreadsheet:
@@ -193,7 +193,7 @@ public class SendToDocs {
spreadsheetId = docsHelper.requestSpreadsheetId(docListWrapper,
sheetTitle);
} catch (IOException e) {
Log.i(MyTracksConstants.TAG, "Spreadsheet lookup failed.", e);
Log.i(Constants.TAG, "Spreadsheet lookup failed.", e);
return false;
}
@@ -204,14 +204,14 @@ public class SendToDocs {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
Log.e(MyTracksConstants.TAG, "Sleep interrupted", e);
Log.e(Constants.TAG, "Sleep interrupted", e);
}
try {
spreadsheetId = docsHelper.requestSpreadsheetId(docListWrapper,
sheetTitle);
} catch (IOException e) {
Log.i(MyTracksConstants.TAG, "2nd spreadsheet lookup failed.", e);
Log.i(Constants.TAG, "2nd spreadsheet lookup failed.", e);
return false;
}
}
@@ -219,13 +219,13 @@ public class SendToDocs {
// We were unable to find an existing spreadsheet, so create a new one.
MyTracks.getInstance().setProgressValue(70);
if (spreadsheetId == null) {
Log.i(MyTracksConstants.TAG, "Creating new spreadsheet: " + sheetTitle);
Log.i(Constants.TAG, "Creating new spreadsheet: " + sheetTitle);
try {
spreadsheetId = docsHelper.createSpreadsheet(activity, docListWrapper,
sheetTitle);
} catch (IOException e) {
Log.i(MyTracksConstants.TAG, "Failed to create new spreadsheet "
Log.i(Constants.TAG, "Failed to create new spreadsheet "
+ sheetTitle, e);
return false;
}
@@ -238,19 +238,19 @@ public class SendToDocs {
// reported an error. Seems to be a know bug,
// see http://code.google.com/p/gdata-issues/issues/detail?id=929
// Try to find the created spreadsheet:
Log.w(MyTracksConstants.TAG,
Log.w(Constants.TAG,
"Create might have failed. Trying to find created document.");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
Log.e(MyTracksConstants.TAG, "Sleep interrupted", e);
Log.e(Constants.TAG, "Sleep interrupted", e);
}
try {
spreadsheetId = docsHelper.requestSpreadsheetId(docListWrapper,
sheetTitle);
} catch (IOException e) {
Log.i(MyTracksConstants.TAG, "Failed create-failed lookup", e);
Log.i(Constants.TAG, "Failed create-failed lookup", e);
return false;
}
@@ -260,19 +260,19 @@ public class SendToDocs {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
Log.e(MyTracksConstants.TAG, "Sleep interrupted", e);
Log.e(Constants.TAG, "Sleep interrupted", e);
}
try {
spreadsheetId = docsHelper.requestSpreadsheetId(docListWrapper,
sheetTitle);
} catch (IOException e) {
Log.i(MyTracksConstants.TAG, "Failed create-failed relookup", e);
Log.i(Constants.TAG, "Failed create-failed relookup", e);
return false;
}
}
if (spreadsheetId == null) {
Log.i(MyTracksConstants.TAG,
Log.i(Constants.TAG,
"Creating new spreadsheet really failed.");
return false;
}
@@ -286,7 +286,7 @@ public class SendToDocs {
throw new IOException("Worksheet ID lookup returned empty");
}
} catch (IOException e) {
Log.i(MyTracksConstants.TAG, "Looking up worksheet id failed.", e);
Log.i(Constants.TAG, "Looking up worksheet id failed.", e);
return false;
}
@@ -294,9 +294,9 @@ public class SendToDocs {
docsHelper.addTrackRow(activity, trixAuth, spreadsheetId, worksheetId,
track, metricUnits);
Log.i(MyTracksConstants.TAG, "Done uploading to docs.");
Log.i(Constants.TAG, "Done uploading to docs.");
} catch (IOException e) {
Log.e(MyTracksConstants.TAG, "Unable to upload docs.", e);
Log.e(Constants.TAG, "Unable to upload docs.", e);
return false;
} finally {
if (androidClient != null) {
@@ -15,8 +15,7 @@
*/
package com.google.android.apps.mytracks.io;
import com.google.android.apps.mytracks.MyTracksConstants;
import com.google.android.apps.mytracks.MyTracksSettings;
import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.ProgressIndicator;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.content.Track;
@@ -25,8 +24,9 @@ import com.google.android.apps.mytracks.io.gdata.GDataWrapper;
import com.google.android.apps.mytracks.io.gdata.GDataWrapper.QueryFunction;
import com.google.android.apps.mytracks.stats.DoubleBuffer;
import com.google.android.apps.mytracks.stats.TripStatistics;
import com.google.android.apps.mytracks.util.MyTracksUtils;
import com.google.android.apps.mytracks.util.LocationUtils;
import com.google.android.apps.mytracks.util.StringUtils;
import com.google.android.apps.mytracks.util.SystemUtils;
import com.google.android.apps.mytracks.util.UnitConversions;
import com.google.android.maps.mytracks.R;
import com.google.api.client.googleapis.GoogleHeaders;
@@ -141,7 +141,7 @@ public class SendToFusionTables implements Runnable {
this.providerUtils = MyTracksProviderUtils.Factory.get(context);
GoogleHeaders headers = new GoogleHeaders();
headers.setApplicationName("Google-MyTracks-" + MyTracksUtils.getMyTracksVersion(context));
headers.setApplicationName("Google-MyTracks-" + SystemUtils.getMyTracksVersion(context));
headers.gdataVersion = GDATA_VERSION;
transport = new HttpTransport();
@@ -151,7 +151,7 @@ public class SendToFusionTables implements Runnable {
@Override
public void run() {
Log.d(MyTracksConstants.TAG, "Sending to Fusion tables: trackId = " + trackId);
Log.d(Constants.TAG, "Sending to Fusion tables: trackId = " + trackId);
doUpload();
}
@@ -204,7 +204,7 @@ public class SendToFusionTables implements Runnable {
}
statusMessageId = R.string.status_new_fusiontable_has_been_created;
Log.d(MyTracksConstants.TAG, "SendToFusionTables: Done: " + success);
Log.d(Constants.TAG, "SendToFusionTables: Done: " + success);
progressIndicator.setProgressValue(PROGRESS_COMPLETE);
} finally {
@@ -228,14 +228,14 @@ public class SendToFusionTables implements Runnable {
* @return true in case of success.
*/
private boolean createNewTable(Track track) {
Log.d(MyTracksConstants.TAG, "Creating a new fusion table.");
Log.d(Constants.TAG, "Creating a new fusion table.");
String query = "CREATE TABLE '" + sqlEscape(track.getName()) +
"' (name:STRING,description:STRING,geometry:LOCATION,marker:STRING)";
return runUpdate(query);
}
private boolean makeTableUnlisted(String tableId) {
Log.d(MyTracksConstants.TAG, "Setting visibility to unlisted.");
Log.d(Constants.TAG, "Setting visibility to unlisted.");
String query = "UPDATE TABLE " + tableId + " SET VISIBILITY = UNLISTED";
return runUpdate(query);
}
@@ -274,7 +274,7 @@ public class SendToFusionTables implements Runnable {
*/
private boolean createNewPoint(String name, String description, Location location,
String marker) {
Log.d(MyTracksConstants.TAG, "Creating a new row with a point.");
Log.d(Constants.TAG, "Creating a new row with a point.");
String query = "INSERT INTO " + tableId + " (name,description,geometry,marker) VALUES "
+ values(name, description, getKmlPoint(location), marker);
return runUpdate(query);
@@ -287,7 +287,7 @@ public class SendToFusionTables implements Runnable {
* @return true in case of success.
*/
private boolean createNewLineString(Track track) {
Log.d(MyTracksConstants.TAG, "Creating a new row with a point.");
Log.d(Constants.TAG, "Creating a new row with a point.");
String query = "INSERT INTO " + tableId
+ " (name,description,geometry) VALUES "
+ values(track.getName(), track.getDescription(), getKmlLineString(track));
@@ -296,7 +296,7 @@ public class SendToFusionTables implements Runnable {
private boolean uploadAllTrackPoints(final Track track, String originalDescription) {
SharedPreferences preferences = context.getSharedPreferences(MyTracksSettings.SETTINGS_NAME, 0);
SharedPreferences preferences = context.getSharedPreferences(Constants.SETTINGS_NAME, 0);
boolean metricUnits = true;
if (preferences != null) {
metricUnits = preferences.getBoolean(context.getString(R.string.metric_units_key), true);
@@ -305,7 +305,7 @@ public class SendToFusionTables implements Runnable {
Cursor locationsCursor = providerUtils.getLocationsCursor(track.getId(), 0, -1, false);
try {
if (!locationsCursor.moveToFirst()) {
Log.w(MyTracksConstants.TAG, "Unable to get any points to upload");
Log.w(Constants.TAG, "Unable to get any points to upload");
return false;
}
@@ -318,14 +318,14 @@ public class SendToFusionTables implements Runnable {
// Limit the number of elevation readings. Ideally we would want around 250.
int elevationSamplingFrequency =
Math.max(1, (int) (totalLocations / 250.0));
Log.d(MyTracksConstants.TAG,
Log.d(Constants.TAG,
"Using elevation sampling factor: " + elevationSamplingFrequency
+ " on " + totalLocations);
double totalDistance = 0;
Vector<Double> distances = new Vector<Double>();
Vector<Double> elevations = new Vector<Double>();
DoubleBuffer elevationBuffer = new DoubleBuffer(MyTracksConstants.ELEVATION_SMOOTHING_FACTOR);
DoubleBuffer elevationBuffer = new DoubleBuffer(Constants.ELEVATION_SMOOTHING_FACTOR);
List<Location> locations = new ArrayList<Location>(MAX_POINTS_PER_UPLOAD);
Location lastLocation = null;
@@ -344,7 +344,7 @@ public class SendToFusionTables implements Runnable {
}
// Add to the elevation profile.
if (loc != null && MyTracksUtils.isValidLocation(loc)) {
if (loc != null && LocationUtils.isValidLocation(loc)) {
// All points go into the smoothing buffer...
elevationBuffer.setNext(metricUnits ? loc.getAltitude()
: loc.getAltitude() * UnitConversions.M_TO_FT);
@@ -447,7 +447,7 @@ public class SendToFusionTables implements Runnable {
int numLocations = locations.size();
if (numLocations < 2) {
Log.d(MyTracksConstants.TAG, "Not preparing/uploading too few points");
Log.d(Constants.TAG, "Not preparing/uploading too few points");
totalLocationsUploaded += numLocations;
return true;
}
@@ -463,16 +463,16 @@ public class SendToFusionTables implements Runnable {
context.getString(R.string.part), totalSegmentsUploaded));
}
totalSegmentsUploaded++;
Log.d(MyTracksConstants.TAG,
Log.d(Constants.TAG,
"SendToFusionTables: Prepared feature for upload w/ "
+ splitTrack.getLocations().size() + " points.");
// Transmit tracks via GData feed:
// -------------------------------
Log.d(MyTracksConstants.TAG,
Log.d(Constants.TAG,
"SendToFusionTables: Uploading to table " + tableId + " w/ auth " + auth);
if (!uploadTrackPoints(splitTrack)) {
Log.e(MyTracksConstants.TAG, "Uploading failed");
Log.e(Constants.TAG, "Uploading failed");
return false;
}
}
@@ -518,7 +518,7 @@ public class SendToFusionTables implements Runnable {
// Close up the last segment.
prepareTrackSegment(segment, splitTracks);
Log.d(MyTracksConstants.TAG,
Log.d(Constants.TAG,
"MyTracksSendToFusionTables: Starting new track segment...");
startNewTrackSegment = false;
segment = new Track();
@@ -566,12 +566,12 @@ public class SendToFusionTables implements Runnable {
* Decimate to 2 meter precision. Fusion tables doesn't like too many
* points:
*/
MyTracksUtils.decimate(segment, 2.0);
LocationUtils.decimate(segment, 2.0);
/* If the track still has > 2500 points, split it in pieces: */
final int maxPoints = 2500;
if (segment.getLocations().size() > maxPoints) {
splitTracks.addAll(MyTracksUtils.split(segment, maxPoints));
splitTracks.addAll(LocationUtils.split(segment, maxPoints));
} else if (segment.getLocations().size() >= 2) {
splitTracks.add(segment);
}
@@ -581,7 +581,7 @@ public class SendToFusionTables implements Runnable {
int numLocations = splitTrack.getLocations().size();
if (numLocations < 2) {
// Need at least two points for a polyline:
Log.w(MyTracksConstants.TAG, "Not uploading too few points");
Log.w(Constants.TAG, "Not uploading too few points");
return true;
}
return createNewLineString(splitTrack);
@@ -604,14 +604,14 @@ public class SendToFusionTables implements Runnable {
try {
c = providerUtils.getWaypointsCursor(
track.getId(), 0,
MyTracksConstants.MAX_LOADED_WAYPOINTS_POINTS);
Constants.MAX_LOADED_WAYPOINTS_POINTS);
if (c != null) {
if (c.moveToFirst()) {
// This will skip the 1st waypoint (it carries the stats for the
// last segment).
while (c.moveToNext()) {
Waypoint wpt = providerUtils.createWaypoint(c);
Log.d(MyTracksConstants.TAG, "SendToFusionTables: Creating waypoint.");
Log.d(Constants.TAG, "SendToFusionTables: Creating waypoint.");
success = createNewPoint(wpt.getName(), wpt.getDescription(), wpt.getLocation(),
MARKER_TYPE_WAYPOINT);
if (!success) {
@@ -621,7 +621,7 @@ public class SendToFusionTables implements Runnable {
}
}
if (!success) {
Log.w(MyTracksConstants.TAG, "SendToFusionTables: upload waypoints failed.");
Log.w(Constants.TAG, "SendToFusionTables: upload waypoints failed.");
}
return success;
} finally {
@@ -656,7 +656,7 @@ public class SendToFusionTables implements Runnable {
wrapper.setAuthManager(auth);
wrapper.setRetryOnAuthFailure(true);
wrapper.setClient(transport);
Log.d(MyTracksConstants.TAG, "GData connection prepared: " + this.auth);
Log.d(Constants.TAG, "GData connection prepared: " + this.auth);
wrapper.runQuery(new QueryFunction<HttpTransport>() {
@Override
public void query(HttpTransport client)
@@ -671,7 +671,7 @@ public class SendToFusionTables implements Runnable {
isc.inputStream = new ByteArrayInputStream(Strings.toBytesUtf8(sql));
request.content = isc;
Log.d(MyTracksConstants.TAG, "Running update query " + url.toString() + ": " + sql);
Log.d(Constants.TAG, "Running update query " + url.toString() + ": " + sql);
HttpResponse response;
try {
response = request.execute();
@@ -686,12 +686,12 @@ public class SendToFusionTables implements Runnable {
String[] lines = s.split(Strings.LINE_SEPARATOR);
if (lines[0].equals("tableid")) {
tableId = lines[1];
Log.d(MyTracksConstants.TAG, "tableId = " + tableId);
Log.d(Constants.TAG, "tableId = " + tableId);
} else {
Log.w(MyTracksConstants.TAG, "Unrecognized response: " + lines[0]);
Log.w(Constants.TAG, "Unrecognized response: " + lines[0]);
}
} else {
Log.d(MyTracksConstants.TAG, "Query failed: " + response.statusMessage + " (" +
Log.d(Constants.TAG, "Query failed: " + response.statusMessage + " (" +
response.statusCode + ")");
throw new GDataWrapper.HttpException(response.statusCode, response.statusMessage);
}
@@ -0,0 +1,455 @@
/*
* 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;
import static com.google.android.apps.mytracks.Constants.TAG;
import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.ProgressIndicator;
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.io.mymaps.MapsFacade;
import com.google.android.apps.mytracks.stats.DoubleBuffer;
import com.google.android.apps.mytracks.stats.TripStatistics;
import com.google.android.apps.mytracks.util.LocationUtils;
import com.google.android.apps.mytracks.util.StringUtils;
import com.google.android.apps.mytracks.util.UnitConversions;
import com.google.android.maps.mytracks.R;
import android.app.Activity;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.location.Location;
import android.util.Log;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;
/**
* A helper class used to transmit tracks to Google MyMaps.
* A new instance should be used for each upload.
*
* IMPORTANT: while this code is Apache-licensed, please notice that usage of
* the Google Maps servers through this API is only allowed for the My Tracks
* application. Other applications looking to upload maps data should look
* into using the Fusion Tables API.
*
* @author Leif Hendrik Wilden
*/
public class SendToMyMaps implements Runnable {
public static final String NEW_MAP_ID = "new";
private static final int MAX_POINTS_PER_UPLOAD = 2048;
private final Activity context;
private final AuthManager auth;
private final long trackId;
private final ProgressIndicator progressIndicator;
private final OnSendCompletedListener onCompletion;
private final StringUtils stringUtils;
private final MyTracksProviderUtils providerUtils;
private String mapId;
private MapsFacade mapsClient;
// Progress status
private int totalLocationsRead;
private int totalLocationsPrepared;
private int totalLocationsUploaded;
private int totalLocations;
private int totalSegmentsUploaded;
public interface OnSendCompletedListener {
void onSendCompleted(String mapId, boolean success, int statusMessage);
}
public SendToMyMaps(Activity context, String mapId, AuthManager auth,
long trackId, ProgressIndicator progressIndicator,
OnSendCompletedListener onCompletion) {
this.context = context;
this.mapId = mapId;
this.auth = auth;
this.trackId = trackId;
this.progressIndicator = progressIndicator;
this.onCompletion = onCompletion;
this.stringUtils = new StringUtils(context);
this.providerUtils = MyTracksProviderUtils.Factory.get(context);
}
@Override
public void run() {
Log.d(TAG, "Sending to MyMaps: trackId = " + trackId);
doUpload();
}
private void doUpload() {
int statusMessageId = R.string.error_sending_to_mymap;
boolean success = true;
try {
progressIndicator.setProgressValue(1);
progressIndicator.setProgressMessage(
R.string.progress_message_reading_track);
// Get the track meta-data
Track track = providerUtils.getTrack(trackId);
String originalDescription = track.getDescription();
track.setDescription("<p>" + track.getDescription() + "</p><p>"
+ stringUtils.generateTrackDescription(track, null, null) + "</p>");
mapsClient = new MapsFacade(context, auth);
// Create a new map if necessary:
boolean isNewMap = mapId.equals(NEW_MAP_ID);
if (isNewMap) {
SharedPreferences preferences = context.getSharedPreferences(
Constants.SETTINGS_NAME, 0);
boolean mapPublic = true;
if (preferences != null) {
mapPublic = preferences.getBoolean(
context.getString(R.string.default_map_public_key), true);
}
progressIndicator.setProgressMessage(
R.string.progress_message_creating_map);
StringBuilder mapIdBuilder = new StringBuilder();
success = mapsClient.createNewMap(
track.getName(), track.getCategory(), originalDescription, mapPublic, mapIdBuilder);
mapId = mapIdBuilder.toString();
}
// Upload all of the segments of the track plus start/end markers
if (success) {
success = uploadAllTrackPoints(track, originalDescription);
}
// Put waypoints.
if (success) {
Cursor c = providerUtils.getWaypointsCursor(
track.getId(), 0,
Constants.MAX_LOADED_WAYPOINTS_POINTS);
if (c != null) {
try {
if (c.getCount() > 1 && c.moveToFirst()) {
// This will skip the 1st waypoint (it carries the stats for the
// last segment).
ArrayList<Waypoint> waypoints = new ArrayList<Waypoint>(c.getCount() - 1);
while (c.moveToNext()) {
Waypoint wpt = providerUtils.createWaypoint(c);
waypoints.add(wpt);
}
success = mapsClient.uploadWaypoints(mapId, waypoints);
}
} finally {
c.close();
}
} else {
success = false;
}
if (!success) {
Log.w(TAG, "SendToMyMaps: upload waypoints failed.");
}
}
if (success) {
statusMessageId = isNewMap
? R.string.status_new_mymap_has_been_created
: R.string.status_tracks_have_been_uploaded;
}
Log.d(TAG, "SendToMyMaps: Done: " + success);
progressIndicator.setProgressValue(100);
} finally {
if (mapsClient != null) {
mapsClient.cleanUp();
}
final boolean finalSuccess = success;
final int finalStatusMessageId = statusMessageId;
context.runOnUiThread(new Runnable() {
public void run() {
if (onCompletion != null) {
onCompletion.onSendCompleted(
mapId, finalSuccess, finalStatusMessageId);
}
}
});
}
}
private boolean uploadAllTrackPoints(
final Track track, String originalDescription) {
SharedPreferences preferences = context.getSharedPreferences(
Constants.SETTINGS_NAME, 0);
boolean metricUnits = true;
if (preferences != null) {
metricUnits =
preferences.getBoolean(context.getString(R.string.metric_units_key),
true);
}
Cursor locationsCursor =
providerUtils.getLocationsCursor(track.getId(), 0, -1, false);
try {
if (!locationsCursor.moveToFirst()) {
Log.w(TAG, "Unable to get any points to upload");
return false;
}
totalLocationsRead = 0;
totalLocationsPrepared = 0;
totalLocationsUploaded = 0;
totalLocations = locationsCursor.getCount();
totalSegmentsUploaded = 0;
// Limit the number of elevation readings. Ideally we would want around 250.
int elevationSamplingFrequency =
Math.max(1, (int) (totalLocations / 250.0));
Log.d(TAG,
"Using elevation sampling factor: " + elevationSamplingFrequency
+ " on " + totalLocations);
double totalDistance = 0;
Vector<Double> distances = new Vector<Double>();
Vector<Double> elevations = new Vector<Double>();
DoubleBuffer elevationBuffer =
new DoubleBuffer(Constants.ELEVATION_SMOOTHING_FACTOR);
List<Location> locations = new ArrayList<Location>(MAX_POINTS_PER_UPLOAD);
progressIndicator.setProgressMessage(
R.string.progress_message_reading_track);
Location lastLocation = null;
do {
if (totalLocationsRead % 100 == 0) {
updateProgress();
}
Location loc = providerUtils.createLocation(locationsCursor);
locations.add(loc);
if (totalLocationsRead == 0) {
// Put a marker at the first point of the first valid segment:
mapsClient.uploadMarker(mapId, track.getName(), track.getDescription(), loc, true);
}
// Add to the elevation profile.
if (loc != null && LocationUtils.isValidLocation(loc)) {
// All points go into the smoothing buffer...
elevationBuffer.setNext(metricUnits ? loc.getAltitude()
: loc.getAltitude() * UnitConversions.M_TO_FT);
if (lastLocation != null) {
double dist = lastLocation.distanceTo(loc);
totalDistance += dist;
}
// ...but only a few points are really used to keep the url short.
if (totalLocationsRead % elevationSamplingFrequency == 0) {
distances.add(totalDistance);
elevations.add(elevationBuffer.getAverage());
}
}
// If the location was not valid, it's a segment split, so make sure the
// distance between the previous segment and the new one is not accounted
// for in the next iteration.
lastLocation = loc;
// Every now and then, upload the accumulated points
if (totalLocationsRead % MAX_POINTS_PER_UPLOAD
== MAX_POINTS_PER_UPLOAD - 1) {
if (!prepareAndUploadPoints(track, locations)) {
return false;
}
}
totalLocationsRead++;
} while (locationsCursor.moveToNext());
// Do a final upload with what's left
if (!prepareAndUploadPoints(track, locations)) {
return false;
}
// Put an end marker at the last point of the last valid segment:
if (lastLocation != null) {
track.setDescription("<p>" + originalDescription + "</p><p>"
+ stringUtils.generateTrackDescription(
track, distances, elevations)
+ "</p>");
return mapsClient.uploadMarker(mapId, track.getName(), track.getDescription(),
lastLocation, false);
}
return true;
} finally {
locationsCursor.close();
}
}
private boolean prepareAndUploadPoints(Track track, List<Location> locations) {
progressIndicator.setProgressMessage(
R.string.progress_message_preparing_track);
updateProgress();
int numLocations = locations.size();
if (numLocations < 2) {
Log.d(TAG, "Not preparing/uploading too few points");
totalLocationsUploaded += numLocations;
return true;
}
// Prepare/pre-process the points
ArrayList<Track> splitTracks = prepareLocations(track, locations);
// Start uploading them
progressIndicator.setProgressMessage(
R.string.progress_message_sending_mymaps);
for (Track splitTrack : splitTracks) {
if (totalSegmentsUploaded > 1) {
splitTrack.setName(splitTrack.getName() + " "
+ String.format(
context.getString(R.string.part), totalSegmentsUploaded));
}
totalSegmentsUploaded++;
Log.d(TAG,
"SendToMyMaps: Prepared feature for upload w/ "
+ splitTrack.getLocations().size() + " points.");
// Transmit tracks via GData feed:
// -------------------------------
Log.d(TAG,
"SendToMyMaps: Uploading to map " + mapId + " w/ auth " + auth);
if (!mapsClient.uploadTrackPoints(mapId, splitTrack.getName(), splitTrack.getLocations())) {
Log.e(TAG, "Uploading failed");
return false;
}
}
locations.clear();
totalLocationsUploaded += numLocations;
updateProgress();
return true;
}
/**
* Prepares a buffer of locations for transmission to google maps.
*
* @param track the original track with meta data
* @param buffer a buffer of locations on the track
* @return an array of tracks each with a sub section of the points in the
* original buffer
*/
private ArrayList<Track> prepareLocations(
Track track, Iterable<Location> locations) {
ArrayList<Track> splitTracks = new ArrayList<Track>();
// Create segments from each full track:
Track segment = new Track();
TripStatistics segmentStats = segment.getStatistics();
TripStatistics trackStats = track.getStatistics();
segment.setId(track.getId());
segment.setName(track.getName());
segment.setDescription(/* track.getDescription() */ "");
segment.setCategory(track.getCategory());
segmentStats.setStartTime(trackStats.getStartTime());
segmentStats.setStopTime(trackStats.getStopTime());
boolean startNewTrackSegment = false;
for (Location loc : locations) {
if (totalLocationsPrepared % 100 == 0) {
updateProgress();
}
if (loc.getLatitude() > 90) {
startNewTrackSegment = true;
}
if (startNewTrackSegment) {
// Close up the last segment.
prepareTrackSegment(segment, splitTracks);
Log.d(TAG,
"MyTracksSendToMyMaps: Starting new track segment...");
startNewTrackSegment = false;
segment = new Track();
segment.setId(track.getId());
segment.setName(track.getName());
segment.setDescription(/* track.getDescription() */ "");
segment.setCategory(track.getCategory());
}
if (loc.getLatitude() <= 90) {
segment.addLocation(loc);
if (segmentStats.getStartTime() < 0) {
segmentStats.setStartTime(loc.getTime());
}
}
totalLocationsPrepared++;
}
prepareTrackSegment(segment, splitTracks);
return splitTracks;
}
/**
* Prepares a track segment for sending to google maps.
* The main steps are:
* - correcting end time
* - decimating locations
* - splitting into smaller tracks.
*
* The final track pieces will be put in the array list splitTracks.
*
* @param segment the original segment of the track
* @param splitTracks an array of smaller track segments
*/
private void prepareTrackSegment(
Track segment, ArrayList<Track> splitTracks) {
TripStatistics segmentStats = segment.getStatistics();
if (segmentStats.getStopTime() < 0
&& segment.getLocations().size() > 0) {
segmentStats.setStopTime(segment.getLocations().size() - 1);
}
/*
* Decimate to 2 meter precision. Mapshop doesn't like too many
* points:
*/
LocationUtils.decimate(segment, 2.0);
/* It the track still has > 500 points, split it in pieces: */
if (segment.getLocations().size() > 500) {
splitTracks.addAll(LocationUtils.split(segment, 500));
} else if (segment.getLocations().size() >= 2) {
splitTracks.add(segment);
}
}
/**
* Sets the current upload progress.
*/
private void updateProgress() {
// The percent of the total that represents the completed part of this
// segment.
int totalPercentage =
(totalLocationsRead + totalLocationsPrepared + totalLocationsUploaded)
/ (totalLocations * 3);
totalPercentage = Math.min(99, totalPercentage);
progressIndicator.setProgressValue(totalPercentage);
}
}
@@ -16,7 +16,7 @@
package com.google.android.apps.mytracks.io.backup;
import com.google.android.apps.mytracks.MyTracks;
import com.google.android.apps.mytracks.MyTracksConstants;
import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.util.FileUtils;
import com.google.android.maps.mytracks.R;
@@ -97,7 +97,7 @@ public class BackupActivityHelper {
backup.writeToDefaultFile();
showToast(R.string.io_write_finished);
} catch (IOException e) {
Log.e(MyTracksConstants.TAG, "Failed to write backup", e);
Log.e(Constants.TAG, "Failed to write backup", e);
showToast(R.string.io_write_failed);
} finally {
dismissDialog(progressDialog);
@@ -199,7 +199,7 @@ public class BackupActivityHelper {
backup.restoreFromDate(date);
showToast(R.string.io_read_finished);
} catch (IOException e) {
Log.e(MyTracksConstants.TAG, "Failed to restore backup", e);
Log.e(Constants.TAG, "Failed to restore backup", e);
showToast(R.string.io_read_failed);
} finally {
dismissDialog(progressDialog);
@@ -15,8 +15,7 @@
*/
package com.google.android.apps.mytracks.io.backup;
import com.google.android.apps.mytracks.MyTracksConstants;
import com.google.android.apps.mytracks.MyTracksSettings;
import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.content.TrackPointsColumns;
import com.google.android.apps.mytracks.content.TracksColumns;
import com.google.android.apps.mytracks.content.WaypointsColumns;
@@ -88,7 +87,7 @@ class ExternalFileBackup {
private File getBackupsDirectory(boolean create) {
String dirName = fileUtils.buildExternalDirectoryPath(BACKUPS_SUBDIR);
final File dir = new File(dirName);
Log.d(MyTracksConstants.TAG, "Dir: " + dir.getAbsolutePath());
Log.d(Constants.TAG, "Dir: " + dir.getAbsolutePath());
if (create) {
// Try to create - if that fails, return null
return fileUtils.ensureDirectoryExists(dir) ? dir : null;
@@ -147,7 +146,7 @@ class ExternalFileBackup {
* Synchronously writes a backup to the given file.
*/
private void writeToFile(File outputFile) throws IOException {
Log.d(MyTracksConstants.TAG,
Log.d(Constants.TAG,
"Writing backup to file " + outputFile.getAbsolutePath());
// Create all the auxiliary classes that will do the writing
@@ -201,7 +200,7 @@ class ExternalFileBackup {
// Dump preferences
SharedPreferences preferences =
context.getSharedPreferences(MyTracksSettings.SETTINGS_NAME, 0);
context.getSharedPreferences(Constants.SETTINGS_NAME, 0);
preferencesHelper.exportPreferences(preferences, outWriter);
} catch (IOException e) {
// We tried to delete the partially created file, but do nothing
@@ -219,7 +218,7 @@ class ExternalFileBackup {
* Synchronously restores the backup from the given file.
*/
private void restoreFromFile(File inputFile) throws IOException {
Log.d(MyTracksConstants.TAG,
Log.d(Constants.TAG,
"Restoring from file " + inputFile.getAbsolutePath());
PreferenceBackupHelper preferencesHelper = new PreferenceBackupHelper();
@@ -253,7 +252,7 @@ class ExternalFileBackup {
// Restore preferences
SharedPreferences preferences =
context.getSharedPreferences(MyTracksSettings.SETTINGS_NAME, 0);
context.getSharedPreferences(Constants.SETTINGS_NAME, 0);
preferencesHelper.importPreferences(reader, preferences);
} finally {
compressedStream.close();
@@ -15,8 +15,7 @@
*/
package com.google.android.apps.mytracks.io.backup;
import com.google.android.apps.mytracks.MyTracksConstants;
import com.google.android.apps.mytracks.MyTracksSettings;
import com.google.android.apps.mytracks.Constants;
import android.app.backup.BackupAgent;
import android.app.backup.BackupDataInput;
@@ -40,12 +39,12 @@ public class MyTracksBackupAgent extends BackupAgent {
@Override
public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
ParcelFileDescriptor newState) throws IOException {
Log.i(MyTracksConstants.TAG, "Performing backup");
Log.i(Constants.TAG, "Performing backup");
SharedPreferences preferences = this.getSharedPreferences(
MyTracksSettings.SETTINGS_NAME, 0);
Constants.SETTINGS_NAME, 0);
backupPreferences(data, preferences);
Log.i(MyTracksConstants.TAG, "Backup complete");
Log.i(Constants.TAG, "Backup complete");
}
private void backupPreferences(BackupDataOutput data,
@@ -63,18 +62,18 @@ public class MyTracksBackupAgent extends BackupAgent {
@Override
public void onRestore(BackupDataInput data, int appVersionCode,
ParcelFileDescriptor newState) throws IOException {
Log.i(MyTracksConstants.TAG, "Restoring from backup");
Log.i(Constants.TAG, "Restoring from backup");
while (data.readNextHeader()) {
String key = data.getKey();
Log.d(MyTracksConstants.TAG, "Restoring entity " + key);
Log.d(Constants.TAG, "Restoring entity " + key);
if (key.equals(PREFERENCES_ENTITY)) {
restorePreferences(data);
} else {
Log.e(MyTracksConstants.TAG, "Found unknown backup entity: " + key);
Log.e(Constants.TAG, "Found unknown backup entity: " + key);
data.skipEntityData();
}
}
Log.i(MyTracksConstants.TAG, "Done restoring from backup");
Log.i(Constants.TAG, "Done restoring from backup");
}
/**
@@ -92,7 +91,7 @@ public class MyTracksBackupAgent extends BackupAgent {
}
SharedPreferences preferences = this.getSharedPreferences(
MyTracksSettings.SETTINGS_NAME, 0);
Constants.SETTINGS_NAME, 0);
PreferenceBackupHelper importer = createPreferenceBackupHelper();
importer.importPreferences(dataBuffer, preferences);
}
@@ -15,7 +15,7 @@
*/
package com.google.android.apps.mytracks.io.docs;
import com.google.android.apps.mytracks.MyTracksConstants;
import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.content.Track;
import com.google.android.apps.mytracks.io.AuthManager;
import com.google.android.apps.mytracks.io.gdata.GDataWrapper;
@@ -144,7 +144,7 @@ public class DocsHelper {
String id = result.substring(
idStringStart + DOCS_SPREADSHEET_URL.length(), idTagCloseIndex);
Log.i(MyTracksConstants.TAG, "Created new spreadsheet: " + id);
Log.i(Constants.TAG, "Created new spreadsheet: " + id);
idSaver.set(id);
}});
@@ -184,7 +184,7 @@ public class DocsHelper {
while (listParser.hasMoreData()) {
Entry entry = listParser.readNextEntry(null);
String entryTitle = entry.getTitle();
Log.i(MyTracksConstants.TAG, "Found docs entry: " + entryTitle);
Log.i(Constants.TAG, "Found docs entry: " + entryTitle);
if (entryTitle.equals(title)) {
String entryId = entry.getId();
int lastSlash = entryId.lastIndexOf('/');
@@ -233,7 +233,7 @@ public class DocsHelper {
trixWrapper.getAuthManager().getAuthToken());
sheetParser.init();
if (!sheetParser.hasMoreData()) {
Log.i(MyTracksConstants.TAG, "Found no worksheets");
Log.i(Constants.TAG, "Found no worksheets");
return;
}
@@ -308,7 +308,7 @@ public class DocsHelper {
if (track.getMapId().length() > 0) {
tagBuilder.append("map", String.format("%s?msa=0&msid=%s",
MyTracksConstants.MAPSHOP_BASE_URL, track.getMapId()));
Constants.MAPSHOP_BASE_URL, track.getMapId()));
}
String postText = new StringBuilder()
@@ -319,14 +319,14 @@ public class DocsHelper {
.append("</entry>")
.toString();
Log.i(MyTracksConstants.TAG,
Log.i(Constants.TAG,
"Inserting at: " + spreadsheetId + " => " + worksheetUri);
Log.i(MyTracksConstants.TAG, postText);
Log.i(Constants.TAG, postText);
writeRowData(trixAuth, worksheetUri, postText);
Log.i(MyTracksConstants.TAG, "Post finished.");
Log.i(Constants.TAG, "Post finished.");
}
/**
@@ -358,7 +358,7 @@ public class DocsHelper {
String line;
while ((line = rd.readLine()) != null) {
// Process line.
Log.i(MyTracksConstants.TAG, "r: " + line);
Log.i(Constants.TAG, "r: " + line);
}
wr.close();
rd.close();
@@ -13,11 +13,11 @@
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks.io;
package com.google.android.apps.mytracks.io.file;
import com.google.android.apps.mytracks.content.Track;
import com.google.android.apps.mytracks.content.Waypoint;
import com.google.android.apps.mytracks.io.TrackWriterFactory.TrackFileFormat;
import com.google.android.apps.mytracks.io.file.TrackWriterFactory.TrackFileFormat;
import android.location.Location;
@@ -13,13 +13,13 @@
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks.io;
package com.google.android.apps.mytracks.io.file;
import com.google.android.apps.mytracks.MyTracksConstants;
import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.content.Track;
import com.google.android.apps.mytracks.stats.TripStatisticsBuilder;
import com.google.android.apps.mytracks.util.MyTracksUtils;
import com.google.android.apps.mytracks.util.LocationUtils;
import com.google.android.apps.mytracks.util.StringUtils;
import android.location.Location;
@@ -174,7 +174,7 @@ public class GpxImporter extends DefaultHandler {
parser.parse(is, handler);
long end = System.currentTimeMillis();
Log.d(MyTracksConstants.TAG, "Total import time: " + (end - start) + "ms");
Log.d(Constants.TAG, "Total import time: " + (end - start) + "ms");
trackIds = handler.getImportedTrackIds();
} finally {
@@ -362,7 +362,7 @@ public class GpxImporter extends DefaultHandler {
* @throws SAXException - thrown if track point is invalid
*/
private void onTrackPointElementEnd() throws SAXException {
if (MyTracksUtils.isValidLocation(location)) {
if (LocationUtils.isValidLocation(location)) {
if (statsBuilder == null) {
// first point did not have a time, start stats builder without it
statsBuilder = new TripStatisticsBuilder(0);
@@ -462,7 +462,7 @@ public class GpxImporter extends DefaultHandler {
// check for negative time change
if (timeDifference < 0) {
Log.w(MyTracksConstants.TAG, "Found negative time change.");
Log.w(Constants.TAG, "Found negative time change.");
} else {
// We don't have a speed and bearing in GPX, make something up from
@@ -1,23 +1,23 @@
/*
* 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;
package com.google.android.apps.mytracks.io.file;
import com.google.android.apps.mytracks.content.Track;
import com.google.android.apps.mytracks.content.Waypoint;
import com.google.android.apps.mytracks.io.TrackWriterFactory.TrackFileFormat;
import com.google.android.apps.mytracks.io.file.TrackWriterFactory.TrackFileFormat;
import com.google.android.apps.mytracks.util.StringUtils;
import android.location.Location;
@@ -25,9 +25,10 @@ import android.location.Location;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.nio.charset.Charset;
import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.text.DecimalFormat;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
/**
@@ -36,22 +37,33 @@ import java.util.TimeZone;
* @author Sandor Dornbush
*/
public class GpxTrackWriter implements TrackFormatWriter {
private static final String TIMESTAMP_FORMAT = "yyyy-MM-dd'T'HH:mm:ss'Z'";
private static final int LATLONG_FORMAT = Location.FORMAT_DEGREES;
private static final DecimalFormat ELEVATION_FORMATTER =
new DecimalFormat("#.#");
private static final SimpleDateFormat TIMESTAMP_FORMATTER =
new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
static {
TIMESTAMP_FORMATTER.setTimeZone(TimeZone.getTimeZone("UTC"));
}
private final NumberFormat elevationFormatter;
private final NumberFormat coordinateFormatter;
private final SimpleDateFormat timestampFormatter;
private PrintWriter pw = null;
private Track track;
public GpxTrackWriter() {
// GPX readers expect to see fractional numbers with US-style punctuation.
// That is, they want periods for decimal points, rather than commas.
elevationFormatter = NumberFormat.getInstance(Locale.US);
elevationFormatter.setMaximumFractionDigits(1);
elevationFormatter.setGroupingUsed(false);
coordinateFormatter = NumberFormat.getInstance(Locale.US);
coordinateFormatter.setMaximumFractionDigits(5);
coordinateFormatter.setMaximumIntegerDigits(3);
coordinateFormatter.setGroupingUsed(false);
timestampFormatter = new SimpleDateFormat(TIMESTAMP_FORMAT);
timestampFormatter.setTimeZone(TimeZone.getTimeZone("UTC"));
}
private String formatLocation(Location l) {
return "lat=\"" + Location.convert(l.getLatitude(), LATLONG_FORMAT)
+ "\" lon=\"" + Location.convert(l.getLongitude(), LATLONG_FORMAT) + "\"";
return "lat=\"" + coordinateFormatter.format(l.getLatitude())
+ "\" lon=\"" + coordinateFormatter.format(l.getLongitude()) + "\"";
}
@Override
@@ -129,8 +141,8 @@ public class GpxTrackWriter implements TrackFormatWriter {
if (pw != null) {
pw.println("<trkpt " + formatLocation(l) + ">");
Date d = new Date(l.getTime());
pw.println("<ele>" + ELEVATION_FORMATTER.format(l.getAltitude()) + "</ele>");
pw.println("<time>" + TIMESTAMP_FORMATTER.format(d) + "</time>");
pw.println("<ele>" + elevationFormatter.format(l.getAltitude()) + "</ele>");
pw.println("<time>" + timestampFormatter.format(d) + "</time>");
pw.println("</trkpt>");
}
}
@@ -149,8 +161,8 @@ public class GpxTrackWriter implements TrackFormatWriter {
Location l = waypoint.getLocation();
if (l != null) {
pw.println("<wpt " + formatLocation(l) + ">");
pw.println("<ele>" + ELEVATION_FORMATTER.format(l.getAltitude()) + "</ele>");
pw.println("<time>" + TIMESTAMP_FORMATTER.format(l.getTime()) + "</time>");
pw.println("<ele>" + elevationFormatter.format(l.getAltitude()) + "</ele>");
pw.println("<time>" + timestampFormatter.format(l.getTime()) + "</time>");
pw.println("<name>" + StringUtils.stringAsCData(waypoint.getName())
+ "</name>");
pw.println("<desc>"
@@ -13,11 +13,11 @@
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks.io;
package com.google.android.apps.mytracks.io.file;
import com.google.android.apps.mytracks.content.Track;
import com.google.android.apps.mytracks.content.Waypoint;
import com.google.android.apps.mytracks.io.TrackWriterFactory.TrackFileFormat;
import com.google.android.apps.mytracks.io.file.TrackWriterFactory.TrackFileFormat;
import com.google.android.apps.mytracks.util.StringUtils;
import android.content.Context;
@@ -1,27 +1,29 @@
/*
* 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.io;
package com.google.android.apps.mytracks.io.file;
import com.google.android.apps.mytracks.content.MyTracksLocation;
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.content.Sensor.SensorDataSet;
import com.google.android.apps.mytracks.io.TrackWriterFactory.TrackFileFormat;
import com.google.android.apps.mytracks.io.file.TrackWriterFactory.TrackFileFormat;
import com.google.android.apps.mytracks.util.SystemUtils;
import android.content.Context;
import android.location.Location;
import android.os.Build;
@@ -30,6 +32,7 @@ import java.io.PrintWriter;
import java.nio.charset.Charset;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
/**
@@ -37,20 +40,35 @@ import java.util.TimeZone;
* As defined by:
* http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2
*
* The TCX file written by this class has been verified as compatible with
* Garmin Training Center 3.5.3.
*
* @author Sandor Dornbush
*/
public class TcxTrackWriter implements TrackFormatWriter {
protected static final String TIMESTAMP_FORMAT = "yyyy-MM-dd'T'HH:mm:ss'Z'";
// These are the only sports allowed by the TCX v2 specification for fields
// of type Sport_t.
private static final String TCX_SPORT_BIKING = "Biking";
private static final String TCX_SPORT_RUNNING = "Running";
private static final String TCX_SPORT_OTHER = "Other";
// Values for fields of type Build_t/Type.
private static final String TCX_TYPE_RELEASE = "Release";
private static final String TCX_TYPE_INTERNAL = "Internal";
private final SimpleDateFormat timestampFormatter;
private final Context context;
private PrintWriter pw = null;
private Track track;
static final SimpleDateFormat TIMESTAMP_FORMAT =
new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
static {
TIMESTAMP_FORMAT.setTimeZone(TimeZone.getTimeZone("UTC"));
}
public TcxTrackWriter(Context context) {
this.context = context;
public TcxTrackWriter() {
timestampFormatter = new SimpleDateFormat(TIMESTAMP_FORMAT);
timestampFormatter.setTimeZone(TimeZone.getTimeZone("UTC"));
}
@Override
@@ -93,16 +111,13 @@ public class TcxTrackWriter implements TrackFormatWriter {
if (pw == null) {
return;
}
String startTime = timestampFormatter.format(track.getStatistics().getStartTime());
pw.println(" <Activities>");
pw.print(" <Activity Sport=\"");
if (track.getCategory() != null) {
pw.print(track.getCategory());
}
pw.println("\">");
pw.print(" <Id>");
pw.print(TIMESTAMP_FORMAT.format(track.getStatistics().getStartTime()));
pw.println("</Id>");
pw.println(" <Lap>");
pw.format(" <Activity Sport=\"%s\">\n", categoryToTcxSport(track.getCategory()));
pw.format(" <Id>%s</Id>\n", startTime);
pw.format(" <Lap StartTime=\"%s\">\n", startTime);
pw.print(" <TotalTimeSeconds>");
pw.print(track.getStatistics().getTotalTime() / 1000);
pw.println("</TotalTimeSeconds>");
@@ -113,7 +128,7 @@ public class TcxTrackWriter implements TrackFormatWriter {
// Calories are a required element just put in 0.
pw.print("<Calories>0</Calories>");
pw.println("<Intensity>Active</Intensity>");
pw.println("<TriggerMethod>Manual</TriggerMethod>)");
pw.println("<TriggerMethod>Manual</TriggerMethod>");
}
@Override
@@ -130,7 +145,7 @@ public class TcxTrackWriter implements TrackFormatWriter {
}
pw.println(" <Trackpoint>");
Date d = new Date(location.getTime());
pw.println(" <Time>" + TIMESTAMP_FORMAT.format(d) + "</Time>");
pw.println(" <Time>" + timestampFormatter.format(d) + "</Time>");
pw.println(" <Position>");
pw.print(" <LatitudeDegrees>");
@@ -194,10 +209,18 @@ public class TcxTrackWriter implements TrackFormatWriter {
}
pw.println(" </Lap>");
pw.print(" <Creator xsi:type=\"Device_t\">");
pw.print("<Name>");
pw.print(Build.MODEL);
pw.print("</Name>");
pw.println("</Creator>)");
pw.format("<Name>%s</Name>\n", Build.MODEL);
// The following code is correct. ID is inconsistently capitalized in the
// TCX schema.
pw.println("<UnitId>0</UnitId>");
pw.println("<ProductID>0</ProductID>");
pw.println("<Version>");
pw.println("<VersionMajor>0</VersionMajor>");
pw.println("<VersionMinor>0</VersionMinor>");
pw.println("</Version>");
pw.println("</Creator>");
pw.println(" </Activity>");
pw.println(" </Activities>");
}
@@ -207,8 +230,31 @@ public class TcxTrackWriter implements TrackFormatWriter {
if (pw == null) {
return;
}
pw.print(" <Author xsi:type=\"Application_t\">");
pw.print("<Name>My Tracks by Google</Name>");
pw.println(" <Author xsi:type=\"Application_t\">");
// We put the version in the name because there isn't a better place for
// it. The TCX schema tightly defined the Version tag, so we can't put it
// there. They've similarly constrained the PartNumber tag, so it can't go
// there either.
pw.format("<Name>My Tracks %s by Google</Name>\n", SystemUtils.getMyTracksVersion(context));
pw.println("<Build>");
// The TCX spec for the Version tag is too strict to allow us to use our
// user-visible version number, so we use our version code instead. We
// also set the minor version to 1 if this is a development build to
// signify that this build is newer than the one associated with the
// version code given in VersionMajor.
pw.println("<Version>");
pw.format("<VersionMajor>%s</VersionMajor>\n", SystemUtils.getMyTracksVersion(context));
pw.format("<VersionMinor>%d</VersionMinor>\n", SystemUtils.isRelease(context) ? 0 : 1);
pw.println("</Version>");
pw.format("<Type>%s</Type>\n", SystemUtils.isRelease(context) ? TCX_TYPE_RELEASE
: TCX_TYPE_INTERNAL);
pw.println("</Build>");
pw.format("<LangID>%s</LangID>\n", Locale.getDefault().getLanguage());
pw.println("<PartNumber>000-00000-00</PartNumber>");
pw.println("</Author>");
pw.println("</TrainingCenterDatabase>");
}
@@ -217,4 +263,15 @@ public class TcxTrackWriter implements TrackFormatWriter {
public void writeWaypoint(Waypoint waypoint) {
// TODO Write out the waypoints somewhere.
}
private String categoryToTcxSport(String category) {
category = category.trim();
if (category.equalsIgnoreCase(TCX_SPORT_RUNNING)) {
return TCX_SPORT_RUNNING;
} else if (category.equalsIgnoreCase(TCX_SPORT_BIKING)) {
return TCX_SPORT_BIKING;
} else {
return TCX_SPORT_OTHER;
}
}
}
@@ -13,7 +13,7 @@
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks.io;
package com.google.android.apps.mytracks.io.file;
import android.os.Environment;
@@ -1,19 +1,19 @@
/*
* 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.io;
package com.google.android.apps.mytracks.io.file;
import com.google.android.apps.mytracks.content.Track;
import com.google.android.apps.mytracks.content.Waypoint;
@@ -54,7 +54,7 @@ public interface TrackFormatWriter {
void prepare(Track track, OutputStream out);
/**
* @return The file extentsion (i.e. gpx, kml, ...)
* @return The file extension (i.e. gpx, kml, ...)
*/
String getExtension();
@@ -77,7 +77,7 @@ public interface TrackFormatWriter {
*
* @param location the location to write
*/
void writeLocation(Location location);
void writeLocation(Location location) throws InterruptedException;
/**
* Write a way point.
@@ -0,0 +1,92 @@
/*
* 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
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks.io.file;
import java.io.File;
/**
* 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 interface TrackWriter {
/** This listener is used to signal completion of track write */
public interface OnCompletionListener {
public void onComplete();
}
/** This listener is used to signal track writes. */
public interface OnWriteListener {
/**
* This method is invoked whenever a location within a track is written.
* @param number the location number
* @param max the maximum number of locations, for calculation of
* completion percentage
*/
public void onWrite(int number, int max);
}
/**
* Sets listener to be invoked when the writer has finished.
*/
void setOnCompletionListener(OnCompletionListener onCompletionListener);
/**
* Sets a listener to be invoked for each location writer.
*/
void setOnWriteListener(OnWriteListener onWriteListener);
/**
* Sets a custom directory where the file will be written.
*/
void setDirectory(File directory);
/**
* 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.
*/
void writeTrackAsync();
/**
* Writes the given track id to the SD card.
* This is blocking.
*/
void writeTrack();
/**
* Stop any in-progress writes
*/
void stopWriteTrack();
/**
* Returns true if the write completed successfully.
*/
boolean wasSuccess();
/**
* Returns the error message (if any) generated by a writer failure.
*/
int getErrorMessage();
}
@@ -1,12 +1,12 @@
/*
* 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
@@ -14,7 +14,7 @@
* the License.
*/
package com.google.android.apps.mytracks.io;
package com.google.android.apps.mytracks.io.file;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.content.Track;
@@ -53,7 +53,7 @@ public class TrackWriterFactory {
TCX {
@Override
public TrackFormatWriter newFormatWriter(Context context) {
return new TcxTrackWriter();
return new TcxTrackWriter(context);
}
};
@@ -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() { }
@@ -1,28 +1,28 @@
/*
* 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;
package com.google.android.apps.mytracks.io.file;
import com.google.android.apps.mytracks.MyTracksConstants;
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.content.MyTracksProviderUtils.LocationIterator;
import com.google.android.apps.mytracks.util.FileUtils;
import com.google.android.apps.mytracks.util.MyTracksUtils;
import com.google.android.apps.mytracks.util.LocationUtils;
import com.google.android.maps.mytracks.R;
import android.app.Activity;
@@ -37,28 +37,29 @@ 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
* {@link TrackFormatWriter} to actually format the data.
* 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 TrackWriter {
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;
private OnCompletionListener onCompletionListener;
private OnWriteListener onWriteListener;
private Thread writeThread;
public TrackWriter(Context context, MyTracksProviderUtils providerUtils,
TrackWriterImpl(Context context, MyTracksProviderUtils providerUtils,
Track track, TrackFormatWriter writer) {
this.context = context;
this.providerUtils = providerUtils;
@@ -67,60 +68,88 @@ public class TrackWriter {
this.fileUtils = new FileUtils();
}
/**
* Sets a completion callback.
*
* @param onCompletion Runnable that will be executed when finished
*/
public void setOnCompletion(Runnable onCompletion) {
this.onCompletion = onCompletion;
@Override
public void setOnCompletionListener(OnCompletionListener onCompletionListener) {
this.onCompletionListener = onCompletionListener;
}
/**
* Sets a custom directory where the file will be written.
*/
@Override
public void setOnWriteListener(OnWriteListener onWriteListener) {
this.onWriteListener = onWriteListener;
}
@Override
public void setDirectory(File directory) {
this.directory = directory;
}
@Override
public String getAbsolutePath() {
return file.getAbsolutePath();
}
/**
* Writes the given track id to the SD card.
* This is non-blocking.
*/
@Override
public void writeTrackAsync() {
Thread t = new Thread() {
writeThread = new Thread() {
@Override
public void run() {
writeTrack();
doWriteTrack();
}
};
t.start();
writeThread.start();
}
/**
* Writes the given track id to the SD card.
* This is blocking.
*/
@Override
public void writeTrack() {
writeTrackAsync();
try {
writeThread.join();
} catch (InterruptedException e) {
Log.e(Constants.TAG, "Interrupted waiting for write to complete", e);
}
}
private void doWriteTrack() {
// Open the input and output
success = false;
errorMessage = R.string.error_track_does_not_exist;
if (track != null) {
if (openFile()) {
writeDocument();
try {
writeDocument();
} catch (InterruptedException e) {
Log.i(Constants.TAG, "The track write was interrupted");
if (file != null) {
file.delete();
}
success = false;
errorMessage = R.string.error_operation_cancelled;
}
}
}
finished();
}
public void stopWriteTrack() {
if (writeThread != null && writeThread.isAlive()) {
Log.i(Constants.TAG, "Attempting to stop track write");
writeThread.interrupt();
try {
writeThread.join();
Log.i(Constants.TAG, "Track write stopped");
} catch (InterruptedException e) {
Log.e(Constants.TAG, "Failed to wait for writer to stop", e);
}
}
}
@Override
public int getErrorMessage() {
return errorMessage;
}
@Override
public boolean wasSuccess() {
return success;
}
@@ -131,8 +160,13 @@ public class TrackWriter {
*/
private void finished() {
if (onCompletion != null) {
runOnUiThread(onCompletion);
if (onCompletionListener != null) {
runOnUiThread(new Runnable() {
@Override
public void run() {
onCompletionListener.onComplete();
}
});
return;
}
}
@@ -147,8 +181,8 @@ public class TrackWriter {
}
/**
* Opens the file and prepares the format writer for it.
*
* Opens the file and prepares the format writer for it.
*
* @return true on success, false otherwise (and errorMessage is set)
*/
protected boolean openFile() {
@@ -160,16 +194,16 @@ public class TrackWriter {
String fileName = fileUtils.buildUniqueFileName(
directory, track.getName(), writer.getExtension());
if (fileName == null) {
Log.e(MyTracksConstants.TAG,
Log.e(Constants.TAG,
"Unable to get a unique filename for " + fileName);
return false;
}
Log.i(MyTracksConstants.TAG, "Writing track to: " + fileName);
Log.i(Constants.TAG, "Writing track to: " + fileName);
try {
writer.prepare(track, newOutputStream(fileName));
} catch (FileNotFoundException e) {
Log.e(MyTracksConstants.TAG, "Failed to open output file.", e);
Log.e(Constants.TAG, "Failed to open output file.", e);
errorMessage = R.string.io_write_failed;
return false;
}
@@ -187,12 +221,12 @@ public class TrackWriter {
}
if (!fileUtils.isSdCardAvailable()) {
Log.i(MyTracksConstants.TAG, "Could not find SD card.");
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(MyTracksConstants.TAG, "Could not create export directory.");
Log.i(Constants.TAG, "Could not create export directory.");
errorMessage = R.string.io_create_dir_failed;
return false;
}
@@ -230,7 +264,7 @@ public class TrackWriter {
// same time.
Cursor cursor = null;
cursor = providerUtils.getWaypointsCursor(trackId, 0,
MyTracksConstants.MAX_LOADED_WAYPOINTS_POINTS);
Constants.MAX_LOADED_WAYPOINTS_POINTS);
if (cursor != null) {
try {
if (cursor.moveToFirst()) {
@@ -252,27 +286,27 @@ public class TrackWriter {
/**
* Does the actual work of writing the track to the now open file.
*/
void writeDocument() {
Log.d(MyTracksConstants.TAG, "Started writing track.");
void writeDocument() throws InterruptedException {
Log.d(Constants.TAG, "Started writing track.");
writer.writeHeader();
writeWaypoints(track.getId());
writeLocations();
writer.writeFooter();
writer.close();
success = true;
Log.d(MyTracksConstants.TAG, "Done writing track.");
Log.d(Constants.TAG, "Done writing track.");
errorMessage = R.string.io_write_finished;
}
private void writeLocations() {
private void writeLocations() throws InterruptedException {
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) {
@@ -280,7 +314,7 @@ public class TrackWriter {
}
return currentLocation;
}
public void swapLocations() {
Location tmpLoc = lastLocation;
lastLocation = currentLocation;
@@ -290,45 +324,54 @@ public class TrackWriter {
}
}
};
TrackWriterLocationFactory locationFactory = new TrackWriterLocationFactory();
LocationIterator it = providerUtils.getLocationIterator(track.getId(), 0, false,
locationFactory);
try {
if (!it.hasNext()) {
Log.w(MyTracksConstants.TAG, "Unable to get any points to write");
Log.w(Constants.TAG, "Unable to get any points to write");
return;
}
int pointNumber = 0;
while (it.hasNext()) {
Location loc = it.next();
boolean isValid = MyTracksUtils.isValidLocation(loc);
if (Thread.interrupted()) {
throw new InterruptedException();
}
pointNumber++;
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);
if (onWriteListener != null) {
onWriteListener.onWrite(pointNumber, track.getNumberOfPoints());
}
} else {
if (segmentOpen) {
writer.writeCloseSegment();
segmentOpen = false;
}
}
locationFactory.swapLocations();
isLastValid = isValid;
}
@@ -187,6 +187,7 @@ public class AndroidGDataClient implements GDataClient {
while (redirectsLeft > 0) {
HttpUriRequest request = creator.createRequest(uri);
request.addHeader("User-Agent", "Android-GData");
request.addHeader("Accept-Encoding", "gzip");
// only add the auth token if not null (to allow for GData feeds that do
@@ -15,7 +15,7 @@
*/
package com.google.android.apps.mytracks.io.gdata;
import com.google.android.apps.mytracks.MyTracksConstants;
import com.google.android.apps.mytracks.Constants;
import com.google.wireless.gdata.client.GDataClient;
import android.content.Context;
@@ -43,7 +43,7 @@ public class GDataClientFactory {
} catch (LinkageError e) {
// On all other platforms use the client implementation packaged in the
// apk.
Log.i(MyTracksConstants.TAG, "Using mytracks AndroidGDataClient.", e);
Log.i(Constants.TAG, "Using mytracks AndroidGDataClient.", e);
return new com.google.android.apps.mytracks.io.gdata.AndroidGDataClient();
}
}
@@ -15,7 +15,7 @@
*/
package com.google.android.apps.mytracks.io.gdata;
import com.google.android.apps.mytracks.MyTracksConstants;
import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.io.AuthManager;
import android.util.Log;
@@ -173,14 +173,14 @@ public class GDataWrapper<C> {
return true;
}
Log.d(MyTracksConstants.TAG, "GData error encountered: " + errorMessage);
Log.d(Constants.TAG, "GData error encountered: " + errorMessage);
if (errorType == ERROR_AUTH && auth != null) {
if (!retryOnAuthFailure || !invalidateAndRefreshAuthToken()) {
return false;
}
}
Log.d(MyTracksConstants.TAG, "retrying function/query");
Log.d(Constants.TAG, "retrying function/query");
}
return false;
}
@@ -206,11 +206,11 @@ public class GDataWrapper<C> {
errorMessage = null;
} catch (AuthenticationException e) {
Log.e(MyTracksConstants.TAG, "AuthenticationException", e);
Log.e(Constants.TAG, "AuthenticationException", e);
errorType = ERROR_AUTH;
errorMessage = e.getMessage();
} catch (HttpException e) {
Log.e(MyTracksConstants.TAG,
Log.e(Constants.TAG,
"HttpException, code " + e.getStatusCode() + " message " + e.getMessage(), e);
errorMessage = e.getMessage();
if (e.getStatusCode() == 401) {
@@ -219,11 +219,11 @@ public class GDataWrapper<C> {
errorType = ERROR_CONNECTION;
}
} catch (FileNotFoundException e) {
Log.e(MyTracksConstants.TAG, "Exception", e);
Log.e(Constants.TAG, "Exception", e);
errorType = ERROR_AUTH;
errorMessage = e.getMessage();
} catch (IOException e) {
Log.e(MyTracksConstants.TAG, "Exception", e);
Log.e(Constants.TAG, "Exception", e);
errorMessage = e.getMessage();
if (errorMessage != null && errorMessage.contains("503")) {
errorType = ERROR_INTERNAL;
@@ -231,11 +231,11 @@ public class GDataWrapper<C> {
errorType = ERROR_CONNECTION;
}
} catch (ParseException e) {
Log.e(MyTracksConstants.TAG, "Exception", e);
Log.e(Constants.TAG, "Exception", e);
errorType = ERROR_LOCAL;
errorMessage = e.getMessage();
} catch (ConflictDetectedException e) {
Log.e(MyTracksConstants.TAG, "Exception", e);
Log.e(Constants.TAG, "Exception", e);
errorType = ERROR_CONFLICT;
errorMessage = e.getMessage();
}
@@ -249,7 +249,7 @@ public class GDataWrapper<C> {
* times out.
*/
private boolean invalidateAndRefreshAuthToken() {
Log.d(MyTracksConstants.TAG, "Retrying due to auth failure");
Log.d(Constants.TAG, "Retrying due to auth failure");
// This FutureTask doesn't do anything -- it exists simply to be
// blocked upon using get().
FutureTask<?> whenFinishedFuture = new FutureTask<Object>(new Runnable() {
@@ -259,18 +259,18 @@ public class GDataWrapper<C> {
auth.invalidateAndRefresh(whenFinishedFuture);
try {
Log.d(MyTracksConstants.TAG, "waiting for invalidate");
Log.d(Constants.TAG, "waiting for invalidate");
whenFinishedFuture.get(AUTH_TOKEN_INVALIDATE_REFRESH_TIMEOUT,
TimeUnit.MILLISECONDS);
Log.d(MyTracksConstants.TAG, "invalidate finished");
Log.d(Constants.TAG, "invalidate finished");
return true;
} catch (InterruptedException e) {
Log.e(MyTracksConstants.TAG, "Failed to invalidate", e);
Log.e(Constants.TAG, "Failed to invalidate", e);
} catch (ExecutionException e) {
Log.e(MyTracksConstants.TAG, "Failed to invalidate", e);
Log.e(Constants.TAG, "Failed to invalidate", e);
} catch (TimeoutException e) {
Log.e(MyTracksConstants.TAG, "Invalidate didn't complete in time", e);
Log.e(Constants.TAG, "Invalidate didn't complete in time", e);
} finally {
whenFinishedFuture.cancel(false);
}

Some files were not shown because too many files have changed in this diff Show More