Merging to Sandor's renaming.

This commit is contained in:
Rodrigo Damazio
2011-03-21 01:10:26 -07:00
89 changed files with 2720 additions and 849 deletions
-1
View File
@@ -5,4 +5,3 @@ syntax:glob
*/proguard/** */proguard/**
.metadata .metadata
MyTracksTest/annotations.log MyTracksTest/annotations.log
MyTracks/src/com/google/android/apps/mytracks/io/mymaps
-1
View File
@@ -8,7 +8,6 @@
<classpathentry kind="src" path="src"/> <classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="gen"/> <classpathentry kind="src" path="gen"/>
<classpathentry exported="true" kind="lib" path="/MyTracksLib/libs/protobuf-java-2.3.0-lite.jar"/> <classpathentry exported="true" kind="lib" path="/MyTracksLib/libs/protobuf-java-2.3.0-lite.jar"/>
<classpathentry kind="lib" path="libs/libmymaps.jar"/>
<classpathentry kind="src" path="MyTracksLib_src"/> <classpathentry kind="src" path="MyTracksLib_src"/>
<classpathentry kind="output" path="bin"/> <classpathentry kind="output" path="bin"/>
</classpath> </classpath>
+6 -6
View File
@@ -17,8 +17,8 @@ limitations under the License.
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.google.android.maps.mytracks" package="com.google.android.maps.mytracks"
android:installLocation="auto" android:installLocation="auto"
android:versionCode="25" android:versionCode="26"
android:versionName="1.1.3rc1"> android:versionName="1.1.4rc1">
<application android:icon="@drawable/arrow_icon" <application android:icon="@drawable/arrow_icon"
android:label="@string/app_name" android:label="@string/app_name"
android:backupAgent="com.google.android.apps.mytracks.io.backup.MyTracksBackupAgent"> android:backupAgent="com.google.android.apps.mytracks.io.backup.MyTracksBackupAgent">
@@ -61,16 +61,16 @@ limitations under the License.
android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|fontScale" android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|fontScale"
android:exported="false" /> android:exported="false" />
<activity android:name="com.google.android.apps.mytracks.MyTracksList" <activity android:name="com.google.android.apps.mytracks.TrackList"
android:label="Recorded Tracks" /> 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" /> 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" /> 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" /> android:label="@string/waypointdetails_title" />
<activity android:name="com.google.android.apps.mytracks.MyTracksSettings" <activity android:name="com.google.android.apps.mytracks.MyTracksSettings"
Binary file not shown.
+60 -60
View File
@@ -1,13 +1,13 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- <!--
Copyright 2010 Google Inc. Copyright 2010 Google Inc.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
You may obtain a copy of the License at You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0 http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -31,7 +31,7 @@ limitations under the License.
<string name="current_segment">Letztes Segment</string> <string name="current_segment">Letztes Segment</string>
<string name="sensor_state">Sensorstatus</string> <string name="sensor_state">Sensorstatus</string>
<string name="aggregated_stats">Aggregierte Statistiken</string> <string name="aggregated_stats">Aggregierte Statistiken</string>
<!-- Error messages --> <!-- Error messages -->
<string name="error_no_location_manager">Es wurde kein Dienst zur Positionsermittlung auf diesem Gerät gefunden.</string> <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_no_gps_location_provider">Es wurde kein GPS-Empfänger auf diesem Gerät gefunden.</string>
@@ -45,7 +45,7 @@ limitations under the License.
<string name="error_track_does_not_exist">Track existiert nicht.</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_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> <string name="error_unable_to_insert_marker">Der Wegpunkt kann nicht einfügt werden. Keine Positionsbestimmung möglich.</string>
<!-- Status messages --> <!-- Status messages -->
<string name="wait_for_fix">Warte auf ein besseres GPS-Signal. Bitte stelle sicher, dass der Himmel sichtbar ist.</string> <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_now_recording">Ein neuer Track wird aufgezeichnet.</string>
@@ -59,7 +59,7 @@ limitations under the License.
<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_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_waypoint_inserted">Ein Wegpunkt wurde eingefügt.</string>
<string name="status_statistics_inserted">Ein Statistikwegpunkt wurde eingefügt.</string> <string name="status_statistics_inserted">Ein Statistikwegpunkt wurde eingefügt.</string>
<!-- Progress dialog --> <!-- Progress dialog -->
<string name="progress_title">Bitte warten…</string> <string name="progress_title">Bitte warten…</string>
<string name="progress_message">Dein Track wird an Google gesendet...</string> <string name="progress_message">Dein Track wird an Google gesendet...</string>
@@ -73,28 +73,28 @@ limitations under the License.
<string name="import_progress_message">Importiere GPS-Track. Das kann ein wenig dauern.</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="write_progress_message">Schreibe Datei auf SD-Karte. Das kann ein wenig dauern.</string>
<string name="progress_message_updating_track">Aktualisiere Trackstatistik...</string> <string name="progress_message_updating_track">Aktualisiere Trackstatistik...</string>
<!-- Used by DeleteAllDataHandler --> <!-- Used by DeleteAllDataHandler -->
<string name="are_you_sure_question">Bist Du Dir wirklich sicher?</string> <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="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="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> <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 --> <!-- Text and links when uploading to Google Fusion Tables -->
<string name="new_map_description">Erstellt von My Tracks für Android.</string> <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> <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 --> <!-- Formatting of track and marker descriptions -->
<string name="points">Punkte</string> <string name="points">Punkte</string>
<string name="recorded_date">Aufgezeichnet am</string> <string name="recorded_date">Aufgezeichnet am</string>
<string name="category">Aktivität</string> <string name="category">Aktivität</string>
<string name="waypoint_category">Art des Wegpunktes</string> <string name="waypoint_category">Art des Wegpunktes</string>
<string name="part">(Teil %d)</string> <string name="part">(Teil %d)</string>
<!-- Used by the track recording service --> <!-- Used by the track recording service -->
<string name="recording_your_track">Dein Track wird aufgezeichnet…</string> <string name="recording_your_track">Dein Track wird aufgezeichnet…</string>
<!--string name="new_track">Track %d</string--> <!--string name="new_track">Track %d</string-->
<!-- Common --> <!-- Common -->
<string name="no">Nein</string> <string name="no">Nein</string>
<string name="yes">Ja</string> <string name="yes">Ja</string>
@@ -111,7 +111,7 @@ limitations under the License.
<!-- Placemark labels for start and end of track --> <!-- Placemark labels for start and end of track -->
<!--string name="start">(Start)</string--> <!--string name="start">(Start)</string-->
<string name="end">(Ende)</string> <string name="end">(Ende)</string>
<!-- TrackList --> <!-- TrackList -->
<string name="tracklist_show_track">Anzeigen</string> <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_fusiontables">An eine Google Fusion Tables-Karte senden</string>
@@ -140,7 +140,7 @@ limitations under the License.
<string name="tracklist_share_csv_file">Eine CSV-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_share_tcx_file">Eine TCX-Datei</string>
<string name="tracklist_clear_map">Karte zurücksetzen.</string> <string name="tracklist_clear_map">Karte zurücksetzen.</string>
<!-- Waypoints list --> <!-- Waypoints list -->
<string name="waypointslist_btn_delete_all">Alle Wegpunkte löschen</string> <string name="waypointslist_btn_delete_all">Alle Wegpunkte löschen</string>
<string name="waypointslist_this_waypoint">Dieser Wegpunkt</string> <string name="waypointslist_this_waypoint">Dieser Wegpunkt</string>
@@ -150,70 +150,70 @@ limitations under the License.
<string name="waypointslist_btn_insert_waypoint">Wegpunkt einfügen</string> <string name="waypointslist_btn_insert_waypoint">Wegpunkt einfügen</string>
<string name="waypointslist_btn_insert_statistics">Statistik 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> <string name="waypointslist_pick_one">Wegpunkt auswählen. Lange berühren für mehr Optionen.</string>
<!-- MyTracks Details --> <!-- MyTracks Details -->
<string name="trackdetails_title">Trackdetails</string> <string name="trackdetails_title">Trackdetails</string>
<string name="trackdetails_name">Name</string> <string name="trackdetails_name">Name</string>
<string name="trackdetails_description">Beschreibung</string> <string name="trackdetails_description">Beschreibung</string>
<string name="trackdetails_category">Aktivität (z. B. Wandern, Fahrradfahren, Laufen, Klettern…)</string> <string name="trackdetails_category">Aktivität (z. B. Wandern, Fahrradfahren, Laufen, Klettern…)</string>
<!-- MyTracks Waypoint Details --> <!-- MyTracks Waypoint Details -->
<string name="waypointdetails_title">Wegpunktdetails</string> <string name="waypointdetails_title">Wegpunktdetails</string>
<string name="waypointdetails_name">Wegpunktname</string> <string name="waypointdetails_name">Wegpunktname</string>
<string name="waypointdetails_description">Wegpunktbeschreibung</string> <string name="waypointdetails_description">Wegpunktbeschreibung</string>
<string name="waypointdetails_category">Art des Wegpunktes (z. B. Gebäude, Schlagloch, Sehenswürdigkeit…)</string> <string name="waypointdetails_category">Art des Wegpunktes (z. B. Gebäude, Schlagloch, Sehenswürdigkeit…)</string>
<!-- MyTracks Settings --> <!-- MyTracks Settings -->
<string name="mytracks_settings">Einstellungen für My Tracks</string> <string name="mytracks_settings">Einstellungen für My Tracks</string>
<string name="settings_display">Anzeige</string> <string name="settings_display">Anzeige</string>
<string name="settings_recording">Aufzeichnung</string> <string name="settings_recording">Aufzeichnung</string>
<string name="settings_sharing">Mit Freunden teilen</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_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">Dauer zwischen Ansagen</string>
<string name="settings_announcement_frequency_summary">Kürzeste Zeit zwischen zwei 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">Kleinste Entfernung zwischen Punkten</string>
<string name="settings_min_recording_distance_summary">Kleinste Entfernung zwischen zwei Positionsaufzeichnungen</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">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_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">Aufzeichnungsfrequenz</string>
<string name="settings_min_recording_interval_summary">Kürzeste Zeit zwischen zwei Positionsaufzeichnungen</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">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_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">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_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_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">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_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_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">Geschwindigkeitsanzeige</string>
<string name="settings_report_speed_or_pace_summary_on">Geschwindigkeit wird angezeigt.</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_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">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_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_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">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_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">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_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">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_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="settings_timestamp_track_name_summary_off">Tracknamen erhalten eine fortlaufende Nummer.</string>
<string name="pace_label">Pace</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="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">Sensortyp</string>
<string name="settings_sensor_type_summary">Der Typ des zu verbindenden Sensors</string> <string name="settings_sensor_type_summary">Der Typ des zu verbindenden Sensors</string>
@@ -225,7 +225,7 @@ limitations under the License.
<string name="bluetooth_sensor_title">Bluetooth-Sensor</string> <string name="bluetooth_sensor_title">Bluetooth-Sensor</string>
<string name="bluetooth_sensor_summary">Der zu verbindende Bluetoothsensor</string> <string name="bluetooth_sensor_summary">Der zu verbindende Bluetoothsensor</string>
<string name="settings_modular_stats_display_title">Art der Datenanzeige</string> <string name="settings_modular_stats_display_title">Art der Datenanzeige</string>
<!-- Backups --> <!-- Backups -->
<string name="settings_backup">Datensicherung (BETA)</string> <string name="settings_backup">Datensicherung (BETA)</string>
<string name="settings_sd_backup">SD-Karten-Sicherung</string> <string name="settings_sd_backup">SD-Karten-Sicherung</string>
@@ -234,13 +234,13 @@ limitations under the License.
<string name="settings_restore_from_sd">Jetzt wiederherstellen</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_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="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="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="select_backup_to_restore">Wähle die wiederherzustellende Datensicherung aus</string>
<string name="no_backups">Keine Datensicherungen gefunden.</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_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> <string name="backup_import_progress_message">Lese alle Tracks und Einstellungen von der SD-Karte. Dies kann eine Weile dauern...</string>
<!-- MyTracksSky --> <!-- MyTracksSky -->
<string name="mytracks_sky">GPS-Satelliten</string> <string name="mytracks_sky">GPS-Satelliten</string>
@@ -248,12 +248,12 @@ limitations under the License.
<string name="share_map">Karte mit Freunden teilen</string> <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: <string name="share_map_body_format">Vielleicht interessierst Du Dich für diese Karte:
%s</string> %s</string>
<string name="send_track_subject">Ich möchte einen GPS-Track mit Dir teilen</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: <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> <string name="share_track">Track mit Freunden teilen</string>
<!-- Visibility --> <!-- Visibility -->
@@ -265,39 +265,39 @@ limitations under the License.
<!-- Average Moving --> <!-- Average Moving -->
<string name="average_moving_speed_label">Durchschnitt in Bew.</string> <string name="average_moving_speed_label">Durchschnitt in Bew.</string>
<string name="average_moving_pace_label">Pace in Bew.</string> <string name="average_moving_pace_label">Pace in Bew.</string>
<!-- Average --> <!-- Average -->
<string name="average_speed_label">Durchschnittsgeschw.</string> <string name="average_speed_label">Durchschnittsgeschw.</string>
<string name="average_pace_label">Durchschnitts-Pace</string> <string name="average_pace_label">Durchschnitts-Pace</string>
<string name="elevation_chart_name">Höhenprofil</string> <string name="elevation_chart_name">Höhenprofil</string>
<string name="elevation_gain_label">Höhengewinn</string> <string name="elevation_gain_label">Höhengewinn</string>
<string name="elevation_label">Höhe</string> <string name="elevation_label">Höhe</string>
<string name="latitude_label">Breitengrad</string> <string name="latitude_label">Breitengrad</string>
<string name="longitude_label">Längengrad</string> <string name="longitude_label">Längengrad</string>
<!-- Min --> <!-- Min -->
<string name="min_elevation_label">Niedrigste Höhenlage</string> <string name="min_elevation_label">Niedrigste Höhenlage</string>
<string name="min_grade_label">Minimale Steigung</string> <string name="min_grade_label">Minimale Steigung</string>
<string name="min_pace_label">Minimaler Pace</string> <string name="min_pace_label">Minimaler Pace</string>
<!-- Max --> <!-- Max -->
<string name="max_elevation_label">Höchste Höhenlage</string> <string name="max_elevation_label">Höchste Höhenlage</string>
<string name="max_grade_label">Maximale Steigung</string> <string name="max_grade_label">Maximale Steigung</string>
<string name="max_speed_label">Max. Geschwindigkeit</string> <string name="max_speed_label">Max. Geschwindigkeit</string>
<string name="loading_track">Lade Track…</string> <string name="loading_track">Lade Track…</string>
<!-- Chart Settings --> <!-- Chart Settings -->
<string name="chart_settings">Diagramm-Einstellungen</string> <string name="chart_settings">Diagramm-Einstellungen</string>
<!-- X Axis --> <!-- X Axis -->
<string name="x_axis">X-Achse</string> <string name="x_axis">X-Achse</string>
<string name="by_distance">Nach Entfernung</string> <string name="by_distance">Nach Entfernung</string>
<string name="by_time">Nach Zeit</string> <string name="by_time">Nach Zeit</string>
<!-- Y Axis --> <!-- Y Axis -->
<string name="y_axis">Y-Achse</string> <string name="y_axis">Y-Achse</string>
<!-- Units --> <!-- Units -->
<!-- Time --> <!-- Time -->
<string name="hour">Stunde</string> <string name="hour">Stunde</string>
@@ -309,7 +309,7 @@ limitations under the License.
<string name="second">Sekunde</string> <string name="second">Sekunde</string>
<string name="seconds">Sekunden</string> <string name="seconds">Sekunden</string>
<!--string name="milliseconds">ms</string--> <!--string name="milliseconds">ms</string-->
<!-- Distance --> <!-- Distance -->
<!--string name="meter">m</string--> <!--string name="meter">m</string-->
<!--string name="kilometer">km</string--> <!--string name="kilometer">km</string-->
@@ -317,7 +317,7 @@ limitations under the License.
<string name="feet">Fuß</string> <string name="feet">Fuß</string>
<!--string name="mile">mi</string--> <!--string name="mile">mi</string-->
<string name="miles_long">Meilen</string> <string name="miles_long">Meilen</string>
<!-- Speed and Pace --> <!-- Speed and Pace -->
<!--string name="kilometer_per_hour">km/h</string--> <!--string name="kilometer_per_hour">km/h</string-->
<string name="kilometer_per_hour_long">Kilometer pro Stunde</string> <string name="kilometer_per_hour_long">Kilometer pro Stunde</string>
@@ -350,12 +350,12 @@ limitations under the License.
<string name="max_heart_rate">Höchste Herzfrequenz</string> <string name="max_heart_rate">Höchste Herzfrequenz</string>
<!--string name="unknown">-</string--> <!--string name="unknown">-</string-->
<string name="waiting">Bitte warten…</string> <string name="waiting">Bitte warten…</string>
<!-- End User License Agreement --> <!-- End User License Agreement -->
<string name="eula_title">Lizenzvereinbarung für Endverbraucher</string> <string name="eula_title">Lizenzvereinbarung für Endverbraucher</string>
<string name="accept">Akzeptieren</string> <string name="accept">Akzeptieren</string>
<string name="decline">Ablehnen</string> <string name="decline">Ablehnen</string>
<!-- About --> <!-- About -->
<string name="about">Über</string> <string name="about">Über</string>
<string name="help">Hilfe</string> <string name="help">Hilfe</string>
@@ -363,7 +363,7 @@ limitations under the License.
<!--string name="about_version">Version:</string--> <!--string name="about_version">Version:</string-->
<string name="about_support">Unterstützung:</string> <string name="about_support">Unterstützung:</string>
<string name="about_privacy">Datenschutz:</string> <string name="about_privacy">Datenschutz:</string>
<!-- Send to Google --> <!-- Send to Google -->
<string name="sendtogoogle_title">Senden an…</string> <string name="sendtogoogle_title">Senden an…</string>
<!--string name="sendtogoogle_google_fusiontables">Google Fusion Tables</string--> <!--string name="sendtogoogle_google_fusiontables">Google Fusion Tables</string-->
@@ -371,12 +371,12 @@ limitations under the License.
<string name="sendtogoogle_send_now">Jetzt senden</string> <string name="sendtogoogle_send_now">Jetzt senden</string>
<string name="sendtogoogle_send_stats">Trackstatistik senden</string> <string name="sendtogoogle_send_stats">Trackstatistik senden</string>
<string name="sendtogoogle_send_stats_and_points">Statistik und Punkte senden</string> <string name="sendtogoogle_send_stats_and_points">Statistik und Punkte senden</string>
<!-- Getting the account to upload to. --> <!-- Getting the account to upload to. -->
<string name="no_account_found_title">Kein Konto vorhanden</string> <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="no_account_found">Kein Konto gefunden, um Tracks zu versenden.</string>
<string name="choose_account_title">Wähle ein Konto</string> <string name="choose_account_title">Wähle ein Konto</string>
<!-- SD card --> <!-- 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_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_write_failed">Die Datei kann nicht geschrieben werden.</string>
@@ -384,7 +384,7 @@ limitations under the License.
<string name="io_create_dir_failed">Das Verzeichnis auf der SD-Karte kann nicht erstellt 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_write_finished">Der Track wurde auf die SD-Karte geschrieben.</string>
<string name="io_read_finished">Lesen von der SD-Karte beendet.</string> <string name="io_read_finished">Lesen von der SD-Karte beendet.</string>
<!-- VersionChecker --> <!-- VersionChecker -->
<string name="version_check_title">Suche nach neuer Version</string> <string name="version_check_title">Suche nach neuer Version</string>
<string name="version_check_upgrade_button">Jetzt aktualisieren</string> <string name="version_check_upgrade_button">Jetzt aktualisieren</string>
@@ -392,12 +392,12 @@ limitations under the License.
<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_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_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> <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 --> <!-- Welcome -->
<string name="welcome">Willkommen</string> <string name="welcome">Willkommen</string>
<string name="welcome_read_later">OK</string> <string name="welcome_read_later">OK</string>
<string name="welcome_about">Über My Tracks</string> <string name="welcome_about">Über My Tracks</string>
<!-- Announcement --> <!-- Announcement -->
<string name="announce_no_distance">My Tracks keine Entfernung</string> <string name="announce_no_distance">My Tracks keine Entfernung</string>
<!-- Format: <!-- Format:
@@ -409,11 +409,11 @@ limitations under the License.
$6 : Speed units (mph) : Pace units (per mile) $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> <string name="announce_template">My Tracks %1$s %2$.2f %3$s in %4$s mit %5$s %6$s</string>
<!-- Check Units --> <!-- Check Units -->
<string name="check_units_title">Einheitenbenachrichtigung</string> <string name="check_units_title">Einheitenbenachrichtigung</string>
<string name="check_units_message">Voreingestellt sind metrische Einheiten. Willst Du diese Einstellung ändern?</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 --> <!-- Fake preference keys - never saved, but show options in the preferences screen -->
<string name="method_bluetooth">Bluetooth</string> <string name="method_bluetooth">Bluetooth</string>
<string name="bluetooth_options">Bluetooth-Einstellungen</string> <string name="bluetooth_options">Bluetooth-Einstellungen</string>
@@ -421,12 +421,12 @@ limitations under the License.
<string name="bluetooth_pairing_summary">Öffnet Androids Bluetooth-Einstellungen, um Geräte zu verbinden.</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_bluetooth_options_key">bluetoothSensorsEnabled</string-->
<string name="sensor_options">Sensor-Einstellungen</string> <string name="sensor_options">Sensor-Einstellungen</string>
<!-- Bluetooth Sensor --> <!-- Bluetooth Sensor -->
<string name="bluetooth_connected">Verbunden mit %s</string> <string name="bluetooth_connected">Verbunden mit %s</string>
<string name="bluetooth_connecting">Verbinde mit Bluetooth-Sensor ...</string> <string name="bluetooth_connecting">Verbinde mit Bluetooth-Sensor ...</string>
<string name="bluetooth_not_connected">Bluetooth-Sensor nicht verbunden.</string> <string name="bluetooth_not_connected">Bluetooth-Sensor nicht verbunden.</string>
<!-- Sensor State --> <!-- Sensor State -->
<string name="sensor_data_time">Uhrzeit</string> <string name="sensor_data_time">Uhrzeit</string>
<string name="power_meter_enabled">Kraftmesser aktiviert</string> <string name="power_meter_enabled">Kraftmesser aktiviert</string>
@@ -439,7 +439,7 @@ limitations under the License.
<string name="no_sensor_service">Kein Sensor-Dienst</string> <string name="no_sensor_service">Kein Sensor-Dienst</string>
<string name="searching">Suche...</string> <string name="searching">Suche...</string>
<string name="sending">Sende...</string> <string name="sending">Sende...</string>
<!-- Manifest description (not seen inside the app) --> <!-- Manifest description (not seen inside the app) -->
<string name="notification_permission_label">Track-Aufzeichnungs-Benachrichtigungen empfangen</string> <string name="notification_permission_label">Track-Aufzeichnungs-Benachrichtigungen empfangen</string>
<string name="read_tracks_permission_label">Aufgezeichnete Trackdaten lesen</string> <string name="read_tracks_permission_label">Aufgezeichnete Trackdaten lesen</string>
@@ -59,7 +59,7 @@ public class AccountChooser {
public void chooseAccount(final Activity activity, public void chooseAccount(final Activity activity,
final AccountHandler handler) { final AccountHandler handler) {
final Account[] accounts = AccountManager.get(activity) final Account[] accounts = AccountManager.get(activity)
.getAccountsByType(MyTracksConstants.ACCOUNT_TYPE); .getAccountsByType(Constants.ACCOUNT_TYPE);
if (accounts.length < 1) { if (accounts.length < 1) {
alertNoAccounts(activity, handler); alertNoAccounts(activity, handler);
return; return;
@@ -76,7 +76,7 @@ public class AccountChooser {
} }
// Let the user choose. // 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); final AlertDialog.Builder builder = new AlertDialog.Builder(activity);
builder.setTitle(R.string.choose_account_title); builder.setTitle(R.string.choose_account_title);
builder.setCancelable(false); builder.setCancelable(false);
@@ -112,7 +112,7 @@ public class AccountChooser {
*/ */
private void alertNoAccounts(final Activity activity, private void alertNoAccounts(final Activity activity,
final AccountHandler handler) { 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); final AlertDialog.Builder builder = new AlertDialog.Builder(activity);
builder.setTitle(R.string.no_account_found_title); builder.setTitle(R.string.no_account_found_title);
builder.setMessage(R.string.no_account_found); builder.setMessage(R.string.no_account_found);
@@ -40,7 +40,7 @@ public class AggregatedStatsActivity extends Activity implements
@Override @Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
String key) { String key) {
Log.d(MyTracksConstants.TAG, "StatsActivity: onSharedPreferences changed " Log.d(Constants.TAG, "StatsActivity: onSharedPreferences changed "
+ key); + key);
if (key != null) { if (key != null) {
if (key.equals(R.string.metric_units_key)) { if (key.equals(R.string.metric_units_key)) {
@@ -15,7 +15,7 @@
*/ */
package com.google.android.apps.mytracks; 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.ChartView.Mode; import com.google.android.apps.mytracks.ChartView.Mode;
import com.google.android.apps.mytracks.content.MyTracksLocation; import com.google.android.apps.mytracks.content.MyTracksLocation;
@@ -55,9 +55,9 @@ import java.util.ArrayList;
public class ChartActivity extends Activity implements TrackDataListener { public class ChartActivity extends Activity implements TrackDataListener {
private final DoubleBuffer elevationBuffer = private final DoubleBuffer elevationBuffer =
new DoubleBuffer(MyTracksConstants.ELEVATION_SMOOTHING_FACTOR); new DoubleBuffer(Constants.ELEVATION_SMOOTHING_FACTOR);
private final DoubleBuffer speedBuffer = 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 final ArrayList<double[]> pendingPoints = new ArrayList<double[]>();
private TrackDataHub dataHub; private TrackDataHub dataHub;
@@ -186,7 +186,7 @@ public class ChartActivity extends Activity implements TrackDataListener {
public boolean onCreateOptionsMenu(Menu menu) { public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu); super.onCreateOptionsMenu(menu);
chartSettingsMenuItem = chartSettingsMenuItem =
menu.add(0, MyTracksConstants.MENU_CHART_SETTINGS, 0, menu.add(0, Constants.MENU_CHART_SETTINGS, 0,
R.string.chart_settings); R.string.chart_settings);
chartSettingsMenuItem.setIcon(R.drawable.chart_settings); chartSettingsMenuItem.setIcon(R.drawable.chart_settings);
return true; return true;
@@ -195,7 +195,7 @@ public class ChartActivity extends Activity implements TrackDataListener {
@Override @Override
public boolean onOptionsItemSelected(MenuItem item) { public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) { switch (item.getItemId()) {
case MyTracksConstants.MENU_CHART_SETTINGS: case Constants.MENU_CHART_SETTINGS:
MyTracks.getInstance().getDialogManager().showDialogSafely( MyTracks.getInstance().getDialogManager().showDialogSafely(
DialogManager.DIALOG_CHART_SETTINGS); DialogManager.DIALOG_CHART_SETTINGS);
return true; return true;
@@ -527,7 +527,7 @@ public class ChartView extends View {
} }
if (nearestWaypoint != null && dmin < 100) { if (nearestWaypoint != null && dmin < 100) {
Intent intent = Intent intent =
new Intent(getContext(), MyTracksWaypointDetails.class); new Intent(getContext(), WaypointDetails.class);
intent.putExtra("waypointid", nearestWaypoint.getId()); intent.putExtra("waypointid", nearestWaypoint.getId());
getContext().startActivity(intent); getContext().startActivity(intent);
return true; return true;
@@ -20,7 +20,7 @@ package com.google.android.apps.mytracks;
* *
* @author Leif Hendrik Wilden * @author Leif Hendrik Wilden
*/ */
public abstract class MyTracksConstants { public abstract class Constants {
/** /**
* Should be used by all log statements * Should be used by all log statements
@@ -188,32 +188,32 @@ public abstract class MyTracksConstants {
public static int getActionFromMenuId(int menuId) { public static int getActionFromMenuId(int menuId) {
switch (menuId) { switch (menuId) {
case MyTracksConstants.MENU_SEND_TO_GOOGLE: case Constants.MENU_SEND_TO_GOOGLE:
return MyTracksConstants.SEND_TO_GOOGLE_DIALOG; return Constants.SEND_TO_GOOGLE_DIALOG;
case MyTracksConstants.MENU_EDIT: case Constants.MENU_EDIT:
return MyTracksConstants.EDIT_DETAILS; return Constants.EDIT_DETAILS;
case MyTracksConstants.MENU_DELETE: case Constants.MENU_DELETE:
return MyTracksConstants.DELETE_TRACK; return Constants.DELETE_TRACK;
case MyTracksConstants.MENU_SHARE_LINK: case Constants.MENU_SHARE_LINK:
return MyTracksConstants.SHARE_LINK; return Constants.SHARE_LINK;
case MyTracksConstants.MENU_SHARE_KML_FILE: case Constants.MENU_SHARE_KML_FILE:
return MyTracksConstants.SHARE_KML_FILE; return Constants.SHARE_KML_FILE;
case MyTracksConstants.MENU_SHARE_GPX_FILE: case Constants.MENU_SHARE_GPX_FILE:
return MyTracksConstants.SHARE_GPX_FILE; return Constants.SHARE_GPX_FILE;
case MyTracksConstants.MENU_SHARE_CSV_FILE: case Constants.MENU_SHARE_CSV_FILE:
return MyTracksConstants.SHARE_CSV_FILE; return Constants.SHARE_CSV_FILE;
case MyTracksConstants.MENU_SHARE_TCX_FILE: case Constants.MENU_SHARE_TCX_FILE:
return MyTracksConstants.SHARE_TCX_FILE; return Constants.SHARE_TCX_FILE;
case MyTracksConstants.MENU_SAVE_GPX_FILE: case Constants.MENU_SAVE_GPX_FILE:
return MyTracksConstants.SAVE_GPX_FILE; return Constants.SAVE_GPX_FILE;
case MyTracksConstants.MENU_SAVE_KML_FILE: case Constants.MENU_SAVE_KML_FILE:
return MyTracksConstants.SAVE_KML_FILE; return Constants.SAVE_KML_FILE;
case MyTracksConstants.MENU_SAVE_CSV_FILE: case Constants.MENU_SAVE_CSV_FILE:
return MyTracksConstants.SAVE_CSV_FILE; return Constants.SAVE_CSV_FILE;
case MyTracksConstants.MENU_SAVE_TCX_FILE: case Constants.MENU_SAVE_TCX_FILE:
return MyTracksConstants.SAVE_TCX_FILE; return Constants.SAVE_TCX_FILE;
case MyTracksConstants.MENU_CLEAR_MAP: case Constants.MENU_CLEAR_MAP:
return MyTracksConstants.CLEAR_MAP; return Constants.CLEAR_MAP;
default: default:
return -1; return -1;
} }
@@ -225,5 +225,5 @@ public abstract class MyTracksConstants {
/** /**
* This is an abstract utility class. * This is an abstract utility class.
*/ */
protected MyTracksConstants() { } protected Constants() { }
} }
@@ -34,12 +34,12 @@ import android.util.Log;
* *
* @author Leif Hendrik Wilden * @author Leif Hendrik Wilden
*/ */
public class MyTracksDeleteAllTracks extends Handler { public class DeleteAllTracks extends Handler {
private final Context context; private final Context context;
private final Runnable done; private final Runnable done;
public MyTracksDeleteAllTracks(Context context, Runnable done) { public DeleteAllTracks(Context context, Runnable done) {
this.context = context; this.context = context;
this.done = done; this.done = done;
} }
@@ -58,7 +58,7 @@ public class MyTracksDeleteAllTracks extends Handler {
new DialogInterface.OnClickListener() { new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int i) { public void onClick(DialogInterface dialog, int i) {
dialog.dismiss(); dialog.dismiss();
Log.w(MyTracksConstants.TAG, "deleting all!"); Log.w(Constants.TAG, "deleting all!");
MyTracksProviderUtils.Factory.get(context).deleteAllTracks(); MyTracksProviderUtils.Factory.get(context).deleteAllTracks();
SharedPreferences prefs = SharedPreferences prefs =
context.getSharedPreferences(MyTracksSettings.SETTINGS_NAME, 0); context.getSharedPreferences(MyTracksSettings.SETTINGS_NAME, 0);
@@ -15,6 +15,8 @@
*/ */
package com.google.android.apps.mytracks; 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.apps.mytracks.io.sendtogoogle.SendDialog;
import com.google.android.maps.mytracks.R; import com.google.android.maps.mytracks.R;
@@ -96,7 +98,7 @@ public class DialogManager {
activity.resetSendToGoogleStatus(); activity.resetSendToGoogleStatus();
break; break;
case DIALOG_CHART_SETTINGS: case DIALOG_CHART_SETTINGS:
Log.d(MyTracksConstants.TAG, "MyTracks.onPrepare chart dialog"); Log.d(TAG, "MyTracks.onPrepare chart dialog");
chartSettingsDialog.setup(activity.getChartActivity()); chartSettingsDialog.setup(activity.getChartActivity());
break; break;
} }
@@ -170,11 +172,9 @@ public class DialogManager {
try { try {
activity.showDialog(id); activity.showDialog(id);
} catch (BadTokenException e) { } catch (BadTokenException e) {
Log.w(MyTracksConstants.TAG, Log.w(TAG, "Could not display dialog with id " + id, e);
"Could not display dialog with id " + id, e);
} catch (IllegalStateException e) { } catch (IllegalStateException e) {
Log.w(MyTracksConstants.TAG, Log.w(TAG, "Could not display dialog with id " + id, e);
"Could not display dialog with id " + id, e);
} }
} }
}); });
@@ -190,9 +190,9 @@ public class DialogManager {
try { try {
dialog.show(); dialog.show();
} catch (BadTokenException e) { } catch (BadTokenException e) {
Log.w(MyTracksConstants.TAG, "Could not display dialog", e); Log.w(TAG, "Could not display dialog", e);
} catch (IllegalStateException e) { } catch (IllegalStateException e) {
Log.w(MyTracksConstants.TAG, "Could not display dialog", e); Log.w(TAG, "Could not display dialog", e);
} }
} }
}); });
@@ -98,7 +98,7 @@ class Eula {
ApiFeatures.getInstance().getApiPlatformAdapter().applyPreferenceChanges( ApiFeatures.getInstance().getApiPlatformAdapter().applyPreferenceChanges(
preferences.edit().putBoolean(PREFERENCE_EULA_ACCEPTED, true)); preferences.edit().putBoolean(PREFERENCE_EULA_ACCEPTED, true));
Intent startIntent = new Intent(activity, WelcomeActivity.class); Intent startIntent = new Intent(activity, WelcomeActivity.class);
activity.startActivityForResult(startIntent, MyTracksConstants.WELCOME); activity.startActivityForResult(startIntent, Constants.WELCOME);
} }
private static void refuse(Activity activity) { private static void refuse(Activity activity) {
@@ -71,14 +71,14 @@ public class ExportAllTracks {
format = TrackFileFormat.TCX; format = TrackFileFormat.TCX;
break; break;
default: default:
Log.w(MyTracksConstants.TAG, "Unknown export format: " + which); Log.w(Constants.TAG, "Unknown export format: " + which);
} }
} }
}; };
public ExportAllTracks(Activity activity) { public ExportAllTracks(Activity activity) {
this.activity = activity; this.activity = activity;
Log.i(MyTracksConstants.TAG, "ExportAllTracks: Starting"); Log.i(Constants.TAG, "ExportAllTracks: Starting");
AlertDialog.Builder builder = new AlertDialog.Builder(activity); AlertDialog.Builder builder = new AlertDialog.Builder(activity);
builder.setSingleChoiceItems(R.array.export_formats, 0, itemClick); builder.setSingleChoiceItems(R.array.export_formats, 0, itemClick);
@@ -130,9 +130,9 @@ public class ExportAllTracks {
// TODO check what happens if we started recording after getting this lock. // TODO check what happens if we started recording after getting this lock.
if (wakeLock != null && wakeLock.isHeld()) { if (wakeLock != null && wakeLock.isHeld()) {
wakeLock.release(); 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(); Toast.makeText(activity, R.string.export_done, Toast.LENGTH_SHORT).show();
} }
@@ -163,7 +163,7 @@ public class ExportAllTracks {
} }
final int trackCount = cursor.getCount(); final int trackCount = cursor.getCount();
Log.i(MyTracksConstants.TAG, Log.i(Constants.TAG,
"ExportAllTracks: Exporting: " + cursor.getCount() + " tracks."); "ExportAllTracks: Exporting: " + cursor.getCount() + " tracks.");
int idxTrackId = cursor.getColumnIndexOrThrow(TracksColumns._ID); int idxTrackId = cursor.getColumnIndexOrThrow(TracksColumns._ID);
activity.runOnUiThread(new Runnable() { activity.runOnUiThread(new Runnable() {
@@ -186,7 +186,7 @@ public class ExportAllTracks {
}); });
long id = cursor.getLong(idxTrackId); long id = cursor.getLong(idxTrackId);
Log.i(MyTracksConstants.TAG, "ExportAllTracks: exporting: " + id); Log.i(Constants.TAG, "ExportAllTracks: exporting: " + id);
TrackWriter writer = TrackWriter writer =
TrackWriterFactory.newWriter(activity, providerUtils, id, format); TrackWriterFactory.newWriter(activity, providerUtils, id, format);
writer.writeTrack(); writer.writeTrack();
@@ -60,7 +60,7 @@ public class ImportAllTracks {
public ImportAllTracks(Activity activity) { public ImportAllTracks(Activity activity) {
this.activity = activity; this.activity = activity;
Log.i(MyTracksConstants.TAG, "ImportAllTracks: Starting"); Log.i(Constants.TAG, "ImportAllTracks: Starting");
fileUtils = new FileUtils(); fileUtils = new FileUtils();
gpxPath = fileUtils.buildExternalDirectoryPath("gpx"); gpxPath = fileUtils.buildExternalDirectoryPath("gpx");
HandlerThread handlerThread; HandlerThread handlerThread;
@@ -98,10 +98,10 @@ public class ImportAllTracks {
// TODO check what happens if we started recording after getting this lock. // TODO check what happens if we started recording after getting this lock.
if (wakeLock != null && wakeLock.isHeld()) { if (wakeLock != null && wakeLock.isHeld()) {
wakeLock.release(); 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); AlertDialog.Builder builder = new AlertDialog.Builder(activity);
if (gpxFileCount == 0) { if (gpxFileCount == 0) {
builder.setMessage(activity.getString(R.string.import_empty, gpxPath + "/")); builder.setMessage(activity.getString(R.string.import_empty, gpxPath + "/"));
@@ -141,7 +141,7 @@ public class ImportAllTracks {
return; return;
} }
Log.i(MyTracksConstants.TAG, "ImportAllTracks: Importing: " + gpxFileCount + " tracks."); Log.i(Constants.TAG, "ImportAllTracks: Importing: " + gpxFileCount + " tracks.");
activity.runOnUiThread(new Runnable() { activity.runOnUiThread(new Runnable() {
public void run() { public void run() {
makeProgressDialog(gpxFileCount); makeProgressDialog(gpxFileCount);
@@ -180,19 +180,19 @@ public class ImportAllTracks {
* notifications and returns false on failure. * notifications and returns false on failure.
*/ */
private boolean importFile(File gpxFile, MyTracksProviderUtils providerUtils) { private boolean importFile(File gpxFile, MyTracksProviderUtils providerUtils) {
Log.i(MyTracksConstants.TAG, "ImportAllTracks: importing: " + gpxFile.getName()); Log.i(Constants.TAG, "ImportAllTracks: importing: " + gpxFile.getName());
try { try {
GpxImporter.importGPXFile(new FileInputStream(gpxFile), providerUtils); GpxImporter.importGPXFile(new FileInputStream(gpxFile), providerUtils);
return true; return true;
} catch (FileNotFoundException e) { } 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); + gpxFile.getAbsolutePath(), e);
} catch (ParserConfigurationException 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) { } 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) { } 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.makeText(activity, activity.getString(R.string.import_error, gpxFile.getName()),
Toast.LENGTH_LONG).show(); Toast.LENGTH_LONG).show();
@@ -64,14 +64,14 @@ class MenuManager {
return true; return true;
} }
case R.id.menu_list_tracks: { case R.id.menu_list_tracks: {
activity.startActivityForResult(new Intent(activity, MyTracksList.class), activity.startActivityForResult(new Intent(activity, TrackList.class),
MyTracksConstants.SHOW_TRACK); Constants.SHOW_TRACK);
return true; return true;
} }
case R.id.menu_list_markers: { 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()); startIntent.putExtra("trackid", activity.getSelectedTrackId());
activity.startActivityForResult(startIntent, MyTracksConstants.SHOW_WAYPOINT); activity.startActivityForResult(startIntent, Constants.SHOW_WAYPOINT);
return true; return true;
} }
case R.id.menu_sensor_state: { case R.id.menu_sensor_state: {
@@ -86,7 +86,7 @@ class MenuManager {
case R.id.menu_help: { case R.id.menu_help: {
return startActivity(WelcomeActivity.class); return startActivity(WelcomeActivity.class);
} }
case MyTracksConstants.MENU_CLEAR_MAP: { case Constants.MENU_CLEAR_MAP: {
activity.clearSelectedTrack(); activity.clearSelectedTrack();
return true; return true;
} }
@@ -18,9 +18,8 @@ package com.google.android.apps.mytracks;
import com.google.android.accounts.Account; import com.google.android.accounts.Account;
import com.google.android.apps.mytracks.io.AuthManager; import com.google.android.apps.mytracks.io.AuthManager;
import com.google.android.apps.mytracks.io.AuthManagerFactory; import com.google.android.apps.mytracks.io.AuthManagerFactory;
import com.google.android.apps.mytracks.io.MyMapsFactory;
import com.google.android.apps.mytracks.io.mymaps.MapsFacade; import com.google.android.apps.mytracks.io.mymaps.MapsFacade;
import com.google.android.apps.mytracks.io.mymaps.MapsService; import com.google.android.apps.mytracks.io.mymaps.MyMapsConstants;
import com.google.android.maps.mytracks.R; import com.google.android.maps.mytracks.R;
import android.app.Activity; import android.app.Activity;
@@ -84,7 +83,7 @@ public class MyMapsList extends Activity implements MapsFacade.MapsListCallback
super.onCreate(icicle); super.onCreate(icicle);
auth = AuthManagerFactory.getAuthManager(this, GET_LOGIN, null, true, auth = AuthManagerFactory.getAuthManager(this, GET_LOGIN, null, true,
MapsService.getServiceName()); MyMapsConstants.SERVICE_NAME);
setContentView(R.layout.list); setContentView(R.layout.list);
@@ -125,7 +124,7 @@ public class MyMapsList extends Activity implements MapsFacade.MapsListCallback
auth.doLogin(new Runnable() { auth.doLogin(new Runnable() {
public void run() { public void run() {
// Runs in UI thread. // Runs in UI thread.
mapsClient = MyMapsFactory.newMapsClient(MyMapsList.this, auth); mapsClient = new MapsFacade(MyMapsList.this, auth);
startLookup(); startLookup();
} }
@@ -200,7 +199,7 @@ public class MyMapsList extends Activity implements MapsFacade.MapsListCallback
shareIntent.putExtra(Intent.EXTRA_TEXT, String.format( shareIntent.putExtra(Intent.EXTRA_TEXT, String.format(
getText(R.string.share_map_body_format).toString(), getText(R.string.share_map_body_format).toString(),
listItem[1], listItem[1],
MapsService.buildMapUrl(listItem[0]))); MapsFacade.buildMapUrl(listItem[0])));
startActivity(Intent.createChooser(shareIntent, startActivity(Intent.createChooser(shareIntent,
getText(R.string.share_map).toString())); getText(R.string.share_map).toString()));
return true; return true;
@@ -15,6 +15,7 @@
*/ */
package com.google.android.apps.mytracks; package com.google.android.apps.mytracks;
import static com.google.android.apps.mytracks.Constants.TAG;
import static com.google.android.apps.mytracks.DialogManager.DIALOG_IMPORT_PROGRESS; import static com.google.android.apps.mytracks.DialogManager.DIALOG_IMPORT_PROGRESS;
import static com.google.android.apps.mytracks.DialogManager.DIALOG_PROGRESS; import static com.google.android.apps.mytracks.DialogManager.DIALOG_PROGRESS;
import static com.google.android.apps.mytracks.DialogManager.DIALOG_SEND_TO_GOOGLE; import static com.google.android.apps.mytracks.DialogManager.DIALOG_SEND_TO_GOOGLE;
@@ -35,7 +36,8 @@ import com.google.android.apps.mytracks.io.TempFileCleaner;
import com.google.android.apps.mytracks.io.TrackWriter; import com.google.android.apps.mytracks.io.TrackWriter;
import com.google.android.apps.mytracks.io.TrackWriterFactory; import com.google.android.apps.mytracks.io.TrackWriterFactory;
import com.google.android.apps.mytracks.io.TrackWriterFactory.TrackFileFormat; import com.google.android.apps.mytracks.io.TrackWriterFactory.TrackFileFormat;
import com.google.android.apps.mytracks.io.mymaps.MapsService; import com.google.android.apps.mytracks.io.mymaps.MapsFacade;
import com.google.android.apps.mytracks.io.mymaps.MyMapsConstants;
import com.google.android.apps.mytracks.io.sendtogoogle.ResultDialogFactory; import com.google.android.apps.mytracks.io.sendtogoogle.ResultDialogFactory;
import com.google.android.apps.mytracks.io.sendtogoogle.SendDialog; import com.google.android.apps.mytracks.io.sendtogoogle.SendDialog;
import com.google.android.apps.mytracks.io.sendtogoogle.SendResult; import com.google.android.apps.mytracks.io.sendtogoogle.SendResult;
@@ -163,7 +165,7 @@ public class MyTracks extends TabActivity implements OnTouchListener,
private final ServiceConnection serviceConnection = new ServiceConnection() { private final ServiceConnection serviceConnection = new ServiceConnection() {
@Override @Override
public void onServiceConnected(ComponentName className, IBinder service) { public void onServiceConnected(ComponentName className, IBinder service) {
Log.d(MyTracksConstants.TAG, "MyTracks: Service now connected."); Log.d(Constants.TAG, "MyTracks: Service now connected.");
// Delay setting the service until we are done with initialization. // Delay setting the service until we are done with initialization.
ITrackRecordingService trackRecordingService = ITrackRecordingService trackRecordingService =
ITrackRecordingService.Stub.asInterface(service); ITrackRecordingService.Stub.asInterface(service);
@@ -181,7 +183,7 @@ public class MyTracks extends TabActivity implements OnTouchListener,
@Override @Override
public void onServiceDisconnected(ComponentName className) { public void onServiceDisconnected(ComponentName className) {
Log.d(MyTracksConstants.TAG, "MyTracks: Service now disconnected."); Log.d(TAG, "MyTracks: Service now disconnected.");
trackRecordingService = null; trackRecordingService = null;
} }
}; };
@@ -226,7 +228,7 @@ public class MyTracks extends TabActivity implements OnTouchListener,
// TODO: We catch Exception, because after eliminating the service process // TODO: We catch Exception, because after eliminating the service process
// all exceptions it may throw are no longer wrapped in a RemoteException. // all exceptions it may throw are no longer wrapped in a RemoteException.
} catch (Exception e) { } catch (Exception e) {
Log.e(MyTracksConstants.TAG, "MyTracks: Remote exception.", e); Log.e(TAG, "MyTracks: Remote exception.", e);
// Fall back to alternative check method. // Fall back to alternative check method.
return dataHub.isRecording(); return dataHub.isRecording();
@@ -240,7 +242,7 @@ public class MyTracks extends TabActivity implements OnTouchListener,
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
Log.d(MyTracksConstants.TAG, "MyTracks.onCreate"); Log.d(TAG, "MyTracks.onCreate");
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
instance = this; instance = this;
ApiFeatures apiFeatures = ApiFeatures.getInstance(); ApiFeatures apiFeatures = ApiFeatures.getInstance();
@@ -303,34 +305,32 @@ public class MyTracks extends TabActivity implements OnTouchListener,
// Do nothing. // Do nothing.
} else if (action.equals(Intent.ACTION_VIEW)) { } else if (action.equals(Intent.ACTION_VIEW)) {
if (intent.getScheme() != null && intent.getScheme().equals("file")) { if (intent.getScheme() != null && intent.getScheme().equals("file")) {
Log.w(MyTracksConstants.TAG, Log.w(TAG, "Received a VIEW intent with file scheme. Importing.");
"Received a VIEW intent with file scheme. Importing.");
importGpxFile(intent.getData().getPath()); importGpxFile(intent.getData().getPath());
} else { } else {
Log.w(MyTracksConstants.TAG, Log.w(TAG, "Received a VIEW intent with unsupported scheme " + intent.getScheme());
"Received a VIEW intent with unsupported scheme "
+ intent.getScheme());
} }
} else { } else {
Log.w(MyTracksConstants.TAG, Log.w(TAG, "Received an intent with unsupported action " + action);
"Received an intent with unsupported action " + action);
} }
} else { } else {
Log.d(MyTracksConstants.TAG, "Received an intent with no action."); Log.d(TAG, "Received an intent with no action.");
} }
} }
@Override @Override
protected void onDestroy() { protected void onDestroy() {
Log.d(MyTracksConstants.TAG, "MyTracks.onDestroy"); Log.d(TAG, "MyTracks.onDestroy");
dataHub.destroy(); dataHub.destroy();
tryUnbindTrackRecordingService(); tryUnbindTrackRecordingService();
super.onDestroy(); super.onDestroy();
} }
@Override @Override
protected void onStop() { protected void onStop() {
Log.d(MyTracksConstants.TAG, "MyTracks.onStop"); Log.d(TAG, "MyTracks.onStop");
dataHub.stop(); dataHub.stop();
@@ -343,7 +343,7 @@ public class MyTracks extends TabActivity implements OnTouchListener,
protected void onPause() { protected void onPause() {
// Called when activity is going into the background, but has not (yet) been // Called when activity is going into the background, but has not (yet) been
// killed. Shouldn't block longer than approx. 2 seconds. // killed. Shouldn't block longer than approx. 2 seconds.
Log.d(MyTracksConstants.TAG, "MyTracks.onPause"); Log.d(TAG, "MyTracks.onPause");
tryUnbindTrackRecordingService(); tryUnbindTrackRecordingService();
super.onPause(); super.onPause();
} }
@@ -352,14 +352,14 @@ public class MyTracks extends TabActivity implements OnTouchListener,
protected void onResume() { protected void onResume() {
// Called when the current activity is being displayed or re-displayed // Called when the current activity is being displayed or re-displayed
// to the user. // to the user.
Log.d(MyTracksConstants.TAG, "MyTracks.onResume"); Log.d(TAG, "MyTracks.onResume");
tryBindTrackRecordingService(); tryBindTrackRecordingService();
super.onResume(); super.onResume();
} }
@Override @Override
protected void onStart() { protected void onStart() {
Log.d(MyTracksConstants.TAG, "MyTracks.onStart"); Log.d(TAG, "MyTracks.onStart");
super.onStart(); super.onStart();
dataHub.start(); dataHub.start();
} }
@@ -422,9 +422,9 @@ public class MyTracks extends TabActivity implements OnTouchListener,
try { try {
insertWaypoint(WaypointCreationRequest.DEFAULT_STATISTICS); insertWaypoint(WaypointCreationRequest.DEFAULT_STATISTICS);
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(MyTracksConstants.TAG, "Cannot insert statistics marker.", e); Log.e(TAG, "Cannot insert statistics marker.", e);
} catch (IllegalStateException e) { } catch (IllegalStateException e) {
Log.e(MyTracksConstants.TAG, "Cannot insert statistics marker.", e); Log.e(TAG, "Cannot insert statistics marker.", e);
} }
return true; return true;
} }
@@ -437,13 +437,13 @@ public class MyTracks extends TabActivity implements OnTouchListener,
final Intent results) { final Intent results) {
TrackFileFormat exportFormat = null; TrackFileFormat exportFormat = null;
switch (requestCode) { switch (requestCode) {
case MyTracksConstants.GET_LOGIN: { case Constants.GET_LOGIN: {
if (resultCode != RESULT_OK || auth == null || !auth.authResult(resultCode, results)) { if (resultCode != RESULT_OK || auth == null || !auth.authResult(resultCode, results)) {
dialogManager.dismissDialogSafely(DIALOG_PROGRESS); dialogManager.dismissDialogSafely(DIALOG_PROGRESS);
} }
break; break;
} }
case MyTracksConstants.SHOW_TRACK: { case Constants.SHOW_TRACK: {
if (results != null) { if (results != null) {
final long trackId = results.getLongExtra("trackid", -1); final long trackId = results.getLongExtra("trackid", -1);
if (trackId >= 0) { if (trackId >= 0) {
@@ -451,14 +451,14 @@ public class MyTracks extends TabActivity implements OnTouchListener,
// The track list passed the requested action as result code. Hand // The track list passed the requested action as result code. Hand
// it off to the onAcitivtyResult for further processing: // it off to the onAcitivtyResult for further processing:
if (resultCode != MyTracksConstants.SHOW_TRACK) { if (resultCode != Constants.SHOW_TRACK) {
onActivityResult(resultCode, Activity.RESULT_OK, results); onActivityResult(resultCode, Activity.RESULT_OK, results);
} }
} }
} }
break; break;
} }
case MyTracksConstants.SHOW_WAYPOINT: { case Constants.SHOW_WAYPOINT: {
if (results != null) { if (results != null) {
final long waypointId = results.getLongExtra("waypointid", -1); final long waypointId = results.getLongExtra("waypointid", -1);
if (waypointId >= 0) { if (waypointId >= 0) {
@@ -472,28 +472,28 @@ public class MyTracks extends TabActivity implements OnTouchListener,
} }
break; break;
} }
case MyTracksConstants.DELETE_TRACK: { case Constants.DELETE_TRACK: {
if (results != null && resultCode == RESULT_OK) { if (results != null && resultCode == RESULT_OK) {
final long trackId = results.getLongExtra("trackid", dataHub.getSelectedTrackId()); final long trackId = results.getLongExtra("trackid", dataHub.getSelectedTrackId());
deleteTrack(trackId); deleteTrack(trackId);
} }
break; break;
} }
case MyTracksConstants.EDIT_DETAILS: { case Constants.EDIT_DETAILS: {
if (results != null && resultCode == RESULT_OK) { if (results != null && resultCode == RESULT_OK) {
final long trackId = results.getLongExtra("trackid", dataHub.getSelectedTrackId()); final long trackId = results.getLongExtra("trackid", dataHub.getSelectedTrackId());
Intent intent = new Intent(this, MyTracksDetails.class); Intent intent = new Intent(this, TrackDetails.class);
intent.putExtra("trackid", trackId); intent.putExtra("trackid", trackId);
startActivity(intent); startActivity(intent);
} }
break; break;
} }
case MyTracksConstants.SEND_TO_GOOGLE_DIALOG: { case Constants.SEND_TO_GOOGLE_DIALOG: {
shareRequested = false; shareRequested = false;
dialogManager.showDialogSafely(DIALOG_SEND_TO_GOOGLE); dialogManager.showDialogSafely(DIALOG_SEND_TO_GOOGLE);
break; break;
} }
case MyTracksConstants.GET_MAP: { case Constants.GET_MAP: {
// User picked a map to upload to // User picked a map to upload to
if (resultCode == RESULT_OK) { if (resultCode == RESULT_OK) {
results.putExtra("trackid", dataHub.getSelectedTrackId()); results.putExtra("trackid", dataHub.getSelectedTrackId());
@@ -506,7 +506,7 @@ public class MyTracks extends TabActivity implements OnTouchListener,
} }
break; break;
} }
case MyTracksConstants.AUTHENTICATE_TO_MY_MAPS: { case Constants.AUTHENTICATE_TO_MY_MAPS: {
// Authenticated with Google My Maps // Authenticated with Google My Maps
if (results != null && resultCode == RESULT_OK) { if (results != null && resultCode == RESULT_OK) {
final String mapId; final String mapId;
@@ -528,7 +528,7 @@ public class MyTracks extends TabActivity implements OnTouchListener,
} }
break; break;
} }
case MyTracksConstants.AUTHENTICATE_TO_FUSION_TABLES: { case Constants.AUTHENTICATE_TO_FUSION_TABLES: {
// Authenticated with Google Fusion Tables // Authenticated with Google Fusion Tables
if (results != null && resultCode == RESULT_OK) { if (results != null && resultCode == RESULT_OK) {
final long trackId; final long trackId;
@@ -544,7 +544,7 @@ public class MyTracks extends TabActivity implements OnTouchListener,
} }
break; break;
} }
case MyTracksConstants.AUTHENTICATE_TO_DOCLIST: { case Constants.AUTHENTICATE_TO_DOCLIST: {
// Authenticated with Google Docs // Authenticated with Google Docs
if (resultCode == RESULT_OK) { if (resultCode == RESULT_OK) {
authenticateToGoogleTrix(); authenticateToGoogleTrix();
@@ -553,7 +553,7 @@ public class MyTracks extends TabActivity implements OnTouchListener,
} }
break; break;
} }
case MyTracksConstants.AUTHENTICATE_TO_TRIX: { case Constants.AUTHENTICATE_TO_TRIX: {
// Authenticated with Trix // Authenticated with Trix
if (resultCode == RESULT_OK) { if (resultCode == RESULT_OK) {
final long trackId = results.getLongExtra("trackid", dataHub.getSelectedTrackId()); final long trackId = results.getLongExtra("trackid", dataHub.getSelectedTrackId());
@@ -563,16 +563,16 @@ public class MyTracks extends TabActivity implements OnTouchListener,
} }
break; break;
} }
case MyTracksConstants.SAVE_GPX_FILE: case Constants.SAVE_GPX_FILE:
if (exportFormat == null) { exportFormat = TrackFileFormat.GPX; } if (exportFormat == null) { exportFormat = TrackFileFormat.GPX; }
//$FALL-THROUGH$ //$FALL-THROUGH$
case MyTracksConstants.SAVE_KML_FILE: case Constants.SAVE_KML_FILE:
if (exportFormat == null) { exportFormat = TrackFileFormat.KML; } if (exportFormat == null) { exportFormat = TrackFileFormat.KML; }
//$FALL-THROUGH$ //$FALL-THROUGH$
case MyTracksConstants.SAVE_CSV_FILE: case Constants.SAVE_CSV_FILE:
if (exportFormat == null) { exportFormat = TrackFileFormat.CSV; } if (exportFormat == null) { exportFormat = TrackFileFormat.CSV; }
//$FALL-THROUGH$ //$FALL-THROUGH$
case MyTracksConstants.SAVE_TCX_FILE: case Constants.SAVE_TCX_FILE:
if (exportFormat == null) { exportFormat = TrackFileFormat.TCX; } if (exportFormat == null) { exportFormat = TrackFileFormat.TCX; }
if (results != null && resultCode == Activity.RESULT_OK) { if (results != null && resultCode == Activity.RESULT_OK) {
@@ -582,11 +582,11 @@ public class MyTracks extends TabActivity implements OnTouchListener,
} }
} }
break; break;
case MyTracksConstants.SHARE_LINK: { case Constants.SHARE_LINK: {
Track selectedTrack = providerUtils.getTrack(dataHub.getSelectedTrackId()); Track selectedTrack = providerUtils.getTrack(dataHub.getSelectedTrackId());
if (selectedTrack != null) { if (selectedTrack != null) {
if (!TextUtils.isEmpty(selectedTrack.getMapId())) { if (!TextUtils.isEmpty(selectedTrack.getMapId())) {
shareLinkToMap(MapsService.buildMapUrl(selectedTrack.getMapId())); shareLinkToMap(MapsFacade.buildMapUrl(selectedTrack.getMapId()));
} else if (!TextUtils.isEmpty(selectedTrack.getTableId())) { } else if (!TextUtils.isEmpty(selectedTrack.getTableId())) {
shareLinkToMap(getFusionTablesUrl(dataHub.getSelectedTrackId())); shareLinkToMap(getFusionTablesUrl(dataHub.getSelectedTrackId()));
} else { } else {
@@ -596,16 +596,16 @@ public class MyTracks extends TabActivity implements OnTouchListener,
} }
break; break;
} }
case MyTracksConstants.SHARE_GPX_FILE: case Constants.SHARE_GPX_FILE:
if (exportFormat == null) { exportFormat = TrackFileFormat.GPX; } if (exportFormat == null) { exportFormat = TrackFileFormat.GPX; }
//$FALL-THROUGH$ //$FALL-THROUGH$
case MyTracksConstants.SHARE_KML_FILE: case Constants.SHARE_KML_FILE:
if (exportFormat == null) { exportFormat = TrackFileFormat.KML; } if (exportFormat == null) { exportFormat = TrackFileFormat.KML; }
//$FALL-THROUGH$ //$FALL-THROUGH$
case MyTracksConstants.SHARE_CSV_FILE: case Constants.SHARE_CSV_FILE:
if (exportFormat == null) { exportFormat = TrackFileFormat.CSV; } if (exportFormat == null) { exportFormat = TrackFileFormat.CSV; }
//$FALL-THROUGH$ //$FALL-THROUGH$
case MyTracksConstants.SHARE_TCX_FILE: { case Constants.SHARE_TCX_FILE: {
if (exportFormat == null) { exportFormat = TrackFileFormat.TCX; } if (exportFormat == null) { exportFormat = TrackFileFormat.TCX; }
if (results != null && resultCode == Activity.RESULT_OK) { if (results != null && resultCode == Activity.RESULT_OK) {
@@ -616,18 +616,17 @@ public class MyTracks extends TabActivity implements OnTouchListener,
} }
break; break;
} }
case MyTracksConstants.CLEAR_MAP: { case Constants.CLEAR_MAP: {
dataHub.unloadCurrentTrack(); dataHub.unloadCurrentTrack();
break; break;
} }
case MyTracksConstants.WELCOME: { case Constants.WELCOME: {
CheckUnits.check(this); CheckUnits.check(this);
break; break;
} }
default: { default: {
Log.w(MyTracksConstants.TAG, Log.w(TAG, "Warning unhandled request code: " + requestCode);
"Warning unhandled request code: " + requestCode);
} }
} }
} }
@@ -668,19 +667,19 @@ public class MyTracks extends TabActivity implements OnTouchListener,
InputStream is = new FileInputStream(fileName); InputStream is = new FileInputStream(fileName);
trackIdsImported = GpxImporter.importGPXFile(is, providerUtils); trackIdsImported = GpxImporter.importGPXFile(is, providerUtils);
} catch (SAXException e) { } catch (SAXException e) {
Log.e(MyTracksConstants.TAG, "Caught an unexpected exception.", e); Log.e(TAG, "Caught an unexpected exception.", e);
message = R.string.error_generic; message = R.string.error_generic;
} catch (ParserConfigurationException e) { } catch (ParserConfigurationException e) {
Log.e(MyTracksConstants.TAG, "Caught an unexpected exception.", e); Log.e(TAG, "Caught an unexpected exception.", e);
message = R.string.error_generic; message = R.string.error_generic;
} catch (IOException e) { } catch (IOException e) {
Log.e(MyTracksConstants.TAG, "Caught an unexpected exception.", e); Log.e(TAG, "Caught an unexpected exception.", e);
message = R.string.error_unable_to_read_file; message = R.string.error_unable_to_read_file;
} catch (NullPointerException e) { } catch (NullPointerException e) {
Log.e(MyTracksConstants.TAG, "Caught an unexpected exception.", e); Log.e(TAG, "Caught an unexpected exception.", e);
message = R.string.error_invalid_gpx_format; message = R.string.error_invalid_gpx_format;
} catch (OutOfMemoryError e) { } catch (OutOfMemoryError e) {
Log.e(MyTracksConstants.TAG, "Caught an unexpected exception.", e); Log.e(TAG, "Caught an unexpected exception.", e);
message = R.string.error_out_of_memory; message = R.string.error_out_of_memory;
} }
if (trackIdsImported != null && trackIdsImported.length > 0) { if (trackIdsImported != null && trackIdsImported.length > 0) {
@@ -803,16 +802,15 @@ public class MyTracks extends TabActivity implements OnTouchListener,
final String service) { final String service) {
auth = authMap.get(service); auth = authMap.get(service);
if (auth == null) { if (auth == null) {
Log.i(MyTracksConstants.TAG, Log.i(TAG, "Creating a new authentication for service: " + service);
"Creating a new authentication for service: " + service);
auth = AuthManagerFactory.getAuthManager(this, auth = AuthManagerFactory.getAuthManager(this,
MyTracksConstants.GET_LOGIN, Constants.GET_LOGIN,
null, null,
true, true,
service); service);
authMap.put(service, auth); authMap.put(service, auth);
} }
Log.d(MyTracksConstants.TAG, "Logging in to " + service + "..."); Log.d(TAG, "Logging in to " + service + "...");
if (AuthManagerFactory.useModernAuthManager()) { if (AuthManagerFactory.useModernAuthManager()) {
runOnUiThread(new Runnable() { runOnUiThread(new Runnable() {
@Override @Override
@@ -839,7 +837,7 @@ public class MyTracks extends TabActivity implements OnTouchListener,
final String service, final Account account) { final String service, final Account account) {
auth.doLogin(new Runnable() { auth.doLogin(new Runnable() {
public void run() { public void run() {
Log.d(MyTracksConstants.TAG, "Loggin success for " + service + "!"); Log.d(TAG, "Loggin success for " + service + "!");
onActivityResult(requestCode, RESULT_OK, results); onActivityResult(requestCode, RESULT_OK, results);
} }
}, account); }, account);
@@ -859,7 +857,7 @@ public class MyTracks extends TabActivity implements OnTouchListener,
Toast.makeText(this, Toast.makeText(this,
getString(R.string.error_unable_to_start_recording), getString(R.string.error_unable_to_start_recording),
Toast.LENGTH_SHORT).show(); Toast.LENGTH_SHORT).show();
Log.w(MyTracksConstants.TAG, "Unable to start recording.", e); Log.w(TAG, "Unable to start recording.", e);
} }
} }
@@ -891,11 +889,11 @@ public class MyTracks extends TabActivity implements OnTouchListener,
// TODO: We catch Exception, because after eliminating the service process // TODO: We catch Exception, because after eliminating the service process
// all exceptions it may throw are no longer wrapped in a RemoteException. // all exceptions it may throw are no longer wrapped in a RemoteException.
} catch (Exception e) { } catch (Exception e) {
Log.e(MyTracksConstants.TAG, "Unable to stop recording.", e); Log.e(TAG, "Unable to stop recording.", e);
} }
if (currentTrackId > 0) { if (currentTrackId > 0) {
Intent intent = new Intent(MyTracks.this, MyTracksDetails.class); Intent intent = new Intent(MyTracks.this, TrackDetails.class);
intent.putExtra("trackid", currentTrackId); intent.putExtra("trackid", currentTrackId);
intent.putExtra("hasCancelButton", false); intent.putExtra("hasCancelButton", false);
startActivity(intent); startActivity(intent);
@@ -905,8 +903,7 @@ public class MyTracks extends TabActivity implements OnTouchListener,
try { try {
stopService(new Intent(MyTracks.this, TrackRecordingService.class)); stopService(new Intent(MyTracks.this, TrackRecordingService.class));
} catch (SecurityException e) { } catch (SecurityException e) {
Log.e(MyTracksConstants.TAG, Log.e(TAG, "Encountered a security exception when trying to stop service.", e);
"Encountered a security exception when trying to stop service.", e);
} }
trackRecordingService = null; trackRecordingService = null;
} }
@@ -915,7 +912,7 @@ public class MyTracks extends TabActivity implements OnTouchListener,
* Initiates the process to send tracks to google. * Initiates the process to send tracks to google.
* This is called once the user has selected sending options via the * This is called once the user has selected sending options via the
* SendToGoogleDialog. * SendToGoogleDialog.
* *
* TODO: Change this whole flow to an actual state machine. * TODO: Change this whole flow to an actual state machine.
*/ */
public void sendToGoogle() { public void sendToGoogle() {
@@ -935,7 +932,7 @@ public class MyTracks extends TabActivity implements OnTouchListener,
} else if (sendToGoogleDialog.getSendToDocs()) { } else if (sendToGoogleDialog.getSendToDocs()) {
authenticateToGoogleDocs(); authenticateToGoogleDocs();
} else { } else {
Log.w(MyTracksConstants.TAG, "Nowhere to upload to"); Log.w(TAG, "Nowhere to upload to");
onSendToGoogleDone(); onSendToGoogleDone();
} }
} }
@@ -944,7 +941,7 @@ public class MyTracks extends TabActivity implements OnTouchListener,
if (!sendToGoogleDialog.getCreateNewMap()) { if (!sendToGoogleDialog.getCreateNewMap()) {
// Ask the user to choose a map to upload into // Ask the user to choose a map to upload into
Intent listIntent = new Intent(this, MyMapsList.class); Intent listIntent = new Intent(this, MyMapsList.class);
startActivityForResult(listIntent, MyTracksConstants.GET_MAP); startActivityForResult(listIntent, Constants.GET_MAP);
// The callback for GET_MAP calls authenticateToGoogleMaps // The callback for GET_MAP calls authenticateToGoogleMaps
} else { } else {
authenticateToGoogleMaps(null); authenticateToGoogleMaps(null);
@@ -957,8 +954,8 @@ public class MyTracks extends TabActivity implements OnTouchListener,
setProgressValue(0); setProgressValue(0);
setProgressMessage( setProgressMessage(
R.string.progress_message_authenticating_mymaps); R.string.progress_message_authenticating_mymaps);
authenticate(results, MyTracksConstants.AUTHENTICATE_TO_MY_MAPS, authenticate(results, Constants.AUTHENTICATE_TO_MY_MAPS,
MapsService.getServiceName()); MyMapsConstants.SERVICE_NAME);
// AUTHENTICATE_TO_MY_MAPS callback calls sendToGoogleMaps // AUTHENTICATE_TO_MY_MAPS callback calls sendToGoogleMaps
} }
@@ -978,7 +975,7 @@ public class MyTracks extends TabActivity implements OnTouchListener,
} catch (RuntimeException e) { } catch (RuntimeException e) {
// If that fails whatever reasons we'll just log an error, but // If that fails whatever reasons we'll just log an error, but
// continue. // continue.
Log.w(MyTracksConstants.TAG, "Updating map id failed.", e); Log.w(TAG, "Updating map id failed.", e);
} }
} }
@@ -1010,7 +1007,7 @@ public class MyTracks extends TabActivity implements OnTouchListener,
setProgressValue(0); setProgressValue(0);
setProgressMessage(R.string.progress_message_authenticating_fusiontables); setProgressMessage(R.string.progress_message_authenticating_fusiontables);
authenticate(results, MyTracksConstants.AUTHENTICATE_TO_FUSION_TABLES, authenticate(results, Constants.AUTHENTICATE_TO_FUSION_TABLES,
SendToFusionTables.SERVICE_ID); SendToFusionTables.SERVICE_ID);
// AUTHENTICATE_TO_FUSION_TABLES callback calls sendToFusionTables // AUTHENTICATE_TO_FUSION_TABLES callback calls sendToFusionTables
} }
@@ -1032,10 +1029,10 @@ public class MyTracks extends TabActivity implements OnTouchListener,
} catch (RuntimeException e) { } catch (RuntimeException e) {
// If that fails whatever reasons we'll just log an error, but // If that fails whatever reasons we'll just log an error, but
// continue. // continue.
Log.w(MyTracksConstants.TAG, "Updating table id failed.", e); Log.w(TAG, "Updating table id failed.", e);
} }
} }
onSendToFusionTablesDone(); onSendToFusionTablesDone();
} }
}; };
@@ -1063,7 +1060,7 @@ public class MyTracks extends TabActivity implements OnTouchListener,
setProgressMessage( setProgressMessage(
R.string.progress_message_authenticating_docs); R.string.progress_message_authenticating_docs);
authenticate(new Intent(), authenticate(new Intent(),
MyTracksConstants.AUTHENTICATE_TO_DOCLIST, Constants.AUTHENTICATE_TO_DOCLIST,
SendToDocs.GDATA_SERVICE_NAME_DOCLIST); SendToDocs.GDATA_SERVICE_NAME_DOCLIST);
// AUTHENTICATE_TO_DOCLIST callback calls authenticateToGoogleTrix // AUTHENTICATE_TO_DOCLIST callback calls authenticateToGoogleTrix
} }
@@ -1073,16 +1070,16 @@ public class MyTracks extends TabActivity implements OnTouchListener,
setProgressMessage( setProgressMessage(
R.string.progress_message_authenticating_docs); R.string.progress_message_authenticating_docs);
authenticate(new Intent(), authenticate(new Intent(),
MyTracksConstants.AUTHENTICATE_TO_TRIX, Constants.AUTHENTICATE_TO_TRIX,
SendToDocs.GDATA_SERVICE_NAME_TRIX); SendToDocs.GDATA_SERVICE_NAME_TRIX);
// AUTHENTICATE_TO_TRIX callback calls sendToGoogleDocs // AUTHENTICATE_TO_TRIX callback calls sendToGoogleDocs
} }
private void sendToGoogleDocs(final long trackId) { private void sendToGoogleDocs(final long trackId) {
Log.d(MyTracksConstants.TAG, "Sending to Docs...."); Log.d(TAG, "Sending to Docs....");
setProgressValue(50); setProgressValue(50);
setProgressMessage(R.string.progress_message_sending_docs); setProgressMessage(R.string.progress_message_sending_docs);
final SendToDocs sender = new SendToDocs(this, final SendToDocs sender = new SendToDocs(this,
authMap.get(SendToDocs.GDATA_SERVICE_NAME_TRIX), authMap.get(SendToDocs.GDATA_SERVICE_NAME_TRIX),
authMap.get(SendToDocs.GDATA_SERVICE_NAME_DOCLIST), trackId); authMap.get(SendToDocs.GDATA_SERVICE_NAME_DOCLIST), trackId);
sendToTrackId = trackId; sendToTrackId = trackId;
@@ -1151,11 +1148,11 @@ public class MyTracks extends TabActivity implements OnTouchListener,
DialogManager.showDialogSafely(this, sendToGoogleResultDialog); DialogManager.showDialogSafely(this, sendToGoogleResultDialog);
} }
private boolean shareLinkToMap(boolean sentToMyMaps, boolean sentToFusionTables) { boolean shareLinkToMap(boolean sentToMyMaps, boolean sentToFusionTables) {
String url = null; String url = null;
if (sentToMyMaps && sendToMyMapsSuccess) { if (sentToMyMaps && sendToMyMapsSuccess) {
// Prefer a link to My Maps // Prefer a link to My Maps
url = MapsService.buildMapUrl(sendToMyMapsMapId); url = MapsFacade.buildMapUrl(sendToMyMapsMapId);
} else if (sentToFusionTables && sendToFusionTablesSuccess) { } else if (sentToFusionTables && sendToFusionTablesSuccess) {
// Otherwise try using the link to fusion tables // Otherwise try using the link to fusion tables
url = getFusionTablesUrl(sendToTrackId); url = getFusionTablesUrl(sendToTrackId);
@@ -1206,11 +1203,11 @@ public class MyTracks extends TabActivity implements OnTouchListener,
* Binds to track recording service if it is running. * Binds to track recording service if it is running.
*/ */
private void tryBindTrackRecordingService() { private void tryBindTrackRecordingService() {
Log.d(MyTracksConstants.TAG, Log.d(TAG,
"MyTracks: Trying to bind to track recording service..."); "MyTracks: Trying to bind to track recording service...");
bindService(new Intent(this, TrackRecordingService.class), bindService(new Intent(this, TrackRecordingService.class),
serviceConnection, 0); serviceConnection, 0);
Log.d(MyTracksConstants.TAG, "MyTracks: ...bind finished!"); Log.d(TAG, "MyTracks: ...bind finished!");
isBound = true; isBound = true;
} }
@@ -1220,14 +1217,12 @@ public class MyTracks extends TabActivity implements OnTouchListener,
*/ */
private void tryUnbindTrackRecordingService() { private void tryUnbindTrackRecordingService() {
if (isBound) { if (isBound) {
Log.d(MyTracksConstants.TAG, Log.d(TAG, "MyTracks: Trying to unbind from track recording service...");
"MyTracks: Trying to unbind from track recording service...");
try { try {
unbindService(serviceConnection); unbindService(serviceConnection);
Log.d(MyTracksConstants.TAG, "MyTracks: ...unbind finished!"); Log.d(TAG, "MyTracks: ...unbind finished!");
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
Log.d(MyTracksConstants.TAG, Log.d(TAG, "MyTracks: Tried unbinding, but service was not registered.", e);
"MyTracks: Tried unbinding, but service was not registered.", e);
} }
isBound = false; isBound = false;
} }
@@ -1319,24 +1314,24 @@ public class MyTracks extends TabActivity implements OnTouchListener,
} }
public boolean getSendToGoogleSuccess() { public boolean getSendToGoogleSuccess() {
return sendToMyMapsSuccess && sendToFusionTablesSuccess && sendToDocsSuccess; return sendToFusionTablesSuccess && sendToDocsSuccess;
} }
// @VisibleForTesting // @VisibleForTesting
long getRecordingTrackId() { long getRecordingTrackId() {
return sharedPreferences.getLong(getString(R.string.recording_track_key), -1); return sharedPreferences.getLong(getString(R.string.recording_track_key), -1);
} }
// @VisibleForTesting // @VisibleForTesting
SharedPreferences getSharedPreferences() { SharedPreferences getSharedPreferences() {
return sharedPreferences; return sharedPreferences;
} }
// @VisibleForTesting // @VisibleForTesting
static void clearInstance() { static void clearInstance() {
instance = null; instance = null;
} }
// @VisibleForTesting // @VisibleForTesting
ITrackRecordingService getTrackRecordingService() { ITrackRecordingService getTrackRecordingService() {
return trackRecordingService; return trackRecordingService;
@@ -15,7 +15,7 @@
*/ */
package com.google.android.apps.mytracks; 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.MyTracksProviderUtils; import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.content.Track; import com.google.android.apps.mytracks.content.Track;
@@ -343,37 +343,37 @@ public class MyTracksMap extends MapActivity
public void onCreateContextMenu(ContextMenu menu, View v, public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenuInfo menuInfo) { ContextMenuInfo menuInfo) {
menu.setHeaderTitle(R.string.tracklist_this_track); menu.setHeaderTitle(R.string.tracklist_this_track);
menu.add(0, MyTracksConstants.MENU_EDIT, 0, menu.add(0, Constants.MENU_EDIT, 0,
R.string.tracklist_edit_track); R.string.tracklist_edit_track);
if (!dataHub.isRecordingSelected()) { if (!dataHub.isRecordingSelected()) {
menu.add(0, MyTracksConstants.MENU_SEND_TO_GOOGLE, 0, menu.add(0, Constants.MENU_SEND_TO_GOOGLE, 0,
R.string.tracklist_send_to_google); 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); R.string.tracklist_share_track);
share.add(0, MyTracksConstants.MENU_SHARE_LINK, 0, share.add(0, Constants.MENU_SHARE_LINK, 0,
R.string.tracklist_share_link); R.string.tracklist_share_link);
share.add(0, MyTracksConstants.MENU_SHARE_GPX_FILE, 0, share.add(0, Constants.MENU_SHARE_GPX_FILE, 0,
R.string.tracklist_share_gpx_file); 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); 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); 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); R.string.tracklist_share_tcx_file);
SubMenu save = menu.addSubMenu(0, 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); 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); 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); 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); 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); R.string.tracklist_save_as_tcx);
menu.add(0, MyTracksConstants.MENU_CLEAR_MAP, 0, menu.add(0, Constants.MENU_CLEAR_MAP, 0,
R.string.tracklist_clear_map); R.string.tracklist_clear_map);
menu.add(0, MyTracksConstants.MENU_DELETE, 0, menu.add(0, Constants.MENU_DELETE, 0,
R.string.tracklist_delete_track); R.string.tracklist_delete_track);
} }
} }
@@ -383,7 +383,7 @@ public class MyTracksMap extends MapActivity
public boolean onMenuItemSelected(int featureId, MenuItem item) { public boolean onMenuItemSelected(int featureId, MenuItem item) {
if (!super.onMenuItemSelected(featureId, item)) { if (!super.onMenuItemSelected(featureId, item)) {
MyTracks.getInstance().onActivityResult( MyTracks.getInstance().onActivityResult(
MyTracksConstants.getActionFromMenuId(item.getItemId()), RESULT_OK, Constants.getActionFromMenuId(item.getItemId()), RESULT_OK,
new Intent()); new Intent());
return true; return true;
} }
@@ -393,10 +393,10 @@ public class MyTracksMap extends MapActivity
@Override @Override
public boolean onCreateOptionsMenu(Menu menu) { public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu); super.onCreateOptionsMenu(menu);
myLocation = menu.add(0, MyTracksConstants.MENU_MY_LOCATION, 0, myLocation = menu.add(0, Constants.MENU_MY_LOCATION, 0,
R.string.mylocation); R.string.mylocation);
myLocation.setIcon(android.R.drawable.ic_menu_mylocation); myLocation.setIcon(android.R.drawable.ic_menu_mylocation);
toggleLayers = menu.add(0, MyTracksConstants.MENU_TOGGLE_LAYERS, 0, toggleLayers = menu.add(0, Constants.MENU_TOGGLE_LAYERS, 0,
R.string.switch_to_sat); R.string.switch_to_sat);
toggleLayers.setIcon(android.R.drawable.ic_menu_mapmode); toggleLayers.setIcon(android.R.drawable.ic_menu_mapmode);
return true; return true;
@@ -412,7 +412,7 @@ public class MyTracksMap extends MapActivity
@Override @Override
public boolean onOptionsItemSelected(MenuItem item) { public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) { switch (item.getItemId()) {
case MyTracksConstants.MENU_MY_LOCATION: { case Constants.MENU_MY_LOCATION: {
dataHub.forceUpdateLocation(); dataHub.forceUpdateLocation();
keepMyLocationVisible = true; keepMyLocationVisible = true;
if (mapView.getZoomLevel() < 18) { if (mapView.getZoomLevel() < 18) {
@@ -420,7 +420,7 @@ public class MyTracksMap extends MapActivity
} }
return true; return true;
} }
case MyTracksConstants.MENU_TOGGLE_LAYERS: { case Constants.MENU_TOGGLE_LAYERS: {
mapView.setSatellite(!mapView.isSatellite()); mapView.setSatellite(!mapView.isSatellite());
return true; return true;
} }
@@ -497,7 +497,7 @@ public class MyTracksMap extends MapActivity
@Override @Override
public void onCurrentLocationChanged(Location location) { public void onCurrentLocationChanged(Location location) {
if (!location.getProvider().equals(MyTracksConstants.GPS_PROVIDER)) { if (!location.getProvider().equals(Constants.GPS_PROVIDER)) {
Log.d(TAG, Log.d(TAG,
"MyTracksMap: Network location update received (provider '" + location.getProvider() + "'."); "MyTracksMap: Network location update received (provider '" + location.getProvider() + "'.");
} }
@@ -103,7 +103,7 @@ public class MyTracksOverlay extends Overlay {
this.waypoints = new ArrayList<Waypoint>(); this.waypoints = new ArrayList<Waypoint>();
this.points = new ArrayList<CachedLocation>(1024); this.points = new ArrayList<CachedLocation>(1024);
this.pendingPoints = new ArrayBlockingQueue<CachedLocation>( 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 // TODO: Can we use a FrameAnimation or similar here rather
// than individual resources for each arrow direction? // than individual resources for each arrow direction?
@@ -460,7 +460,7 @@ public class MyTracksOverlay extends Overlay {
if (waypoint != null && if (waypoint != null &&
dmin < 15000000 / Math.pow(2, mapView.getZoomLevel())) { dmin < 15000000 / Math.pow(2, mapView.getZoomLevel())) {
Intent intent = new Intent(context, MyTracksWaypointDetails.class); Intent intent = new Intent(context, WaypointDetails.class);
intent.putExtra("waypointid", waypoint.getId()); intent.putExtra("waypointid", waypoint.getId());
context.startActivity(intent); context.startActivity(intent);
return true; return true;
@@ -16,8 +16,8 @@
package com.google.android.apps.mytracks; package com.google.android.apps.mytracks;
import static android.content.Intent.ACTION_BOOT_COMPLETED; 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.Constants.RESUME_TRACK_EXTRA_NAME;
import static com.google.android.apps.mytracks.MyTracksConstants.TAG; import static com.google.android.apps.mytracks.Constants.TAG;
import com.google.android.apps.mytracks.services.TrackRecordingService; import com.google.android.apps.mytracks.services.TrackRecordingService;
@@ -15,7 +15,7 @@
*/ */
package com.google.android.apps.mytracks; 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.io.backup.BackupActivityHelper; import com.google.android.apps.mytracks.io.backup.BackupActivityHelper;
import com.google.android.apps.mytracks.io.backup.BackupPreferencesListener; import com.google.android.apps.mytracks.io.backup.BackupPreferencesListener;
@@ -15,7 +15,7 @@
*/ */
package com.google.android.apps.mytracks; 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.content.Sensor;
import com.google.android.apps.mytracks.services.ITrackRecordingService; import com.google.android.apps.mytracks.services.ITrackRecordingService;
import com.google.android.apps.mytracks.services.sensors.SensorUtils; import com.google.android.apps.mytracks.services.sensors.SensorUtils;
@@ -103,7 +103,7 @@ public class SensorStateActivity extends Activity {
ITrackRecordingService service = ITrackRecordingService service =
mt == null ? null : mt.getTrackRecordingService(); mt == null ? null : mt.getTrackRecordingService();
if (service == null) { 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); updateSensorState(Sensor.SensorState.NONE);
updateSensorData(null); updateSensorData(null);
return; return;
@@ -116,9 +116,9 @@ public class SensorStateActivity extends Activity {
updateSensorData(sds); updateSensorData(sds);
} }
} catch (RemoteException e) { } 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) { } 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); updateSensorData(sds);
@@ -126,7 +126,7 @@ public class SensorStateActivity extends Activity {
int i = service.getSensorState(); int i = service.getSensorState();
updateSensorState(Sensor.SensorState.valueOf(i)); updateSensorState(Sensor.SensorState.valueOf(i));
} catch (RemoteException e) { } 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); updateSensorState(Sensor.SensorState.NONE);
} }
} }
@@ -15,7 +15,7 @@
*/ */
package com.google.android.apps.mytracks; 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.Track; import com.google.android.apps.mytracks.content.Track;
import com.google.android.apps.mytracks.content.Waypoint; import com.google.android.apps.mytracks.content.Waypoint;
@@ -175,14 +175,14 @@ public class StatsActivity extends Activity implements TrackDataListener {
public boolean onCreateOptionsMenu(Menu menu) { public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu); super.onCreateOptionsMenu(menu);
MenuItem currentSegment = menu.add(0, 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); currentSegment.setIcon(R.drawable.ic_menu_lastsegment);
return true; return true;
} }
@Override @Override
public boolean onPrepareOptionsMenu(Menu menu) { public boolean onPrepareOptionsMenu(Menu menu) {
MenuItem item = menu.findItem(MyTracksConstants.MENU_CURRENT_SEGMENT); MenuItem item = menu.findItem(Constants.MENU_CURRENT_SEGMENT);
if (item != null) { if (item != null) {
item.setTitle(showCurrentSegment item.setTitle(showCurrentSegment
? getString(R.string.current_track) ? getString(R.string.current_track)
@@ -194,7 +194,7 @@ public class StatsActivity extends Activity implements TrackDataListener {
@Override @Override
public boolean onOptionsItemSelected(MenuItem item) { public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) { switch (item.getItemId()) {
case MyTracksConstants.MENU_CURRENT_SEGMENT: case Constants.MENU_CURRENT_SEGMENT:
showCurrentSegment = !showCurrentSegment; showCurrentSegment = !showCurrentSegment;
// TODO: Re-read only the data that interests us // TODO: Re-read only the data that interests us
return true; return true;
@@ -235,7 +235,7 @@ public class StatsUtilities {
} }
public void setSpeedLabel(int id, int speedString, int paceString) { 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 + " to " + reportSpeed +
" speed: " + speedString + " speed: " + speedString +
" pace: " + paceString); " pace: " + paceString);
@@ -243,7 +243,7 @@ public class StatsUtilities {
if (tv != null) { if (tv != null) {
tv.setText(reportSpeed ? speedString : paceString); tv.setText(reportSpeed ? speedString : paceString);
} else { } else {
Log.w(MyTracksConstants.TAG, "Could not find id: " + id); Log.w(Constants.TAG, "Could not find id: " + id);
} }
} }
@@ -15,7 +15,7 @@
*/ */
package com.google.android.apps.mytracks; 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.TrackDataListener.ProviderState; import com.google.android.apps.mytracks.TrackDataListener.ProviderState;
import com.google.android.apps.mytracks.content.MyTracksLocation; import com.google.android.apps.mytracks.content.MyTracksLocation;
@@ -359,7 +359,7 @@ public class TrackDataHub {
final long now = System.currentTimeMillis(); final long now = System.currentTimeMillis();
Location loc = locationManager.getLastKnownLocation( Location loc = locationManager.getLastKnownLocation(
MyTracksConstants.GPS_PROVIDER); Constants.GPS_PROVIDER);
if (loc == null || loc.getTime() < now - MAX_LOCATION_AGE_MS) { if (loc == null || loc.getTime() < now - MAX_LOCATION_AGE_MS) {
// We don't have a recent GPS fix, just use cell towers if available // We don't have a recent GPS fix, just use cell towers if available
loc = locationManager.getLastKnownLocation( loc = locationManager.getLastKnownLocation(
@@ -502,25 +502,25 @@ public class TrackDataHub {
// Listen to compass // Listen to compass
Sensor compass = sensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION); Sensor compass = sensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);
if (compass != null) { if (compass != null) {
Log.d(MyTracksConstants.TAG, Log.d(Constants.TAG,
"TrackDataHub: Now registering sensor listeners."); "TrackDataHub: Now registering sensor listeners.");
sensorManager.registerListener(compassListener, compass, SensorManager.SENSOR_DELAY_UI); sensorManager.registerListener(compassListener, compass, SensorManager.SENSOR_DELAY_UI);
} }
// Listen to GPS // Listen to GPS
LocationProvider gpsProvider = LocationProvider gpsProvider =
locationManager.getProvider(MyTracksConstants.GPS_PROVIDER); locationManager.getProvider(Constants.GPS_PROVIDER);
if (gpsProvider == null) { if (gpsProvider == null) {
Toast.makeText(context, R.string.error_no_gps_location_provider, Toast.LENGTH_LONG).show(); Toast.makeText(context, R.string.error_no_gps_location_provider, Toast.LENGTH_LONG).show();
hasProviderEnabled = false; hasProviderEnabled = false;
return; return;
} else { } else {
Log.d(MyTracksConstants.TAG, "TrackDataHub: Using location provider " Log.d(Constants.TAG, "TrackDataHub: Using location provider "
+ gpsProvider.getName()); + gpsProvider.getName());
} }
locationManager.requestLocationUpdates(gpsProvider.getName(), locationManager.requestLocationUpdates(gpsProvider.getName(),
0 /*minTime*/, 0 /*minDist*/, locationListener); 0 /*minTime*/, 0 /*minDist*/, locationListener);
hasProviderEnabled = locationManager.isProviderEnabled(MyTracksConstants.GPS_PROVIDER); hasProviderEnabled = locationManager.isProviderEnabled(Constants.GPS_PROVIDER);
// Listen to network location // Listen to network location
try { try {
@@ -529,7 +529,7 @@ public class TrackDataHub {
} catch (RuntimeException e) { } catch (RuntimeException e) {
// If anything at all goes wrong with getting a cell location do not // If anything at all goes wrong with getting a cell location do not
// abort. Cell location is not essential to this app. // abort. Cell location is not essential to this app.
Log.w(MyTracksConstants.TAG, Log.w(Constants.TAG,
"Could not register network location listener."); "Could not register network location listener.");
} }
} }
@@ -777,7 +777,7 @@ public class TrackDataHub {
private void notifyWaypointUpdated(final TrackDataListener... listeners) { private void notifyWaypointUpdated(final TrackDataListener... listeners) {
// Always reload all the waypoints. // Always reload all the waypoints.
final Cursor cursor = providerUtils.getWaypointsCursor( final Cursor cursor = providerUtils.getWaypointsCursor(
selectedTrackId, 0, MyTracksConstants.MAX_DISPLAYED_WAYPOINTS_POINTS); selectedTrackId, 0, Constants.MAX_DISPLAYED_WAYPOINTS_POINTS);
listenerHandler.post(new Runnable() { listenerHandler.post(new Runnable() {
@Override @Override
@@ -857,7 +857,7 @@ public class TrackDataHub {
long minPointId = keepState ? lastSeenLocationId + 1 : 0; long minPointId = keepState ? lastSeenLocationId + 1 : 0;
long maxPointId = keepState ? -1 : lastSeenLocationId; long maxPointId = keepState ? -1 : lastSeenLocationId;
if (numLoadedPoints >= MyTracksConstants.MAX_DISPLAYED_TRACK_POINTS) { if (numLoadedPoints >= Constants.MAX_DISPLAYED_TRACK_POINTS) {
// We're about to exceed the maximum allowed number of points, so reload // We're about to exceed the maximum allowed number of points, so reload
// the whole track with fewer points (the sampling frequency will be // the whole track with fewer points (the sampling frequency will be
// lower). We do this for every listener even if we were loading just for // lower). We do this for every listener even if we were loading just for
@@ -931,7 +931,7 @@ public class TrackDataHub {
// frequency. // frequency.
long numTotalPoints = lastStoredLocationId - localFirstSeenLocationId; long numTotalPoints = lastStoredLocationId - localFirstSeenLocationId;
pointSamplingFrequency = pointSamplingFrequency =
(int) (1 + numTotalPoints / MyTracksConstants.TARGET_DISPLAYED_TRACK_POINTS); (int) (1 + numTotalPoints / Constants.TARGET_DISPLAYED_TRACK_POINTS);
} }
// Include a point if it fits one of the following criteria: // Include a point if it fits one of the following criteria:
@@ -37,7 +37,7 @@ import android.widget.EditText;
* *
* @author Leif Hendrik Wilden * @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") * 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: // Required extra when launching this intent:
trackId = getIntent().getLongExtra("trackid", -1); trackId = getIntent().getLongExtra("trackid", -1);
if (trackId < 0) { if (trackId < 0) {
Log.d(MyTracksConstants.TAG, Log.d(Constants.TAG,
"MyTracksDetails intent was launched w/o track id."); "MyTracksDetails intent was launched w/o track id.");
finish(); finish();
return; return;
@@ -45,7 +45,7 @@ import android.widget.TextView;
* *
* @author Leif Hendrik Wilden * @author Leif Hendrik Wilden
*/ */
public class MyTracksList extends ListActivity public class TrackList extends ListActivity
implements SharedPreferences.OnSharedPreferenceChangeListener, implements SharedPreferences.OnSharedPreferenceChangeListener,
View.OnClickListener { View.OnClickListener {
@@ -70,40 +70,40 @@ public class MyTracksList extends ListActivity
AdapterView.AdapterContextMenuInfo info = AdapterView.AdapterContextMenuInfo info =
(AdapterView.AdapterContextMenuInfo) menuInfo; (AdapterView.AdapterContextMenuInfo) menuInfo;
contextPosition = info.position; contextPosition = info.position;
trackId = MyTracksList.this.listView.getAdapter().getItemId( trackId = TrackList.this.listView.getAdapter().getItemId(
contextPosition); contextPosition);
menu.add(0, MyTracksConstants.MENU_SHOW, 0, menu.add(0, Constants.MENU_SHOW, 0,
R.string.tracklist_show_track); R.string.tracklist_show_track);
menu.add(0, MyTracksConstants.MENU_EDIT, 0, menu.add(0, Constants.MENU_EDIT, 0,
R.string.tracklist_edit_track); R.string.tracklist_edit_track);
if (!MyTracks.getInstance().isRecording() if (!MyTracks.getInstance().isRecording()
|| trackId != recordingTrackId) { || 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); 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); R.string.tracklist_share_track);
share.add(0, MyTracksConstants.MENU_SHARE_LINK, 0, share.add(0, Constants.MENU_SHARE_LINK, 0,
R.string.tracklist_share_link); R.string.tracklist_share_link);
share.add(0, MyTracksConstants.MENU_SHARE_GPX_FILE, 0, share.add(0, Constants.MENU_SHARE_GPX_FILE, 0,
R.string.tracklist_share_gpx_file); 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); 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); 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); R.string.tracklist_share_tcx_file);
SubMenu save = menu.addSubMenu(0, 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); 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); 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); 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); 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); 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); 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) { protected void onListItemClick(ListView l, View v, int position, long id) {
Intent result = new Intent(); Intent result = new Intent();
result.putExtra("trackid", id); result.putExtra("trackid", id);
setResult(MyTracksConstants.SHOW_TRACK, result); setResult(Constants.SHOW_TRACK, result);
finish(); finish();
} }
@@ -140,24 +140,24 @@ public class MyTracksList extends ListActivity
public boolean onMenuItemSelected(int featureId, MenuItem item) { public boolean onMenuItemSelected(int featureId, MenuItem item) {
if (!super.onMenuItemSelected(featureId, item)) { if (!super.onMenuItemSelected(featureId, item)) {
switch (item.getItemId()) { switch (item.getItemId()) {
case MyTracksConstants.MENU_SHOW: { case Constants.MENU_SHOW: {
onListItemClick(null, null, 0, trackId); onListItemClick(null, null, 0, trackId);
return true; return true;
} }
case MyTracksConstants.MENU_EDIT: { case Constants.MENU_EDIT: {
Intent intent = new Intent(this, MyTracksDetails.class); Intent intent = new Intent(this, TrackDetails.class);
intent.putExtra("trackid", trackId); intent.putExtra("trackid", trackId);
startActivity(intent); startActivity(intent);
return true; return true;
} }
case MyTracksConstants.MENU_SHARE: case Constants.MENU_SHARE:
case MyTracksConstants.MENU_WRITE_TO_SD_CARD: case Constants.MENU_WRITE_TO_SD_CARD:
return false; return false;
default: { default: {
Intent result = new Intent(); Intent result = new Intent();
result.putExtra("trackid", trackId); result.putExtra("trackid", trackId);
setResult( setResult(
MyTracksConstants.getActionFromMenuId(item.getItemId()), result); Constants.getActionFromMenuId(item.getItemId()), result);
finish(); finish();
return true; return true;
} }
@@ -170,7 +170,7 @@ public class MyTracksList extends ListActivity
public void onClick(View v) { public void onClick(View v) {
switch (v.getId()) { switch (v.getId()) {
case R.id.tracklist_btn_delete_all: { case R.id.tracklist_btn_delete_all: {
Handler h = new MyTracksDeleteAllTracks(this, null); Handler h = new DeleteAllTracks(this, null);
h.handleMessage(null); h.handleMessage(null);
break; break;
} }
@@ -39,7 +39,7 @@ import android.widget.ImageView;
* *
* @author Leif Hendrik Wilden * @author Leif Hendrik Wilden
*/ */
public class MyTracksWaypointDetails extends Activity public class WaypointDetails extends Activity
implements OnClickListener { implements OnClickListener {
public static final String WAYPOINT_ID_EXTRA = "com.google.android.apps.mytracks.WAYPOINT_ID"; public static final String WAYPOINT_ID_EXTRA = "com.google.android.apps.mytracks.WAYPOINT_ID";
@@ -82,7 +82,7 @@ public class MyTracksWaypointDetails extends Activity
// Required extra when launching this intent: // Required extra when launching this intent:
waypointId = getIntent().getLongExtra(WAYPOINT_ID_EXTRA, -1); waypointId = getIntent().getLongExtra(WAYPOINT_ID_EXTRA, -1);
if (waypointId < 0) { if (waypointId < 0) {
Log.d(MyTracksConstants.TAG, Log.d(Constants.TAG,
"MyTracksWaypointsDetails intent was launched w/o waypoint id."); "MyTracksWaypointsDetails intent was launched w/o waypoint id.");
finish(); finish();
return; return;
@@ -49,7 +49,7 @@ import android.widget.TextView;
* *
* @author Leif Hendrik Wilden * @author Leif Hendrik Wilden
*/ */
public class MyTracksWaypointsList extends ListActivity public class WaypointsList extends ListActivity
implements View.OnClickListener { implements View.OnClickListener {
private int contextPosition = -1; private int contextPosition = -1;
@@ -71,14 +71,14 @@ public class MyTracksWaypointsList extends ListActivity
AdapterView.AdapterContextMenuInfo info = AdapterView.AdapterContextMenuInfo info =
(AdapterView.AdapterContextMenuInfo) menuInfo; (AdapterView.AdapterContextMenuInfo) menuInfo;
contextPosition = info.position; contextPosition = info.position;
waypointId = MyTracksWaypointsList.this.listView.getAdapter() waypointId = WaypointsList.this.listView.getAdapter()
.getItemId(contextPosition); .getItemId(contextPosition);
int type = providerUtils.getWaypoint(info.id).getType(); 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); R.string.waypointslist_show_waypoint);
menu.add(0, MyTracksConstants.MENU_EDIT, 0, menu.add(0, Constants.MENU_EDIT, 0,
R.string.waypointslist_edit_waypoint); 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( R.string.waypointslist_delete_waypoint).setEnabled(
recordingTrackId < 0 || type == Waypoint.TYPE_WAYPOINT || recordingTrackId < 0 || type == Waypoint.TYPE_WAYPOINT ||
info.id != providerUtils.getLastWaypointId(recordingTrackId)); info.id != providerUtils.getLastWaypointId(recordingTrackId));
@@ -89,8 +89,8 @@ public class MyTracksWaypointsList extends ListActivity
protected void onListItemClick(ListView l, View v, int position, long id) { protected void onListItemClick(ListView l, View v, int position, long id) {
Intent result = new Intent(); Intent result = new Intent();
result.putExtra("trackid", trackId); result.putExtra("trackid", trackId);
result.putExtra(MyTracksWaypointDetails.WAYPOINT_ID_EXTRA, id); result.putExtra(WaypointDetails.WAYPOINT_ID_EXTRA, id);
setResult(MyTracksConstants.EDIT_WAYPOINT, result); setResult(Constants.EDIT_WAYPOINT, result);
finish(); finish();
} }
@@ -98,18 +98,18 @@ public class MyTracksWaypointsList extends ListActivity
public boolean onMenuItemSelected(int featureId, MenuItem item) { public boolean onMenuItemSelected(int featureId, MenuItem item) {
if (!super.onMenuItemSelected(featureId, item)) { if (!super.onMenuItemSelected(featureId, item)) {
switch (item.getItemId()) { switch (item.getItemId()) {
case MyTracksConstants.MENU_SHOW: { case Constants.MENU_SHOW: {
onListItemClick(null, null, 0, waypointId); onListItemClick(null, null, 0, waypointId);
return true; return true;
} }
case MyTracksConstants.MENU_EDIT: { case Constants.MENU_EDIT: {
Intent intent = new Intent(this, MyTracksWaypointDetails.class); Intent intent = new Intent(this, WaypointDetails.class);
intent.putExtra("trackid", trackId); intent.putExtra("trackid", trackId);
intent.putExtra(MyTracksWaypointDetails.WAYPOINT_ID_EXTRA, waypointId); intent.putExtra(WaypointDetails.WAYPOINT_ID_EXTRA, waypointId);
startActivity(intent); startActivity(intent);
return true; return true;
} }
case MyTracksConstants.MENU_DELETE: { case Constants.MENU_DELETE: {
deleteWaypoint(waypointId); deleteWaypoint(waypointId);
} }
} }
@@ -185,18 +185,18 @@ public class MyTracksWaypointsList extends ListActivity
try { try {
id = MyTracks.getInstance().insertWaypoint(request); id = MyTracks.getInstance().insertWaypoint(request);
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(MyTracksConstants.TAG, "Cannot insert marker.", e); Log.e(Constants.TAG, "Cannot insert marker.", e);
return; return;
} catch (IllegalStateException e) { } catch (IllegalStateException e) {
Log.e(MyTracksConstants.TAG, "Cannot insert marker.", e); Log.e(Constants.TAG, "Cannot insert marker.", e);
return; return;
} }
if (id < 0) { if (id < 0) {
Log.e(MyTracksConstants.TAG, "Failed to insert marker."); Log.e(Constants.TAG, "Failed to insert marker.");
return; return;
} }
Intent intent = new Intent(this, MyTracksWaypointDetails.class); Intent intent = new Intent(this, WaypointDetails.class);
intent.putExtra(MyTracksWaypointDetails.WAYPOINT_ID_EXTRA, id); intent.putExtra(WaypointDetails.WAYPOINT_ID_EXTRA, id);
startActivity(intent); startActivity(intent);
} }
@@ -261,7 +261,7 @@ public class MyTracksWaypointsList extends ListActivity
public void onClick(DialogInterface dialog, int i) { public void onClick(DialogInterface dialog, int i) {
dialog.dismiss(); dialog.dismiss();
providerUtils.deleteWaypoint(waypointId, providerUtils.deleteWaypoint(waypointId,
new StringUtils(MyTracksWaypointsList.this)); new StringUtils(WaypointsList.this));
} }
}); });
builder.setNegativeButton(getString(R.string.no), builder.setNegativeButton(getString(R.string.no),
@@ -15,7 +15,7 @@
*/ */
package com.google.android.apps.mytracks.content; 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 com.google.android.apps.mytracks.util.ApiFeatures;
import android.content.ContentProvider; import android.content.ContentProvider;
@@ -382,7 +382,7 @@ public class MyTracksProvider extends ContentProvider {
} }
if (ApiFeatures.getInstance().canReuseSQLiteQueryBuilder()) { if (ApiFeatures.getInstance().canReuseSQLiteQueryBuilder()) {
Log.i(MyTracksConstants.TAG, Log.i(Constants.TAG,
"Build query: " + qb.buildQuery(projection, selection, selectionArgs, "Build query: " + qb.buildQuery(projection, selection, selectionArgs,
null, null, sortOrder, null)); null, null, sortOrder, null));
} }
@@ -15,7 +15,7 @@
*/ */
package com.google.android.apps.mytracks.io; 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.app.Activity;
import android.os.Build; import android.os.Build;
@@ -46,11 +46,11 @@ public class AuthManagerFactory {
public static AuthManager getAuthManager(Activity activity, int code, public static AuthManager getAuthManager(Activity activity, int code,
Bundle extras, boolean requireGoogle, String service) { Bundle extras, boolean requireGoogle, String service) {
if (useModernAuthManager()) { if (useModernAuthManager()) {
Log.i(MyTracksConstants.TAG, Log.i(Constants.TAG,
"Creating modern auth manager: " + service); "Creating modern auth manager: " + service);
return new ModernAuthManager(activity, code, extras, requireGoogle, service); return new ModernAuthManager(activity, code, extras, requireGoogle, service);
} else { } else {
Log.i(MyTracksConstants.TAG, Log.i(Constants.TAG,
"Creating legacy auth manager: " + service); "Creating legacy auth manager: " + service);
return new AuthManagerOld(activity, code, extras, requireGoogle, service); return new AuthManagerOld(activity, code, extras, requireGoogle, service);
} }
@@ -15,7 +15,7 @@
*/ */
package com.google.android.apps.mytracks.io; package com.google.android.apps.mytracks.io;
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.MyTracksProviderUtils;
import com.google.android.apps.mytracks.content.Track; import com.google.android.apps.mytracks.content.Track;
import com.google.android.apps.mytracks.stats.TripStatisticsBuilder; import com.google.android.apps.mytracks.stats.TripStatisticsBuilder;
@@ -174,7 +174,7 @@ public class GpxImporter extends DefaultHandler {
parser.parse(is, handler); parser.parse(is, handler);
long end = System.currentTimeMillis(); 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(); trackIds = handler.getImportedTrackIds();
} finally { } finally {
@@ -462,7 +462,7 @@ public class GpxImporter extends DefaultHandler {
// check for negative time change // check for negative time change
if (timeDifference < 0) { if (timeDifference < 0) {
Log.w(MyTracksConstants.TAG, "Found negative time change."); Log.w(Constants.TAG, "Found negative time change.");
} else { } else {
// We don't have a speed and bearing in GPX, make something up from // We don't have a speed and bearing in GPX, make something up from
@@ -23,7 +23,7 @@ import com.google.android.accounts.AuthenticatorException;
import com.google.android.accounts.OperationCanceledException; import com.google.android.accounts.OperationCanceledException;
import com.google.android.apps.mytracks.AccountChooser; import com.google.android.apps.mytracks.AccountChooser;
import com.google.android.apps.mytracks.MyTracks; 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.app.Activity;
import android.content.Intent; import android.content.Intent;
@@ -104,20 +104,20 @@ public class ModernAuthManager implements AuthManager {
if (result.containsKey(AccountManager.KEY_INTENT)) { if (result.containsKey(AccountManager.KEY_INTENT)) {
Intent intent = (Intent) result.get(AccountManager.KEY_INTENT); Intent intent = (Intent) result.get(AccountManager.KEY_INTENT);
clearNewTaskFlag(intent); clearNewTaskFlag(intent);
activity.startActivityForResult(intent, MyTracksConstants.GET_LOGIN); activity.startActivityForResult(intent, Constants.GET_LOGIN);
return; return;
} }
authToken = result.getString( authToken = result.getString(
AccountManager.KEY_AUTHTOKEN); AccountManager.KEY_AUTHTOKEN);
Log.e(MyTracksConstants.TAG, "Got auth token."); Log.e(Constants.TAG, "Got auth token.");
runWhenFinished(); runWhenFinished();
} catch (OperationCanceledException e) { } catch (OperationCanceledException e) {
Log.e(MyTracksConstants.TAG, "Operation Canceled", e); Log.e(Constants.TAG, "Operation Canceled", e);
} catch (IOException e) { } catch (IOException e) {
Log.e(MyTracksConstants.TAG, "IOException", e); Log.e(Constants.TAG, "IOException", e);
} catch (AuthenticatorException e) { } catch (AuthenticatorException e) {
Log.e(MyTracksConstants.TAG, "Authentication Failed", e); Log.e(Constants.TAG, "Authentication Failed", e);
} }
} }
}, null /* handler */); }, null /* handler */);
@@ -149,9 +149,9 @@ public class ModernAuthManager implements AuthManager {
if (results != null) { if (results != null) {
authToken = results.getStringExtra( authToken = results.getStringExtra(
AccountManager.KEY_AUTHTOKEN); AccountManager.KEY_AUTHTOKEN);
Log.w(MyTracksConstants.TAG, "authResult: " + authToken); Log.w(Constants.TAG, "authResult: " + authToken);
} else { } else {
Log.e(MyTracksConstants.TAG, "No auth result results!!"); Log.e(Constants.TAG, "No auth result results!!");
} }
runWhenFinished(); runWhenFinished();
return authToken != null; return authToken != null;
@@ -181,7 +181,7 @@ public class ModernAuthManager implements AuthManager {
activity.runOnUiThread(new Runnable() { activity.runOnUiThread(new Runnable() {
public void run() { public void run() {
accountManager.invalidateAuthToken(MyTracksConstants.ACCOUNT_TYPE, accountManager.invalidateAuthToken(Constants.ACCOUNT_TYPE,
authToken); authToken);
MyTracks.getInstance().getAccountChooser().chooseAccount(activity, MyTracks.getInstance().getAccountChooser().chooseAccount(activity,
new AccountChooser.AccountHandler() { new AccountChooser.AccountHandler() {
@@ -1,68 +0,0 @@
package com.google.android.apps.mytracks.io;
import com.google.android.apps.mytracks.io.gdata.GDataClientFactory;
import com.google.android.apps.mytracks.io.mymaps.MapsFacade;
import com.google.android.apps.mytracks.io.mymaps.MapsService;
import com.google.android.apps.mytracks.io.mymaps.MapsStringsProvider;
import com.google.android.apps.mytracks.io.mymaps.MapsFacade.AuthenticationRefresher;
import com.google.android.maps.mytracks.R;
import android.app.Activity;
import android.content.Context;
/**
* Factory to easily instantiate a {@link MapsFacade}.
*
* @author Rodrigo Damazio
*/
public class MyMapsFactory {
/**
* Simple provider for reading strings from resources.
*/
private static class MyMapsStringProvider implements MapsStringsProvider {
private final Context context;
public MyMapsStringProvider(Context context) {
this.context = context;
}
@Override
public String getNewMapDescription() {
return context.getString(R.string.new_map_description);
}
@Override
public String getStart() {
return context.getString(R.string.start);
}
@Override
public String getEnd() {
return context.getString(R.string.end);
}
}
/**
* Creates a new Maps fa�ade interface instance.
*
* @param context current context
* @param auth a valid authentication manager
* @return the fa�ade
*/
public static MapsFacade newMapsClient(Activity context, final AuthManager auth) {
MapsFacade client = MapsService.newClient(context,
GDataClientFactory.getGDataClient(context),
new MyMapsStringProvider(context),
auth.getAuthToken());
client.setAuthenticationRefresher(new AuthenticationRefresher() {
@Override
public void invalidateAndRefresh(Runnable done) {
auth.invalidateAndRefresh(done);
}
});
return client;
}
private MyMapsFactory() {}
}
@@ -16,7 +16,7 @@
package com.google.android.apps.mytracks.io; package com.google.android.apps.mytracks.io;
import com.google.android.apps.mytracks.MyTracks; 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.MyTracksSettings; import com.google.android.apps.mytracks.MyTracksSettings;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils; import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.content.Track; import com.google.android.apps.mytracks.content.Track;
@@ -82,7 +82,7 @@ public class SendToDocs {
metricUnits = true; metricUnits = true;
} }
Log.d(MyTracksConstants.TAG, Log.d(Constants.TAG,
"Sending to Google Docs: trackId = " + trackId); "Sending to Google Docs: trackId = " + trackId);
handlerThread = new HandlerThread("SendToGoogleDocs"); handlerThread = new HandlerThread("SendToGoogleDocs");
handlerThread.start(); handlerThread.start();
@@ -105,7 +105,7 @@ public class SendToDocs {
try { try {
if (trackId == -1) { if (trackId == -1) {
Log.w(MyTracksConstants.TAG, "Cannot get track id."); Log.w(Constants.TAG, "Cannot get track id.");
return; return;
} }
@@ -113,14 +113,14 @@ public class SendToDocs {
Track track = Track track =
MyTracksProviderUtils.Factory.get(activity).getTrack(trackId); MyTracksProviderUtils.Factory.get(activity).getTrack(trackId);
if (track == null) { if (track == null) {
Log.w(MyTracksConstants.TAG, "Cannot get track."); Log.w(Constants.TAG, "Cannot get track.");
return; return;
} }
// Transmit track stats via GData feed: // 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); success = uploadToDocs(track);
if (success) { if (success) {
if (createdNewSpreadSheet) { if (createdNewSpreadSheet) {
@@ -133,7 +133,7 @@ public class SendToDocs {
} else { } else {
statusMessage = activity.getString(R.string.error_sending_to_docs); statusMessage = activity.getString(R.string.error_sending_to_docs);
} }
Log.d(MyTracksConstants.TAG, "SendToDocs: Done."); Log.d(Constants.TAG, "SendToDocs: Done.");
} finally { } finally {
if (onCompletion != null) { if (onCompletion != null) {
activity.runOnUiThread(onCompletion); activity.runOnUiThread(onCompletion);
@@ -176,7 +176,7 @@ public class SendToDocs {
SpreadsheetsClient gdataClient = new SpreadsheetsClient(androidClient, SpreadsheetsClient gdataClient = new SpreadsheetsClient(androidClient,
new XmlDocsGDataParserFactory(new AndroidXmlParserFactory())); new XmlDocsGDataParserFactory(new AndroidXmlParserFactory()));
trixWrapper.setClient(gdataClient); trixWrapper.setClient(gdataClient);
Log.d(MyTracksConstants.TAG, Log.d(Constants.TAG,
"GData connection prepared: " + this.docListAuth); "GData connection prepared: " + this.docListAuth);
String sheetTitle = "My Tracks"; String sheetTitle = "My Tracks";
@@ -194,7 +194,7 @@ public class SendToDocs {
spreadsheetId = docsHelper.requestSpreadsheetId(docListWrapper, spreadsheetId = docsHelper.requestSpreadsheetId(docListWrapper,
sheetTitle); sheetTitle);
} catch (IOException e) { } catch (IOException e) {
Log.i(MyTracksConstants.TAG, "Spreadsheet lookup failed.", e); Log.i(Constants.TAG, "Spreadsheet lookup failed.", e);
return false; return false;
} }
@@ -205,14 +205,14 @@ public class SendToDocs {
try { try {
Thread.sleep(5000); Thread.sleep(5000);
} catch (InterruptedException e) { } catch (InterruptedException e) {
Log.e(MyTracksConstants.TAG, "Sleep interrupted", e); Log.e(Constants.TAG, "Sleep interrupted", e);
} }
try { try {
spreadsheetId = docsHelper.requestSpreadsheetId(docListWrapper, spreadsheetId = docsHelper.requestSpreadsheetId(docListWrapper,
sheetTitle); sheetTitle);
} catch (IOException e) { } catch (IOException e) {
Log.i(MyTracksConstants.TAG, "2nd spreadsheet lookup failed.", e); Log.i(Constants.TAG, "2nd spreadsheet lookup failed.", e);
return false; return false;
} }
} }
@@ -220,13 +220,13 @@ public class SendToDocs {
// We were unable to find an existing spreadsheet, so create a new one. // We were unable to find an existing spreadsheet, so create a new one.
MyTracks.getInstance().setProgressValue(70); MyTracks.getInstance().setProgressValue(70);
if (spreadsheetId == null) { if (spreadsheetId == null) {
Log.i(MyTracksConstants.TAG, "Creating new spreadsheet: " + sheetTitle); Log.i(Constants.TAG, "Creating new spreadsheet: " + sheetTitle);
try { try {
spreadsheetId = docsHelper.createSpreadsheet(activity, docListWrapper, spreadsheetId = docsHelper.createSpreadsheet(activity, docListWrapper,
sheetTitle); sheetTitle);
} catch (IOException e) { } catch (IOException e) {
Log.i(MyTracksConstants.TAG, "Failed to create new spreadsheet " Log.i(Constants.TAG, "Failed to create new spreadsheet "
+ sheetTitle, e); + sheetTitle, e);
return false; return false;
} }
@@ -239,19 +239,19 @@ public class SendToDocs {
// reported an error. Seems to be a know bug, // reported an error. Seems to be a know bug,
// see http://code.google.com/p/gdata-issues/issues/detail?id=929 // see http://code.google.com/p/gdata-issues/issues/detail?id=929
// Try to find the created spreadsheet: // Try to find the created spreadsheet:
Log.w(MyTracksConstants.TAG, Log.w(Constants.TAG,
"Create might have failed. Trying to find created document."); "Create might have failed. Trying to find created document.");
try { try {
Thread.sleep(5000); Thread.sleep(5000);
} catch (InterruptedException e) { } catch (InterruptedException e) {
Log.e(MyTracksConstants.TAG, "Sleep interrupted", e); Log.e(Constants.TAG, "Sleep interrupted", e);
} }
try { try {
spreadsheetId = docsHelper.requestSpreadsheetId(docListWrapper, spreadsheetId = docsHelper.requestSpreadsheetId(docListWrapper,
sheetTitle); sheetTitle);
} catch (IOException e) { } catch (IOException e) {
Log.i(MyTracksConstants.TAG, "Failed create-failed lookup", e); Log.i(Constants.TAG, "Failed create-failed lookup", e);
return false; return false;
} }
@@ -261,19 +261,19 @@ public class SendToDocs {
try { try {
Thread.sleep(5000); Thread.sleep(5000);
} catch (InterruptedException e) { } catch (InterruptedException e) {
Log.e(MyTracksConstants.TAG, "Sleep interrupted", e); Log.e(Constants.TAG, "Sleep interrupted", e);
} }
try { try {
spreadsheetId = docsHelper.requestSpreadsheetId(docListWrapper, spreadsheetId = docsHelper.requestSpreadsheetId(docListWrapper,
sheetTitle); sheetTitle);
} catch (IOException e) { } catch (IOException e) {
Log.i(MyTracksConstants.TAG, "Failed create-failed relookup", e); Log.i(Constants.TAG, "Failed create-failed relookup", e);
return false; return false;
} }
} }
if (spreadsheetId == null) { if (spreadsheetId == null) {
Log.i(MyTracksConstants.TAG, Log.i(Constants.TAG,
"Creating new spreadsheet really failed."); "Creating new spreadsheet really failed.");
return false; return false;
} }
@@ -287,7 +287,7 @@ public class SendToDocs {
throw new IOException("Worksheet ID lookup returned empty"); throw new IOException("Worksheet ID lookup returned empty");
} }
} catch (IOException e) { } 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; return false;
} }
@@ -295,9 +295,9 @@ public class SendToDocs {
docsHelper.addTrackRow(activity, trixAuth, spreadsheetId, worksheetId, docsHelper.addTrackRow(activity, trixAuth, spreadsheetId, worksheetId,
track, metricUnits); track, metricUnits);
Log.i(MyTracksConstants.TAG, "Done uploading to docs."); Log.i(Constants.TAG, "Done uploading to docs.");
} catch (IOException e) { } catch (IOException e) {
Log.e(MyTracksConstants.TAG, "Unable to upload docs.", e); Log.e(Constants.TAG, "Unable to upload docs.", e);
return false; return false;
} finally { } finally {
if (androidClient != null) { if (androidClient != null) {
@@ -15,7 +15,7 @@
*/ */
package com.google.android.apps.mytracks.io; package com.google.android.apps.mytracks.io;
import com.google.android.apps.mytracks.MyTracksConstants; import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.MyTracksSettings; import com.google.android.apps.mytracks.MyTracksSettings;
import com.google.android.apps.mytracks.ProgressIndicator; import com.google.android.apps.mytracks.ProgressIndicator;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils; import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
@@ -151,7 +151,7 @@ public class SendToFusionTables implements Runnable {
@Override @Override
public void run() { public void run() {
Log.d(MyTracksConstants.TAG, "Sending to Fusion tables: trackId = " + trackId); Log.d(Constants.TAG, "Sending to Fusion tables: trackId = " + trackId);
doUpload(); doUpload();
} }
@@ -172,7 +172,7 @@ public class SendToFusionTables implements Runnable {
private void doUpload() { private void doUpload() {
((GoogleHeaders) transport.defaultHeaders).setGoogleLogin(auth.getAuthToken()); ((GoogleHeaders) transport.defaultHeaders).setGoogleLogin(auth.getAuthToken());
int statusMessageId = R.string.error_sending_to_fusiontables; int statusMessageId = R.string.error_sending_to_fusiontables;
boolean success = false; boolean success = true;
try { try {
progressIndicator.setProgressValue(PROGRESS_INITIALIZATION); progressIndicator.setProgressValue(PROGRESS_INITIALIZATION);
progressIndicator.setProgressMessage(R.string.progress_message_reading_track); progressIndicator.setProgressMessage(R.string.progress_message_reading_track);
@@ -204,11 +204,10 @@ public class SendToFusionTables implements Runnable {
} }
statusMessageId = R.string.status_new_fusiontable_has_been_created; statusMessageId = R.string.status_new_fusiontable_has_been_created;
success = true; Log.d(Constants.TAG, "SendToFusionTables: Done: " + success);
Log.d(MyTracksConstants.TAG, "SendToFusionTables: Done: " + success);
progressIndicator.setProgressValue(PROGRESS_COMPLETE); progressIndicator.setProgressValue(PROGRESS_COMPLETE);
} finally { } finally {
final boolean finalSuccess = success; final boolean finalSuccess = success;
final int finalStatusMessageId = statusMessageId; final int finalStatusMessageId = statusMessageId;
context.runOnUiThread(new Runnable() { context.runOnUiThread(new Runnable() {
@@ -229,14 +228,14 @@ public class SendToFusionTables implements Runnable {
* @return true in case of success. * @return true in case of success.
*/ */
private boolean createNewTable(Track track) { 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()) + String query = "CREATE TABLE '" + sqlEscape(track.getName()) +
"' (name:STRING,description:STRING,geometry:LOCATION,marker:STRING)"; "' (name:STRING,description:STRING,geometry:LOCATION,marker:STRING)";
return runUpdate(query); return runUpdate(query);
} }
private boolean makeTableUnlisted(String tableId) { 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"; String query = "UPDATE TABLE " + tableId + " SET VISIBILITY = UNLISTED";
return runUpdate(query); return runUpdate(query);
} }
@@ -275,7 +274,7 @@ public class SendToFusionTables implements Runnable {
*/ */
private boolean createNewPoint(String name, String description, Location location, private boolean createNewPoint(String name, String description, Location location,
String marker) { 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 " String query = "INSERT INTO " + tableId + " (name,description,geometry,marker) VALUES "
+ values(name, description, getKmlPoint(location), marker); + values(name, description, getKmlPoint(location), marker);
return runUpdate(query); return runUpdate(query);
@@ -288,7 +287,7 @@ public class SendToFusionTables implements Runnable {
* @return true in case of success. * @return true in case of success.
*/ */
private boolean createNewLineString(Track track) { 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 String query = "INSERT INTO " + tableId
+ " (name,description,geometry) VALUES " + " (name,description,geometry) VALUES "
+ values(track.getName(), track.getDescription(), getKmlLineString(track)); + values(track.getName(), track.getDescription(), getKmlLineString(track));
@@ -306,7 +305,7 @@ public class SendToFusionTables implements Runnable {
Cursor locationsCursor = providerUtils.getLocationsCursor(track.getId(), 0, -1, false); Cursor locationsCursor = providerUtils.getLocationsCursor(track.getId(), 0, -1, false);
try { try {
if (!locationsCursor.moveToFirst()) { 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; return false;
} }
@@ -319,14 +318,14 @@ public class SendToFusionTables implements Runnable {
// Limit the number of elevation readings. Ideally we would want around 250. // Limit the number of elevation readings. Ideally we would want around 250.
int elevationSamplingFrequency = int elevationSamplingFrequency =
Math.max(1, (int) (totalLocations / 250.0)); Math.max(1, (int) (totalLocations / 250.0));
Log.d(MyTracksConstants.TAG, Log.d(Constants.TAG,
"Using elevation sampling factor: " + elevationSamplingFrequency "Using elevation sampling factor: " + elevationSamplingFrequency
+ " on " + totalLocations); + " on " + totalLocations);
double totalDistance = 0; double totalDistance = 0;
Vector<Double> distances = new Vector<Double>(); Vector<Double> distances = new Vector<Double>();
Vector<Double> elevations = 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); List<Location> locations = new ArrayList<Location>(MAX_POINTS_PER_UPLOAD);
Location lastLocation = null; Location lastLocation = null;
@@ -448,7 +447,7 @@ public class SendToFusionTables implements Runnable {
int numLocations = locations.size(); int numLocations = locations.size();
if (numLocations < 2) { 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; totalLocationsUploaded += numLocations;
return true; return true;
} }
@@ -464,16 +463,16 @@ public class SendToFusionTables implements Runnable {
context.getString(R.string.part), totalSegmentsUploaded)); context.getString(R.string.part), totalSegmentsUploaded));
} }
totalSegmentsUploaded++; totalSegmentsUploaded++;
Log.d(MyTracksConstants.TAG, Log.d(Constants.TAG,
"SendToFusionTables: Prepared feature for upload w/ " "SendToFusionTables: Prepared feature for upload w/ "
+ splitTrack.getLocations().size() + " points."); + splitTrack.getLocations().size() + " points.");
// Transmit tracks via GData feed: // Transmit tracks via GData feed:
// ------------------------------- // -------------------------------
Log.d(MyTracksConstants.TAG, Log.d(Constants.TAG,
"SendToFusionTables: Uploading to table " + tableId + " w/ auth " + auth); "SendToFusionTables: Uploading to table " + tableId + " w/ auth " + auth);
if (!uploadTrackPoints(splitTrack)) { if (!uploadTrackPoints(splitTrack)) {
Log.e(MyTracksConstants.TAG, "Uploading failed"); Log.e(Constants.TAG, "Uploading failed");
return false; return false;
} }
} }
@@ -519,7 +518,7 @@ public class SendToFusionTables implements Runnable {
// Close up the last segment. // Close up the last segment.
prepareTrackSegment(segment, splitTracks); prepareTrackSegment(segment, splitTracks);
Log.d(MyTracksConstants.TAG, Log.d(Constants.TAG,
"MyTracksSendToFusionTables: Starting new track segment..."); "MyTracksSendToFusionTables: Starting new track segment...");
startNewTrackSegment = false; startNewTrackSegment = false;
segment = new Track(); segment = new Track();
@@ -582,7 +581,7 @@ public class SendToFusionTables implements Runnable {
int numLocations = splitTrack.getLocations().size(); int numLocations = splitTrack.getLocations().size();
if (numLocations < 2) { if (numLocations < 2) {
// Need at least two points for a polyline: // 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 true;
} }
return createNewLineString(splitTrack); return createNewLineString(splitTrack);
@@ -605,14 +604,14 @@ public class SendToFusionTables implements Runnable {
try { try {
c = providerUtils.getWaypointsCursor( c = providerUtils.getWaypointsCursor(
track.getId(), 0, track.getId(), 0,
MyTracksConstants.MAX_LOADED_WAYPOINTS_POINTS); Constants.MAX_LOADED_WAYPOINTS_POINTS);
if (c != null) { if (c != null) {
if (c.moveToFirst()) { if (c.moveToFirst()) {
// This will skip the 1st waypoint (it carries the stats for the // This will skip the 1st waypoint (it carries the stats for the
// last segment). // last segment).
while (c.moveToNext()) { while (c.moveToNext()) {
Waypoint wpt = providerUtils.createWaypoint(c); 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(), success = createNewPoint(wpt.getName(), wpt.getDescription(), wpt.getLocation(),
MARKER_TYPE_WAYPOINT); MARKER_TYPE_WAYPOINT);
if (!success) { if (!success) {
@@ -622,7 +621,7 @@ public class SendToFusionTables implements Runnable {
} }
} }
if (!success) { if (!success) {
Log.w(MyTracksConstants.TAG, "SendToFusionTables: upload waypoints failed."); Log.w(Constants.TAG, "SendToFusionTables: upload waypoints failed.");
} }
return success; return success;
} finally { } finally {
@@ -657,7 +656,7 @@ public class SendToFusionTables implements Runnable {
wrapper.setAuthManager(auth); wrapper.setAuthManager(auth);
wrapper.setRetryOnAuthFailure(true); wrapper.setRetryOnAuthFailure(true);
wrapper.setClient(transport); 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>() { wrapper.runQuery(new QueryFunction<HttpTransport>() {
@Override @Override
public void query(HttpTransport client) public void query(HttpTransport client)
@@ -672,7 +671,7 @@ public class SendToFusionTables implements Runnable {
isc.inputStream = new ByteArrayInputStream(Strings.toBytesUtf8(sql)); isc.inputStream = new ByteArrayInputStream(Strings.toBytesUtf8(sql));
request.content = isc; 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; HttpResponse response;
try { try {
response = request.execute(); response = request.execute();
@@ -687,12 +686,12 @@ public class SendToFusionTables implements Runnable {
String[] lines = s.split(Strings.LINE_SEPARATOR); String[] lines = s.split(Strings.LINE_SEPARATOR);
if (lines[0].equals("tableid")) { if (lines[0].equals("tableid")) {
tableId = lines[1]; tableId = lines[1];
Log.d(MyTracksConstants.TAG, "tableId = " + tableId); Log.d(Constants.TAG, "tableId = " + tableId);
} else { } else {
Log.w(MyTracksConstants.TAG, "Unrecognized response: " + lines[0]); Log.w(Constants.TAG, "Unrecognized response: " + lines[0]);
} }
} else { } else {
Log.d(MyTracksConstants.TAG, "Query failed: " + response.statusMessage + " (" + Log.d(Constants.TAG, "Query failed: " + response.statusMessage + " (" +
response.statusCode + ")"); response.statusCode + ")");
throw new GDataWrapper.HttpException(response.statusCode, response.statusMessage); throw new GDataWrapper.HttpException(response.statusCode, response.statusMessage);
} }
@@ -15,14 +15,14 @@
*/ */
package com.google.android.apps.mytracks.io; package com.google.android.apps.mytracks.io;
import com.google.android.apps.mytracks.MyTracksConstants; import static com.google.android.apps.mytracks.Constants.TAG;
import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.MyTracksSettings; import com.google.android.apps.mytracks.MyTracksSettings;
import com.google.android.apps.mytracks.ProgressIndicator; import com.google.android.apps.mytracks.ProgressIndicator;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils; import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.content.Track; import com.google.android.apps.mytracks.content.Track;
import com.google.android.apps.mytracks.content.Waypoint; import com.google.android.apps.mytracks.content.Waypoint;
import com.google.android.apps.mytracks.io.mymaps.MapsFacade; import com.google.android.apps.mytracks.io.mymaps.MapsFacade;
import com.google.android.apps.mytracks.io.mymaps.MapsFacade.WaypointData;
import com.google.android.apps.mytracks.stats.DoubleBuffer; import com.google.android.apps.mytracks.stats.DoubleBuffer;
import com.google.android.apps.mytracks.stats.TripStatistics; import com.google.android.apps.mytracks.stats.TripStatistics;
import com.google.android.apps.mytracks.util.MyTracksUtils; import com.google.android.apps.mytracks.util.MyTracksUtils;
@@ -93,7 +93,7 @@ public class SendToMyMaps implements Runnable {
@Override @Override
public void run() { public void run() {
Log.d(MyTracksConstants.TAG, "Sending to MyMaps: trackId = " + trackId); Log.d(TAG, "Sending to MyMaps: trackId = " + trackId);
doUpload(); doUpload();
} }
@@ -111,7 +111,7 @@ public class SendToMyMaps implements Runnable {
track.setDescription("<p>" + track.getDescription() + "</p><p>" track.setDescription("<p>" + track.getDescription() + "</p><p>"
+ stringUtils.generateTrackDescription(track, null, null) + "</p>"); + stringUtils.generateTrackDescription(track, null, null) + "</p>");
mapsClient = MyMapsFactory.newMapsClient(context, auth); mapsClient = new MapsFacade(context, auth);
// Create a new map if necessary: // Create a new map if necessary:
boolean isNewMap = mapId.equals(NEW_MAP_ID); boolean isNewMap = mapId.equals(NEW_MAP_ID);
@@ -142,17 +142,16 @@ public class SendToMyMaps implements Runnable {
if (success) { if (success) {
Cursor c = providerUtils.getWaypointsCursor( Cursor c = providerUtils.getWaypointsCursor(
track.getId(), 0, track.getId(), 0,
MyTracksConstants.MAX_LOADED_WAYPOINTS_POINTS); Constants.MAX_LOADED_WAYPOINTS_POINTS);
if (c != null) { if (c != null) {
try { try {
if (c.getCount() > 1 && c.moveToFirst()) { if (c.getCount() > 1 && c.moveToFirst()) {
// This will skip the 1st waypoint (it carries the stats for the // This will skip the 1st waypoint (it carries the stats for the
// last segment). // last segment).
ArrayList<WaypointData> waypoints = new ArrayList<WaypointData>(c.getCount() - 1); ArrayList<Waypoint> waypoints = new ArrayList<Waypoint>(c.getCount() - 1);
while (c.moveToNext()) { while (c.moveToNext()) {
Waypoint wpt = providerUtils.createWaypoint(c); Waypoint wpt = providerUtils.createWaypoint(c);
waypoints.add(new WaypointData( waypoints.add(wpt);
wpt.getName(), wpt.getDescription(), wpt.getIcon(), wpt.getLocation()));
} }
success = mapsClient.uploadWaypoints(mapId, waypoints); success = mapsClient.uploadWaypoints(mapId, waypoints);
@@ -165,8 +164,7 @@ public class SendToMyMaps implements Runnable {
} }
if (!success) { if (!success) {
Log.w(MyTracksConstants.TAG, Log.w(TAG, "SendToMyMaps: upload waypoints failed.");
"SendToMyMaps: upload waypoints failed.");
} }
} }
@@ -175,7 +173,7 @@ public class SendToMyMaps implements Runnable {
? R.string.status_new_mymap_has_been_created ? R.string.status_new_mymap_has_been_created
: R.string.status_tracks_have_been_uploaded; : R.string.status_tracks_have_been_uploaded;
} }
Log.d(MyTracksConstants.TAG, "SendToMyMaps: Done: " + success); Log.d(TAG, "SendToMyMaps: Done: " + success);
progressIndicator.setProgressValue(100); progressIndicator.setProgressValue(100);
} finally { } finally {
if (mapsClient != null) { if (mapsClient != null) {
@@ -210,7 +208,7 @@ public class SendToMyMaps implements Runnable {
providerUtils.getLocationsCursor(track.getId(), 0, -1, false); providerUtils.getLocationsCursor(track.getId(), 0, -1, false);
try { try {
if (!locationsCursor.moveToFirst()) { if (!locationsCursor.moveToFirst()) {
Log.w(MyTracksConstants.TAG, "Unable to get any points to upload"); Log.w(TAG, "Unable to get any points to upload");
return false; return false;
} }
@@ -223,7 +221,7 @@ public class SendToMyMaps implements Runnable {
// Limit the number of elevation readings. Ideally we would want around 250. // Limit the number of elevation readings. Ideally we would want around 250.
int elevationSamplingFrequency = int elevationSamplingFrequency =
Math.max(1, (int) (totalLocations / 250.0)); Math.max(1, (int) (totalLocations / 250.0));
Log.d(MyTracksConstants.TAG, Log.d(TAG,
"Using elevation sampling factor: " + elevationSamplingFrequency "Using elevation sampling factor: " + elevationSamplingFrequency
+ " on " + totalLocations); + " on " + totalLocations);
double totalDistance = 0; double totalDistance = 0;
@@ -231,7 +229,7 @@ public class SendToMyMaps implements Runnable {
Vector<Double> distances = new Vector<Double>(); Vector<Double> distances = new Vector<Double>();
Vector<Double> elevations = new Vector<Double>(); Vector<Double> elevations = new Vector<Double>();
DoubleBuffer elevationBuffer = DoubleBuffer elevationBuffer =
new DoubleBuffer(MyTracksConstants.ELEVATION_SMOOTHING_FACTOR); new DoubleBuffer(Constants.ELEVATION_SMOOTHING_FACTOR);
List<Location> locations = new ArrayList<Location>(MAX_POINTS_PER_UPLOAD); List<Location> locations = new ArrayList<Location>(MAX_POINTS_PER_UPLOAD);
progressIndicator.setProgressMessage( progressIndicator.setProgressMessage(
@@ -312,7 +310,7 @@ public class SendToMyMaps implements Runnable {
int numLocations = locations.size(); int numLocations = locations.size();
if (numLocations < 2) { if (numLocations < 2) {
Log.d(MyTracksConstants.TAG, "Not preparing/uploading too few points"); Log.d(TAG, "Not preparing/uploading too few points");
totalLocationsUploaded += numLocations; totalLocationsUploaded += numLocations;
return true; return true;
} }
@@ -330,16 +328,16 @@ public class SendToMyMaps implements Runnable {
context.getString(R.string.part), totalSegmentsUploaded)); context.getString(R.string.part), totalSegmentsUploaded));
} }
totalSegmentsUploaded++; totalSegmentsUploaded++;
Log.d(MyTracksConstants.TAG, Log.d(TAG,
"SendToMyMaps: Prepared feature for upload w/ " "SendToMyMaps: Prepared feature for upload w/ "
+ splitTrack.getLocations().size() + " points."); + splitTrack.getLocations().size() + " points.");
// Transmit tracks via GData feed: // Transmit tracks via GData feed:
// ------------------------------- // -------------------------------
Log.d(MyTracksConstants.TAG, Log.d(TAG,
"SendToMyMaps: Uploading to map " + mapId + " w/ auth " + auth); "SendToMyMaps: Uploading to map " + mapId + " w/ auth " + auth);
if (!mapsClient.uploadTrackPoints(mapId, splitTrack.getName(), splitTrack.getLocations())) { if (!mapsClient.uploadTrackPoints(mapId, splitTrack.getName(), splitTrack.getLocations())) {
Log.e(MyTracksConstants.TAG, "Uploading failed"); Log.e(TAG, "Uploading failed");
return false; return false;
} }
} }
@@ -385,7 +383,7 @@ public class SendToMyMaps implements Runnable {
// Close up the last segment. // Close up the last segment.
prepareTrackSegment(segment, splitTracks); prepareTrackSegment(segment, splitTracks);
Log.d(MyTracksConstants.TAG, Log.d(TAG,
"MyTracksSendToMyMaps: Starting new track segment..."); "MyTracksSendToMyMaps: Starting new track segment...");
startNewTrackSegment = false; startNewTrackSegment = false;
segment = new Track(); segment = new Track();
@@ -1,12 +1,12 @@
/* /*
* Copyright 2010 Google Inc. * Copyright 2010 Google Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); you may not * 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 * use this file except in compliance with the License. You may obtain a copy of
* the License at * the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
@@ -17,11 +17,13 @@ package com.google.android.apps.mytracks.io;
import com.google.android.apps.mytracks.content.MyTracksLocation; import com.google.android.apps.mytracks.content.MyTracksLocation;
import com.google.android.apps.mytracks.content.Sensor; 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.Track;
import com.google.android.apps.mytracks.content.Waypoint; 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.TrackWriterFactory.TrackFileFormat;
import com.google.android.apps.mytracks.util.MyTracksUtils;
import android.content.Context;
import android.location.Location; import android.location.Location;
import android.os.Build; import android.os.Build;
@@ -30,6 +32,7 @@ import java.io.PrintWriter;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Date; import java.util.Date;
import java.util.Locale;
import java.util.TimeZone; import java.util.TimeZone;
/** /**
@@ -37,20 +40,35 @@ import java.util.TimeZone;
* As defined by: * As defined by:
* http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2 * 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 * @author Sandor Dornbush
*/ */
public class TcxTrackWriter implements TrackFormatWriter { 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 PrintWriter pw = null;
private Track track; private Track track;
static final SimpleDateFormat TIMESTAMP_FORMAT = public TcxTrackWriter(Context context) {
new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); this.context = context;
static {
TIMESTAMP_FORMAT.setTimeZone(TimeZone.getTimeZone("UTC"));
}
public TcxTrackWriter() { timestampFormatter = new SimpleDateFormat(TIMESTAMP_FORMAT);
timestampFormatter.setTimeZone(TimeZone.getTimeZone("UTC"));
} }
@Override @Override
@@ -93,16 +111,13 @@ public class TcxTrackWriter implements TrackFormatWriter {
if (pw == null) { if (pw == null) {
return; return;
} }
String startTime = timestampFormatter.format(track.getStatistics().getStartTime());
pw.println(" <Activities>"); pw.println(" <Activities>");
pw.print(" <Activity Sport=\""); pw.format(" <Activity Sport=\"%s\">\n", categoryToTcxSport(track.getCategory()));
if (track.getCategory() != null) { pw.format(" <Id>%s</Id>\n", startTime);
pw.print(track.getCategory()); pw.format(" <Lap StartTime=\"%s\">\n", startTime);
}
pw.println("\">");
pw.print(" <Id>");
pw.print(TIMESTAMP_FORMAT.format(track.getStatistics().getStartTime()));
pw.println("</Id>");
pw.println(" <Lap>");
pw.print(" <TotalTimeSeconds>"); pw.print(" <TotalTimeSeconds>");
pw.print(track.getStatistics().getTotalTime() / 1000); pw.print(track.getStatistics().getTotalTime() / 1000);
pw.println("</TotalTimeSeconds>"); pw.println("</TotalTimeSeconds>");
@@ -113,7 +128,7 @@ public class TcxTrackWriter implements TrackFormatWriter {
// Calories are a required element just put in 0. // Calories are a required element just put in 0.
pw.print("<Calories>0</Calories>"); pw.print("<Calories>0</Calories>");
pw.println("<Intensity>Active</Intensity>"); pw.println("<Intensity>Active</Intensity>");
pw.println("<TriggerMethod>Manual</TriggerMethod>)"); pw.println("<TriggerMethod>Manual</TriggerMethod>");
} }
@Override @Override
@@ -130,7 +145,7 @@ public class TcxTrackWriter implements TrackFormatWriter {
} }
pw.println(" <Trackpoint>"); pw.println(" <Trackpoint>");
Date d = new Date(location.getTime()); 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.println(" <Position>");
pw.print(" <LatitudeDegrees>"); pw.print(" <LatitudeDegrees>");
@@ -194,10 +209,18 @@ public class TcxTrackWriter implements TrackFormatWriter {
} }
pw.println(" </Lap>"); pw.println(" </Lap>");
pw.print(" <Creator xsi:type=\"Device_t\">"); pw.print(" <Creator xsi:type=\"Device_t\">");
pw.print("<Name>"); pw.format("<Name>%s</Name>\n", Build.MODEL);
pw.print(Build.MODEL);
pw.print("</Name>"); // The following code is correct. ID is inconsistently capitalized in the
pw.println("</Creator>)"); // 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(" </Activity>");
pw.println(" </Activities>"); pw.println(" </Activities>");
} }
@@ -207,8 +230,31 @@ public class TcxTrackWriter implements TrackFormatWriter {
if (pw == null) { if (pw == null) {
return; return;
} }
pw.print(" <Author xsi:type=\"Application_t\">"); pw.println(" <Author xsi:type=\"Application_t\">");
pw.print("<Name>My Tracks by Google</Name>");
// 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", MyTracksUtils.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>%d</VersionMajor>\n", MyTracksUtils.getMyTracksVersion(context));
pw.format("<VersionMinor>%d</VersionMinor>\n", MyTracksUtils.isRelease(context) ? 0 : 1);
pw.println("</Version>");
pw.format("<Type>%s</Type>\n", MyTracksUtils.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("</Author>");
pw.println("</TrainingCenterDatabase>"); pw.println("</TrainingCenterDatabase>");
} }
@@ -217,4 +263,15 @@ public class TcxTrackWriter implements TrackFormatWriter {
public void writeWaypoint(Waypoint waypoint) { public void writeWaypoint(Waypoint waypoint) {
// TODO Write out the waypoints somewhere. // 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;
}
}
} }
@@ -15,7 +15,7 @@
*/ */
package com.google.android.apps.mytracks.io; package com.google.android.apps.mytracks.io;
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.MyTracksLocation;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils; import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.content.Track; import com.google.android.apps.mytracks.content.Track;
@@ -160,16 +160,16 @@ public class TrackWriter {
String fileName = fileUtils.buildUniqueFileName( String fileName = fileUtils.buildUniqueFileName(
directory, track.getName(), writer.getExtension()); directory, track.getName(), writer.getExtension());
if (fileName == null) { if (fileName == null) {
Log.e(MyTracksConstants.TAG, Log.e(Constants.TAG,
"Unable to get a unique filename for " + fileName); "Unable to get a unique filename for " + fileName);
return false; return false;
} }
Log.i(MyTracksConstants.TAG, "Writing track to: " + fileName); Log.i(Constants.TAG, "Writing track to: " + fileName);
try { try {
writer.prepare(track, newOutputStream(fileName)); writer.prepare(track, newOutputStream(fileName));
} catch (FileNotFoundException e) { } 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; errorMessage = R.string.io_write_failed;
return false; return false;
} }
@@ -187,12 +187,12 @@ public class TrackWriter {
} }
if (!fileUtils.isSdCardAvailable()) { 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; errorMessage = R.string.io_no_external_storage_found;
return false; return false;
} }
if (!fileUtils.ensureDirectoryExists(directory)) { 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; errorMessage = R.string.io_create_dir_failed;
return false; return false;
} }
@@ -230,7 +230,7 @@ public class TrackWriter {
// same time. // same time.
Cursor cursor = null; Cursor cursor = null;
cursor = providerUtils.getWaypointsCursor(trackId, 0, cursor = providerUtils.getWaypointsCursor(trackId, 0,
MyTracksConstants.MAX_LOADED_WAYPOINTS_POINTS); Constants.MAX_LOADED_WAYPOINTS_POINTS);
if (cursor != null) { if (cursor != null) {
try { try {
if (cursor.moveToFirst()) { if (cursor.moveToFirst()) {
@@ -253,14 +253,14 @@ public class TrackWriter {
* Does the actual work of writing the track to the now open file. * Does the actual work of writing the track to the now open file.
*/ */
void writeDocument() { void writeDocument() {
Log.d(MyTracksConstants.TAG, "Started writing track."); Log.d(Constants.TAG, "Started writing track.");
writer.writeHeader(); writer.writeHeader();
writeWaypoints(track.getId()); writeWaypoints(track.getId());
writeLocations(); writeLocations();
writer.writeFooter(); writer.writeFooter();
writer.close(); writer.close();
success = true; success = true;
Log.d(MyTracksConstants.TAG, "Done writing track."); Log.d(Constants.TAG, "Done writing track.");
errorMessage = R.string.io_write_finished; errorMessage = R.string.io_write_finished;
} }
@@ -296,7 +296,7 @@ public class TrackWriter {
locationFactory); locationFactory);
try { try {
if (!it.hasNext()) { 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; return;
} }
while (it.hasNext()) { while (it.hasNext()) {
@@ -1,12 +1,12 @@
/* /*
* Copyright 2010 Google Inc. * Copyright 2010 Google Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); you may not * 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 * use this file except in compliance with the License. You may obtain a copy of
* the License at * the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
@@ -53,7 +53,7 @@ public class TrackWriterFactory {
TCX { TCX {
@Override @Override
public TrackFormatWriter newFormatWriter(Context context) { public TrackFormatWriter newFormatWriter(Context context) {
return new TcxTrackWriter(); return new TcxTrackWriter(context);
} }
}; };
@@ -16,7 +16,7 @@
package com.google.android.apps.mytracks.io.backup; package com.google.android.apps.mytracks.io.backup;
import com.google.android.apps.mytracks.MyTracks; 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.apps.mytracks.util.FileUtils;
import com.google.android.maps.mytracks.R; import com.google.android.maps.mytracks.R;
@@ -97,7 +97,7 @@ public class BackupActivityHelper {
backup.writeToDefaultFile(); backup.writeToDefaultFile();
showToast(R.string.io_write_finished); showToast(R.string.io_write_finished);
} catch (IOException e) { } 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); showToast(R.string.io_write_failed);
} finally { } finally {
dismissDialog(progressDialog); dismissDialog(progressDialog);
@@ -199,7 +199,7 @@ public class BackupActivityHelper {
backup.restoreFromDate(date); backup.restoreFromDate(date);
showToast(R.string.io_read_finished); showToast(R.string.io_read_finished);
} catch (IOException e) { } 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); showToast(R.string.io_read_failed);
} finally { } finally {
dismissDialog(progressDialog); dismissDialog(progressDialog);
@@ -15,7 +15,7 @@
*/ */
package com.google.android.apps.mytracks.io.backup; package com.google.android.apps.mytracks.io.backup;
import com.google.android.apps.mytracks.MyTracksConstants; import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.MyTracksSettings; import com.google.android.apps.mytracks.MyTracksSettings;
import com.google.android.apps.mytracks.content.TrackPointsColumns; import com.google.android.apps.mytracks.content.TrackPointsColumns;
import com.google.android.apps.mytracks.content.TracksColumns; import com.google.android.apps.mytracks.content.TracksColumns;
@@ -88,7 +88,7 @@ class ExternalFileBackup {
private File getBackupsDirectory(boolean create) { private File getBackupsDirectory(boolean create) {
String dirName = fileUtils.buildExternalDirectoryPath(BACKUPS_SUBDIR); String dirName = fileUtils.buildExternalDirectoryPath(BACKUPS_SUBDIR);
final File dir = new File(dirName); final File dir = new File(dirName);
Log.d(MyTracksConstants.TAG, "Dir: " + dir.getAbsolutePath()); Log.d(Constants.TAG, "Dir: " + dir.getAbsolutePath());
if (create) { if (create) {
// Try to create - if that fails, return null // Try to create - if that fails, return null
return fileUtils.ensureDirectoryExists(dir) ? dir : null; return fileUtils.ensureDirectoryExists(dir) ? dir : null;
@@ -147,7 +147,7 @@ class ExternalFileBackup {
* Synchronously writes a backup to the given file. * Synchronously writes a backup to the given file.
*/ */
private void writeToFile(File outputFile) throws IOException { private void writeToFile(File outputFile) throws IOException {
Log.d(MyTracksConstants.TAG, Log.d(Constants.TAG,
"Writing backup to file " + outputFile.getAbsolutePath()); "Writing backup to file " + outputFile.getAbsolutePath());
// Create all the auxiliary classes that will do the writing // Create all the auxiliary classes that will do the writing
@@ -219,7 +219,7 @@ class ExternalFileBackup {
* Synchronously restores the backup from the given file. * Synchronously restores the backup from the given file.
*/ */
private void restoreFromFile(File inputFile) throws IOException { private void restoreFromFile(File inputFile) throws IOException {
Log.d(MyTracksConstants.TAG, Log.d(Constants.TAG,
"Restoring from file " + inputFile.getAbsolutePath()); "Restoring from file " + inputFile.getAbsolutePath());
PreferenceBackupHelper preferencesHelper = new PreferenceBackupHelper(); PreferenceBackupHelper preferencesHelper = new PreferenceBackupHelper();
@@ -15,7 +15,7 @@
*/ */
package com.google.android.apps.mytracks.io.backup; package com.google.android.apps.mytracks.io.backup;
import com.google.android.apps.mytracks.MyTracksConstants; import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.MyTracksSettings; import com.google.android.apps.mytracks.MyTracksSettings;
import android.app.backup.BackupAgent; import android.app.backup.BackupAgent;
@@ -40,12 +40,12 @@ public class MyTracksBackupAgent extends BackupAgent {
@Override @Override
public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data, public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
ParcelFileDescriptor newState) throws IOException { ParcelFileDescriptor newState) throws IOException {
Log.i(MyTracksConstants.TAG, "Performing backup"); Log.i(Constants.TAG, "Performing backup");
SharedPreferences preferences = this.getSharedPreferences( SharedPreferences preferences = this.getSharedPreferences(
MyTracksSettings.SETTINGS_NAME, 0); MyTracksSettings.SETTINGS_NAME, 0);
backupPreferences(data, preferences); backupPreferences(data, preferences);
Log.i(MyTracksConstants.TAG, "Backup complete"); Log.i(Constants.TAG, "Backup complete");
} }
private void backupPreferences(BackupDataOutput data, private void backupPreferences(BackupDataOutput data,
@@ -63,18 +63,18 @@ public class MyTracksBackupAgent extends BackupAgent {
@Override @Override
public void onRestore(BackupDataInput data, int appVersionCode, public void onRestore(BackupDataInput data, int appVersionCode,
ParcelFileDescriptor newState) throws IOException { ParcelFileDescriptor newState) throws IOException {
Log.i(MyTracksConstants.TAG, "Restoring from backup"); Log.i(Constants.TAG, "Restoring from backup");
while (data.readNextHeader()) { while (data.readNextHeader()) {
String key = data.getKey(); String key = data.getKey();
Log.d(MyTracksConstants.TAG, "Restoring entity " + key); Log.d(Constants.TAG, "Restoring entity " + key);
if (key.equals(PREFERENCES_ENTITY)) { if (key.equals(PREFERENCES_ENTITY)) {
restorePreferences(data); restorePreferences(data);
} else { } else {
Log.e(MyTracksConstants.TAG, "Found unknown backup entity: " + key); Log.e(Constants.TAG, "Found unknown backup entity: " + key);
data.skipEntityData(); data.skipEntityData();
} }
} }
Log.i(MyTracksConstants.TAG, "Done restoring from backup"); Log.i(Constants.TAG, "Done restoring from backup");
} }
/** /**
@@ -15,7 +15,7 @@
*/ */
package com.google.android.apps.mytracks.io.docs; 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.content.Track;
import com.google.android.apps.mytracks.io.AuthManager; import com.google.android.apps.mytracks.io.AuthManager;
import com.google.android.apps.mytracks.io.gdata.GDataWrapper; import com.google.android.apps.mytracks.io.gdata.GDataWrapper;
@@ -144,7 +144,7 @@ public class DocsHelper {
String id = result.substring( String id = result.substring(
idStringStart + DOCS_SPREADSHEET_URL.length(), idTagCloseIndex); 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); idSaver.set(id);
}}); }});
@@ -184,7 +184,7 @@ public class DocsHelper {
while (listParser.hasMoreData()) { while (listParser.hasMoreData()) {
Entry entry = listParser.readNextEntry(null); Entry entry = listParser.readNextEntry(null);
String entryTitle = entry.getTitle(); String entryTitle = entry.getTitle();
Log.i(MyTracksConstants.TAG, "Found docs entry: " + entryTitle); Log.i(Constants.TAG, "Found docs entry: " + entryTitle);
if (entryTitle.equals(title)) { if (entryTitle.equals(title)) {
String entryId = entry.getId(); String entryId = entry.getId();
int lastSlash = entryId.lastIndexOf('/'); int lastSlash = entryId.lastIndexOf('/');
@@ -233,7 +233,7 @@ public class DocsHelper {
trixWrapper.getAuthManager().getAuthToken()); trixWrapper.getAuthManager().getAuthToken());
sheetParser.init(); sheetParser.init();
if (!sheetParser.hasMoreData()) { if (!sheetParser.hasMoreData()) {
Log.i(MyTracksConstants.TAG, "Found no worksheets"); Log.i(Constants.TAG, "Found no worksheets");
return; return;
} }
@@ -308,7 +308,7 @@ public class DocsHelper {
if (track.getMapId().length() > 0) { if (track.getMapId().length() > 0) {
tagBuilder.append("map", String.format("%s?msa=0&msid=%s", 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() String postText = new StringBuilder()
@@ -319,14 +319,14 @@ public class DocsHelper {
.append("</entry>") .append("</entry>")
.toString(); .toString();
Log.i(MyTracksConstants.TAG, Log.i(Constants.TAG,
"Inserting at: " + spreadsheetId + " => " + worksheetUri); "Inserting at: " + spreadsheetId + " => " + worksheetUri);
Log.i(MyTracksConstants.TAG, postText); Log.i(Constants.TAG, postText);
writeRowData(trixAuth, worksheetUri, 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; String line;
while ((line = rd.readLine()) != null) { while ((line = rd.readLine()) != null) {
// Process line. // Process line.
Log.i(MyTracksConstants.TAG, "r: " + line); Log.i(Constants.TAG, "r: " + line);
} }
wr.close(); wr.close();
rd.close(); rd.close();
@@ -15,7 +15,7 @@
*/ */
package com.google.android.apps.mytracks.io.gdata; 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 com.google.wireless.gdata.client.GDataClient;
import android.content.Context; import android.content.Context;
@@ -43,7 +43,7 @@ public class GDataClientFactory {
} catch (LinkageError e) { } catch (LinkageError e) {
// On all other platforms use the client implementation packaged in the // On all other platforms use the client implementation packaged in the
// apk. // 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(); return new com.google.android.apps.mytracks.io.gdata.AndroidGDataClient();
} }
} }
@@ -15,7 +15,7 @@
*/ */
package com.google.android.apps.mytracks.io.gdata; 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 com.google.android.apps.mytracks.io.AuthManager;
import android.util.Log; import android.util.Log;
@@ -173,14 +173,14 @@ public class GDataWrapper<C> {
return true; 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 (errorType == ERROR_AUTH && auth != null) {
if (!retryOnAuthFailure || !invalidateAndRefreshAuthToken()) { if (!retryOnAuthFailure || !invalidateAndRefreshAuthToken()) {
return false; return false;
} }
} }
Log.d(MyTracksConstants.TAG, "retrying function/query"); Log.d(Constants.TAG, "retrying function/query");
} }
return false; return false;
} }
@@ -206,11 +206,11 @@ public class GDataWrapper<C> {
errorMessage = null; errorMessage = null;
} catch (AuthenticationException e) { } catch (AuthenticationException e) {
Log.e(MyTracksConstants.TAG, "AuthenticationException", e); Log.e(Constants.TAG, "AuthenticationException", e);
errorType = ERROR_AUTH; errorType = ERROR_AUTH;
errorMessage = e.getMessage(); errorMessage = e.getMessage();
} catch (HttpException e) { } catch (HttpException e) {
Log.e(MyTracksConstants.TAG, Log.e(Constants.TAG,
"HttpException, code " + e.getStatusCode() + " message " + e.getMessage(), e); "HttpException, code " + e.getStatusCode() + " message " + e.getMessage(), e);
errorMessage = e.getMessage(); errorMessage = e.getMessage();
if (e.getStatusCode() == 401) { if (e.getStatusCode() == 401) {
@@ -219,11 +219,11 @@ public class GDataWrapper<C> {
errorType = ERROR_CONNECTION; errorType = ERROR_CONNECTION;
} }
} catch (FileNotFoundException e) { } catch (FileNotFoundException e) {
Log.e(MyTracksConstants.TAG, "Exception", e); Log.e(Constants.TAG, "Exception", e);
errorType = ERROR_AUTH; errorType = ERROR_AUTH;
errorMessage = e.getMessage(); errorMessage = e.getMessage();
} catch (IOException e) { } catch (IOException e) {
Log.e(MyTracksConstants.TAG, "Exception", e); Log.e(Constants.TAG, "Exception", e);
errorMessage = e.getMessage(); errorMessage = e.getMessage();
if (errorMessage != null && errorMessage.contains("503")) { if (errorMessage != null && errorMessage.contains("503")) {
errorType = ERROR_INTERNAL; errorType = ERROR_INTERNAL;
@@ -231,11 +231,11 @@ public class GDataWrapper<C> {
errorType = ERROR_CONNECTION; errorType = ERROR_CONNECTION;
} }
} catch (ParseException e) { } catch (ParseException e) {
Log.e(MyTracksConstants.TAG, "Exception", e); Log.e(Constants.TAG, "Exception", e);
errorType = ERROR_LOCAL; errorType = ERROR_LOCAL;
errorMessage = e.getMessage(); errorMessage = e.getMessage();
} catch (ConflictDetectedException e) { } catch (ConflictDetectedException e) {
Log.e(MyTracksConstants.TAG, "Exception", e); Log.e(Constants.TAG, "Exception", e);
errorType = ERROR_CONFLICT; errorType = ERROR_CONFLICT;
errorMessage = e.getMessage(); errorMessage = e.getMessage();
} }
@@ -249,7 +249,7 @@ public class GDataWrapper<C> {
* times out. * times out.
*/ */
private boolean invalidateAndRefreshAuthToken() { 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 // This FutureTask doesn't do anything -- it exists simply to be
// blocked upon using get(). // blocked upon using get().
FutureTask<?> whenFinishedFuture = new FutureTask<Object>(new Runnable() { FutureTask<?> whenFinishedFuture = new FutureTask<Object>(new Runnable() {
@@ -259,18 +259,18 @@ public class GDataWrapper<C> {
auth.invalidateAndRefresh(whenFinishedFuture); auth.invalidateAndRefresh(whenFinishedFuture);
try { try {
Log.d(MyTracksConstants.TAG, "waiting for invalidate"); Log.d(Constants.TAG, "waiting for invalidate");
whenFinishedFuture.get(AUTH_TOKEN_INVALIDATE_REFRESH_TIMEOUT, whenFinishedFuture.get(AUTH_TOKEN_INVALIDATE_REFRESH_TIMEOUT,
TimeUnit.MILLISECONDS); TimeUnit.MILLISECONDS);
Log.d(MyTracksConstants.TAG, "invalidate finished"); Log.d(Constants.TAG, "invalidate finished");
return true; return true;
} catch (InterruptedException e) { } catch (InterruptedException e) {
Log.e(MyTracksConstants.TAG, "Failed to invalidate", e); Log.e(Constants.TAG, "Failed to invalidate", e);
} catch (ExecutionException e) { } catch (ExecutionException e) {
Log.e(MyTracksConstants.TAG, "Failed to invalidate", e); Log.e(Constants.TAG, "Failed to invalidate", e);
} catch (TimeoutException 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 { } finally {
whenFinishedFuture.cancel(false); whenFinishedFuture.cancel(false);
} }
@@ -0,0 +1,50 @@
// Copyright 2009 Google Inc. All Rights Reserved.
package com.google.android.apps.mytracks.io.mymaps;
import com.google.android.maps.GeoPoint;
/**
* A rectangle in geographical space.
*/
class GeoRect {
public int top;
public int left;
public int bottom;
public int right;
public GeoRect() {
top = 0;
left = 0;
bottom = 0;
right = 0;
}
public GeoRect(GeoPoint center, int latSpan, int longSpan) {
top = center.getLatitudeE6() - latSpan / 2;
left = center.getLongitudeE6() - longSpan / 2;
bottom = center.getLatitudeE6() + latSpan / 2;
right = center.getLongitudeE6() + longSpan / 2;
}
public GeoPoint getCenter() {
return new GeoPoint(top / 2 + bottom / 2, left / 2 + right / 2);
}
public int getLatSpan() {
return bottom - top;
}
public int getLongSpan() {
return right - left;
}
public boolean contains(GeoPoint geoPoint) {
if (geoPoint.getLatitudeE6() >= top
&& geoPoint.getLatitudeE6() <= bottom
&& geoPoint.getLongitudeE6() >= left
&& geoPoint.getLongitudeE6() <= right) {
return true;
}
return false;
}
}
@@ -0,0 +1,36 @@
// Copyright 2010 Google Inc. All Rights Reserved.
package com.google.android.apps.mytracks.io.mymaps;
import com.google.wireless.gdata.data.Entry;
import java.util.HashMap;
import java.util.Map;
/**
* GData entry for a map feature.
*/
class MapFeatureEntry extends Entry {
private String mPrivacy = null;
private Map<String, String> mAttributes = new HashMap<String, String>();
public void setPrivacy(String privacy) {
mPrivacy = privacy;
}
public String getPrivacy() {
return mPrivacy;
}
public void setAttribute(String name, String value) {
mAttributes.put(name, value);
}
public void removeAttribute(String name) {
mAttributes.remove(name);
}
public Map<String, String> getAllAttributes() {
return mAttributes;
}
}
@@ -0,0 +1,101 @@
// Copyright 2010 Google Inc. All Rights Reserved.
package com.google.android.apps.mytracks.io.mymaps;
import com.google.wireless.gdata.client.GDataClient;
import com.google.wireless.gdata.client.GDataParserFactory;
import com.google.wireless.gdata.client.GDataServiceClient;
import android.util.Log;
/**
* Client to talk to Google Maps via GData.
*/
class MapsClient extends GDataServiceClient {
private static final boolean DEBUG = false;
public static final boolean LOG_COMMUNICATION = false;
private static final String MAPS_BASE_FEED_URL =
"http://maps.google.com/maps/feeds/";
private static final String MAPS_MAP_FEED_PATH = "maps/default/full";
private static final String MAPS_FEATURE_FEED_PATH_BEFORE_MAPID = "features/";
private static final String MAPS_FEATURE_FEED_PATH_AFTER_MAPID = "/full";
private static final String MAPS_VERSION_FEED_PATH_FORMAT =
"%smaps/%s/versions/%s/full/%s";
private static final String MAP_ENTRY_ID_BEFORE_USER_ID = "maps/feeds/maps/";
private static final String MAP_ENTRY_ID_BETWEEN_USER_ID_AND_MAP_ID = "/";
private static final String V2_ONLY_PARAM = "?v=2.0";
public MapsClient(GDataClient dataClient,
GDataParserFactory dataParserFactory) {
super(dataClient, dataParserFactory);
}
@Override
public String getServiceName() {
return MyMapsConstants.SERVICE_NAME;
}
public static String buildMapUrl(String mapId) {
return MyMapsConstants.MAPSHOP_BASE_URL + "?msa=0&msid=" + mapId;
}
public static String getMapsFeed() {
if (DEBUG) {
Log.d("Maps Client", "Requesting map feed:");
}
return MAPS_BASE_FEED_URL + MAPS_MAP_FEED_PATH + V2_ONLY_PARAM;
}
public static String getFeaturesFeed(String mapid) {
StringBuilder feed = new StringBuilder();
feed.append(MAPS_BASE_FEED_URL);
feed.append(MAPS_FEATURE_FEED_PATH_BEFORE_MAPID);
feed.append(mapid);
feed.append(MAPS_FEATURE_FEED_PATH_AFTER_MAPID);
feed.append(V2_ONLY_PARAM);
return feed.toString();
}
public static String getMapIdFromMapEntryId(String entryId) {
String userId = null;
String mapId = null;
if (DEBUG) {
Log.d("Maps GData Client", "Getting mapid from entry id: " + entryId);
}
int userIdStart =
entryId.indexOf(MAP_ENTRY_ID_BEFORE_USER_ID)
+ MAP_ENTRY_ID_BEFORE_USER_ID.length();
int userIdEnd =
entryId.indexOf(MAP_ENTRY_ID_BETWEEN_USER_ID_AND_MAP_ID, userIdStart);
if (userIdStart >= 0 && userIdEnd < entryId.length()
&& userIdStart <= userIdEnd) {
userId = entryId.substring(userIdStart, userIdEnd);
}
int mapIdStart =
entryId.indexOf(MAP_ENTRY_ID_BETWEEN_USER_ID_AND_MAP_ID, userIdEnd)
+ MAP_ENTRY_ID_BETWEEN_USER_ID_AND_MAP_ID.length();
if (mapIdStart >= 0 && mapIdStart < entryId.length()) {
mapId = entryId.substring(mapIdStart);
}
if (userId == null) {
userId = "";
}
if (mapId == null) {
mapId = "";
}
if (DEBUG) {
Log.d("Maps GData Client", "Got user id: " + userId);
Log.d("Maps GData Client", "Got map id: " + mapId);
}
return userId + "." + mapId;
}
public static String getVersionFeed(String versionUserId,
String versionClient, String currentVersion) {
return String.format(MAPS_VERSION_FEED_PATH_FORMAT,
MAPS_BASE_FEED_URL, versionUserId,
versionClient, currentVersion);
}
}
@@ -0,0 +1,372 @@
// Copyright 2011 Google Inc. All Rights Reserved.
package com.google.android.apps.mytracks.io.mymaps;
import com.google.android.apps.mytracks.content.Waypoint;
import com.google.android.apps.mytracks.io.AuthManager;
import com.google.android.maps.GeoPoint;
import com.google.android.maps.mytracks.R;
import com.google.wireless.gdata.client.HttpException;
import com.google.wireless.gdata.data.Entry;
import com.google.wireless.gdata.parser.GDataParser;
import com.google.wireless.gdata.parser.ParseException;
import android.content.Context;
import android.location.Location;
import android.text.TextUtils;
import android.util.Log;
import java.io.IOException;
import java.util.Collection;
import org.xmlpull.v1.XmlPullParserException;
/**
* Single interface which abstracts all access to the Google Maps service.
*
* @author Rodrigo Damazio
*/
public class MapsFacade {
/**
* Interface for receiving data back from getMapsList.
* All calls to the interface will happen before getMapsList returns.
*/
public interface MapsListCallback {
void onReceivedMapListing(String mapId, String title, String description,
boolean isPublic);
}
private static final String END_ICON_URL =
"http://maps.google.com/mapfiles/ms/micons/red-dot.png";
private static final String START_ICON_URL =
"http://maps.google.com/mapfiles/ms/micons/green-dot.png";
private final Context context;
private final MyMapsGDataWrapper wrapper;
private final MyMapsGDataConverter gdataConverter;
private final String authToken;
public MapsFacade(Context context, AuthManager auth) {
this.context = context;
this.authToken = auth.getAuthToken();
wrapper = new MyMapsGDataWrapper(context, auth);
wrapper.setRetryOnAuthFailure(true);
try {
gdataConverter = new MyMapsGDataConverter();
} catch (XmlPullParserException e) {
throw new IllegalStateException("Unable to create maps data converter", e);
}
}
public static String buildMapUrl(String mapId) {
return MapsClient.buildMapUrl(mapId);
}
/**
* Returns a list of all maps for the current user.
*
* @param callback callback to call for each map returned
* @return true on success, false otherwise
*/
public boolean getMapsList(final MapsListCallback callback) {
return wrapper.runQuery(new MyMapsGDataWrapper.QueryFunction() {
@Override
public void query(MapsClient client) throws IOException, Exception {
GDataParser listParser = client.getParserForFeed(
MapFeatureEntry.class, MapsClient.getMapsFeed(), authToken);
listParser.init();
while (listParser.hasMoreData()) {
MapFeatureEntry entry =
(MapFeatureEntry) listParser.readNextEntry(null);
MyMapsMapMetadata metadata =
MyMapsGDataConverter.getMapMetadataForEntry(entry);
String mapId = MyMapsGDataConverter.getMapidForEntry(entry);
callback.onReceivedMapListing(
mapId, metadata.getTitle(), metadata.getDescription(), metadata.getSearchable());
}
listParser.close();
listParser = null;
}
});
}
/**
* Creates a new map for the current user.
*
* @param title title of the map
* @param category category of the map
* @param description description for the map
* @param isPublic whether the map should be public
* @param mapIdBuilder builder to append the map ID to
* @return true on success, false otherwise
*/
public boolean createNewMap(
final String title, final String category, final String description,
final boolean isPublic, final StringBuilder mapIdBuilder) {
if (mapIdBuilder.length() > 0) {
throw new IllegalArgumentException("mapIdBuilder should be empty");
}
return wrapper.runQuery(new MyMapsGDataWrapper.QueryFunction() {
@Override
public void query(MapsClient client) throws IOException, Exception {
Log.d(MyMapsConstants.TAG, "Creating a new map.");
String mapFeed = MapsClient.getMapsFeed();
Log.d(MyMapsConstants.TAG, "Map feed is " + mapFeed);
MyMapsMapMetadata metaData = new MyMapsMapMetadata();
metaData.setTitle(title);
metaData.setDescription(description + " - "
+ category + " - " + context.getString(R.string.new_map_description));
metaData.setSearchable(isPublic);
Entry entry = MyMapsGDataConverter.getMapEntryForMetadata(metaData);
Log.d(MyMapsConstants.TAG, "Title: " + entry.getTitle());
Entry map = client.createEntry(mapFeed, authToken, entry);
String mapId = MapsClient.getMapIdFromMapEntryId(map.getId());
mapIdBuilder.append(mapId);
Log.d(MyMapsConstants.TAG, "New map id is: " + mapId);
}
});
}
/**
* Uploads a single start or end marker to the given map.
*
* @param mapId ID of the map to upload to
* @param trackName name of the track being started/ended
* @param trackDescription description of the track being started/ended
* @param location the location of the marker
* @param isStart true to add a start marker, false to add an end marker
* @return true on success, false otherwise
*/
public boolean uploadMarker(final String mapId, final String trackName,
final String trackDescription, final Location loc, final boolean isStart) {
return wrapper.runQuery(new MyMapsGDataWrapper.QueryFunction() {
@Override
public void query(MapsClient client)
throws IOException, Exception {
String featureFeed = MapsClient.getFeaturesFeed(mapId);
GeoPoint geoPoint = getGeoPoint(loc);
insertMarker(client, featureFeed, trackName, trackDescription, geoPoint, isStart);
}
});
}
/**
* Inserts a place mark. Second try if 1st try fails. Will throw exception on
* 2nd failure.
*/
private void insertMarker(MapsClient client,
String featureFeed,
String trackName, String trackDescription,
GeoPoint geoPoint,
boolean isStart) throws IOException, Exception {
MyMapsFeature feature =
buildMyMapsPlacemarkFeature(trackName, trackDescription, geoPoint, isStart);
Entry entry = gdataConverter.getEntryForFeature(feature);
Log.d(MyMapsConstants.TAG, "SendToMyMaps: Creating placemark "
+ entry.getTitle());
try {
client.createEntry(featureFeed, authToken, entry);
Log.d(MyMapsConstants.TAG, "SendToMyMaps: createEntry success!");
} catch (IOException e) {
Log.w(MyMapsConstants.TAG,
"SendToMyMaps: createEntry 1st try failed. Trying again.");
// Retry once (often IOException is thrown on a timeout):
client.createEntry(featureFeed, authToken, entry);
Log.d(MyMapsConstants.TAG,
"SendToMyMaps: createEntry success on 2nd try!");
}
}
/**
* Builds a placemark MyMapsFeature from a track.
*
* @param track the track
* @param isStart true if it's the start of the track, or false for end
* @return a MyMapsFeature
*/
private MyMapsFeature buildMyMapsPlacemarkFeature(
String trackName, String trackDescription,
GeoPoint geoPoint, boolean isStart) {
String iconUrl;
if (isStart) {
iconUrl = START_ICON_URL;
} else {
iconUrl = END_ICON_URL;
}
String title = trackName + " "
+ (isStart ? context.getString(R.string.start)
: context.getString(R.string.end));
String description = isStart ? "" : trackDescription;
return buildMyMapsPlacemarkFeature(title, description, iconUrl, geoPoint);
}
/**
* Builds a MyMapsFeature from a track.
*
* @param wpt the waypoint
* @return a MyMapsFeature
*/
private static MyMapsFeature buildMyMapsPlacemarkFeature(
String title, String description, String iconUrl, GeoPoint geoPoint) {
MyMapsFeature myMapsFeature = new MyMapsFeature();
myMapsFeature.generateAndroidId();
myMapsFeature.setType(MyMapsFeature.MARKER);
myMapsFeature.setIconUrl(iconUrl);
myMapsFeature.setDescription(description);
myMapsFeature.addPoint(geoPoint);
if (TextUtils.isEmpty(title)) {
// Features must have a name (otherwise GData upload may fail):
myMapsFeature.setTitle("-");
} else {
myMapsFeature.setTitle(title);
}
myMapsFeature.setDescription(description.replaceAll("\n", "<br>"));
return myMapsFeature;
}
/**
* Uploads a series of waypoints to the given map.
*
* @param mapId ID of the map to upload to
* @param waypoints the waypoints to upload
* @return true on success, false otherwise
*/
public boolean uploadWaypoints(
final String mapId, final Iterable<Waypoint> waypoints) {
return wrapper.runQuery(new MyMapsGDataWrapper.QueryFunction() {
public void query(MapsClient client) {
// TODO(rdamazio): Stream through the waypoints in chunks.
// I am leaving the number of waypoints very high which should not be a
// problem because we don't try to load them into objects all at the
// same time.
String featureFeed = MapsClient.getFeaturesFeed(mapId);
try {
for (Waypoint waypoint : waypoints) {
MyMapsFeature feature = buildMyMapsPlacemarkFeature(
waypoint.getName(), waypoint.getDescription(), waypoint.getIcon(),
getGeoPoint(waypoint.getLocation()));
Entry entry = gdataConverter.getEntryForFeature(feature);
Log.d(MyMapsConstants.TAG,
"SendToMyMaps: Creating waypoint.");
try {
client.createEntry(featureFeed, authToken, entry);
Log.d(MyMapsConstants.TAG,
"SendToMyMaps: createEntry success!");
} catch (IOException e) {
Log.w(MyMapsConstants.TAG,
"SendToMyMaps: createEntry 1st try failed. Retrying.");
// Retry once (often IOException is thrown on a timeout):
client.createEntry(featureFeed, authToken, entry);
Log.d(MyMapsConstants.TAG,
"SendToMyMaps: createEntry success on 2nd try!");
}
}
} catch (ParseException e) {
Log.w(MyMapsConstants.TAG, "ParseException caught.", e);
} catch (HttpException e) {
Log.w(MyMapsConstants.TAG, "HttpException caught.", e);
} catch (IOException e) {
Log.w(MyMapsConstants.TAG, "IOException caught.", e);
}
}
});
}
/**
* Uploads a series of points to the given map.
*
* @param mapId ID of the map to upload to
* @param trackName the name of the track
* @param locations the locations to upload
* @return true on success, false otherwise
*/
public boolean uploadTrackPoints(
final String mapId, final String trackName, final Collection<Location> locations) {
return wrapper.runQuery(new MyMapsGDataWrapper.QueryFunction() {
@Override
public void query(MapsClient client)
throws IOException, Exception {
String featureFeed = MapsClient.getFeaturesFeed(mapId);
Log.d(MyMapsConstants.TAG, "Feature feed url: " + featureFeed);
uploadTrackPoints(client, featureFeed, trackName, locations);
}
});
}
private boolean uploadTrackPoints(
MapsClient client,
String featureFeed,
String trackName, Collection<Location> locations)
throws IOException, Exception {
Entry entry = null;
int numLocations = locations.size();
if (numLocations < 2) {
// Need at least two points for a polyline:
Log.w(MyMapsConstants.TAG, "Not uploading too few points");
return true;
}
// Put the line:
entry = gdataConverter.getEntryForFeature(
buildMyMapsLineFeature(trackName, locations));
Log.d(MyMapsConstants.TAG,
"SendToMyMaps: Creating line " + entry.getTitle());
try {
client.createEntry(featureFeed, authToken, entry);
Log.d(MyMapsConstants.TAG, "SendToMyMaps: createEntry success!");
} catch (IOException e) {
Log.w(MyMapsConstants.TAG,
"SendToMyMaps: createEntry 1st try failed. Trying again.");
// Retry once (often IOException is thrown on a timeout):
client.createEntry(featureFeed, authToken, entry);
Log.d(MyMapsConstants.TAG,
"SendToMyMaps: createEntry success on 2nd try!");
}
return true;
}
/**
* Builds a MyMapsFeature from a track.
*
* @param track the track
* @return a MyMapsFeature
*/
private static MyMapsFeature buildMyMapsLineFeature(String trackName,
Iterable<Location> locations) {
MyMapsFeature myMapsFeature = new MyMapsFeature();
myMapsFeature.generateAndroidId();
myMapsFeature.setType(MyMapsFeature.LINE);
if (TextUtils.isEmpty(trackName)) {
// Features must have a name (otherwise GData upload may fail):
myMapsFeature.setTitle("-");
} else {
myMapsFeature.setTitle(trackName);
}
myMapsFeature.setColor(0x80FF0000);
for (Location loc : locations) {
myMapsFeature.addPoint(getGeoPoint(loc));
}
return myMapsFeature;
}
/**
* Cleans up after a series of uploads.
* This closes the connection to Maps and resets retry counters.
*/
public void cleanUp() {
wrapper.cleanUp();
}
private static GeoPoint getGeoPoint(Location location) {
return new GeoPoint((int) (location.getLatitude() * 1E6),
(int) (location.getLongitude() * 1E6));
}
}
@@ -0,0 +1,17 @@
// Copyright 2009 Google Inc. All Rights Reserved.
package com.google.android.apps.mytracks.io.mymaps;
/**
* Constants for My Maps.
*/
public class MyMapsConstants {
static final String TAG = "MapsApi";
static final String MAPSHOP_BASE_URL =
"http://maps.google.com/maps/ms";
public static final String SERVICE_NAME = "local";
/**
* Private constructor to prevent instantiation.
*/
private MyMapsConstants() { }
}
@@ -0,0 +1,233 @@
// Copyright 2009 Google Inc. All Rights Reserved.
package com.google.android.apps.mytracks.io.mymaps;
import com.google.android.maps.GeoPoint;
import java.io.Serializable;
import java.util.Vector;
/**
* MyMapsFeature contains all of the data associated with a feature in My Maps,
* where a feature is a marker, line, or shape. Some of the data is stored in a
* {@link MyMapsFeatureMetadata} object so that it can be more efficiently
* transmitted to other activities.
*/
class MyMapsFeature implements Serializable {
private static final long serialVersionUID = 8439035544430497236L;
/** A marker feature displays an icon at a single point on the map. */
public static final int MARKER = 0;
/**
* A line feature displays a line connecting a set of points on the map.
*/
public static final int LINE = 1;
/**
* A shape feature displays a border defined by connecting a set of points,
* including connecting the last to the first, and displays the area
* confined by this border.
*/
public static final int SHAPE = 2;
/** The local feature id for this feature, if needed. */
private String androidId;
/**
* The latitudes of the points of this feature in order, specified in
* millionths of a degree north.
*/
private final Vector<Integer> latitudeE6 = new Vector<Integer>();
/**
* The longitudes of the points of this feature in order, specified in
* millionths of a degree east.
*/
private final Vector<Integer> longitudeE6 = new Vector<Integer>();
/** The metadata of this feature in a format efficient for transmission. */
private MyMapsFeatureMetadata featureInfo = new MyMapsFeatureMetadata();
/**
* Initializes a valid but empty feature. It will default to a
* {@link #MARKER} with a blue placemark with a dot as an icon at the
* location (0, 0).
*/
public MyMapsFeature() {
}
/**
* Adds a new point to the end of this feature.
*
* @param point The new point to add
*/
public synchronized void addPoint(GeoPoint point) {
latitudeE6.add(point.getLatitudeE6());
longitudeE6.add(point.getLongitudeE6());
}
/**
* Generates a new local id for this feature based on the current time and
* a random number.
*/
public synchronized void generateAndroidId() {
Long time = System.currentTimeMillis();
Integer random = (int) (Math.random() * 10000);
androidId = time.toString() + "." + random.toString();
}
/**
* Retrieves the current local id for this feature if one is available.
*
* @return The local id for this feature
*/
public String getAndroidId() {
return androidId;
}
/**
* Retrieves the current (html) description of this feature. The description
* is stored in the feature metadata.
*
* @return The description of this feature
*/
public String getDescription() {
return featureInfo.getDescription();
}
/**
* Sets the description of this feature. That description is stored in the
* feature metadata.
*
* @param description The new description of this feature
*/
public synchronized void setDescription(String description) {
featureInfo.setDescription(description);
}
/**
* Retrieves the point at the given index for this feature.
*
* @param index The index of the point desired
* @return A {@link GeoPoint} representing the point or null if that point
* doesn't exist
*/
public GeoPoint getPoint(int index) {
if (latitudeE6.size() <= index) {
return null;
}
return new GeoPoint(latitudeE6.get(index), longitudeE6.get(index));
}
/**
* Counts the number of points in this feature and return that count.
*
* @return The number of points in this feature
*/
public int getPointCount() {
return latitudeE6.size();
}
/**
* Retrieves the title of this feature. That title is stored in the feature
* metadata.
*
* @return the current title of this feature
*/
public String getTitle() {
return featureInfo.getTitle();
}
/**
* Retrieves the type of this feature. That type is stored in the feature
* metadata.
*
* @return One of {@link #MARKER}, {@link #LINE}, or {@link #SHAPE}
* identifying the type of this feature
*/
public int getType() {
return featureInfo.getType();
}
/**
* Retrieves the current color of this feature as an ARGB color integer.
* That color is stored in the feature metadata.
*
* @return The ARGB color of this feature
*/
public int getColor() {
return featureInfo.getColor();
}
/**
* Retrieves the current line width of this feature. That line width is
* stored in the feature metadata.
*
* @return The line width of this feature
*/
public int getLineWidth() {
return featureInfo.getLineWidth();
}
/**
* Retrieves the current fill color of this feature as an ARGB color
* integer. That color is stored in the feature metadata.
*
* @return The ARGB fill color of this feature
*/
public int getFillColor() {
return featureInfo.getFillColor();
}
/**
* Retrieves the current icon url of this feature. That icon url is stored
* in the feature metadata.
*
* @return The icon url for this feature
*/
public String getIconUrl() {
return featureInfo.getIconUrl();
}
/**
* Sets the title of this feature. That title is stored in the feature
* metadata.
*
* @param title The new title of this feature
*/
public synchronized void setTitle(String title) {
featureInfo.setTitle(title);
}
/**
* Sets the type of this feature. That type is stored in the feature
* metadata.
*
* @param type The new type of the feature. That type must be one of
* {@link #MARKER}, {@link #LINE}, or {@link #SHAPE}
*/
public synchronized void setType(int type) {
featureInfo.setType(type);
}
/**
* Sets the ARGB color of this feature. That color is stored in the feature
* metadata.
*
* @param color The new ARGB color of this feature
*/
public synchronized void setColor(int color) {
featureInfo.setColor(color);
}
/**
* Sets the icon url of this feature. That icon url is stored in the feature
* metadata.
*
* @param url The new icon url of the feature
*/
public synchronized void setIconUrl(String url) {
featureInfo.setIconUrl(url);
}
}
@@ -0,0 +1,87 @@
// Copyright 2009 Google Inc. All Rights Reserved.
package com.google.android.apps.mytracks.io.mymaps;
/**
* Metadata about a maps feature.
*/
class MyMapsFeatureMetadata {
private static final String BLUE_DOT_URL =
"http://maps.google.com/mapfiles/ms/micons/blue-dot.png";
private static final int DEFAULT_COLOR = 0x800000FF;
private static final int DEFAULT_FILL_COLOR = 0xC00000FF;
private String title;
private String description;
private int type;
private int color;
private int lineWidth;
private int fillColor;
private String iconUrl;
public MyMapsFeatureMetadata() {
title = "";
description = "";
type = MyMapsFeature.MARKER;
color = DEFAULT_COLOR;
lineWidth = 5;
fillColor = DEFAULT_FILL_COLOR;
iconUrl = BLUE_DOT_URL;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
public int getColor() {
return color;
}
public void setColor(int color) {
this.color = color;
}
public int getLineWidth() {
return lineWidth;
}
public void setLineWidth(int width) {
lineWidth = width;
}
public int getFillColor() {
return fillColor;
}
public void setFillColor(int color) {
fillColor = color;
}
public String getIconUrl() {
return iconUrl;
}
public void setIconUrl(String url) {
iconUrl = new String(url);
}
}
@@ -0,0 +1,183 @@
// Copyright 2009 Google Inc. All Rights Reserved.
package com.google.android.apps.mytracks.io.mymaps;
import com.google.wireless.gdata.data.Entry;
import com.google.wireless.gdata.data.StringUtils;
import android.graphics.Color;
import android.util.Log;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;
import org.xmlpull.v1.XmlSerializer;
import java.io.IOException;
import java.io.StringWriter;
/**
* Converter from GData objects to MyMaps objects.
*/
class MyMapsGDataConverter {
private final XmlSerializer xmlSerializer;
public MyMapsGDataConverter() throws XmlPullParserException {
xmlSerializer = XmlPullParserFactory.newInstance().newSerializer();
}
public static MyMapsMapMetadata getMapMetadataForEntry(
MapFeatureEntry entry) {
MyMapsMapMetadata metadata = new MyMapsMapMetadata();
if ("public".equals(entry.getPrivacy())) {
metadata.setSearchable(true);
} else {
metadata.setSearchable(false);
}
metadata.setTitle(entry.getTitle());
String desc = entry.getContent();
if (desc.length() > 12) {
metadata.setDescription(desc.substring(9, desc.length() - 3));
}
String editUri = entry.getEditUri();
if (editUri != null) {
metadata.setGDataEditUri(editUri);
}
return metadata;
}
public static String getMapidForEntry(Entry entry) {
return MapsClient.getMapIdFromMapEntryId(entry.getId());
}
public static Entry getMapEntryForMetadata(MyMapsMapMetadata metadata) {
MapFeatureEntry entry = new MapFeatureEntry();
entry.setEditUri(metadata.getGDataEditUri());
entry.setTitle(metadata.getTitle());
entry.setContent(metadata.getDescription());
entry.setPrivacy(metadata.getSearchable() ? "public" : "unlisted");
entry.setAuthor("android");
entry.setEmail("nobody@google.com");
return entry;
}
public MapFeatureEntry getEntryForFeature(MyMapsFeature feature) {
MapFeatureEntry entry = new MapFeatureEntry();
entry.setTitle(feature.getTitle());
entry.setAuthor("android");
entry.setEmail("nobody@google.com");
entry.setCategoryScheme("http://schemas.google.com/g/2005#kind");
entry.setCategory("http://schemas.google.com/g/2008#mapfeature");
entry.setEditUri("");
if (!StringUtils.isEmpty(feature.getAndroidId())) {
entry.setAttribute("_androidId", feature.getAndroidId());
}
try {
StringWriter writer = new StringWriter();
xmlSerializer.setOutput(writer);
xmlSerializer.startTag(null, "Placemark");
xmlSerializer.attribute(null, "xmlns", "http://earth.google.com/kml/2.2");
xmlSerializer.startTag(null, "Style");
if (feature.getType() == MyMapsFeature.MARKER) {
xmlSerializer.startTag(null, "IconStyle");
xmlSerializer.startTag(null, "Icon");
xmlSerializer.startTag(null, "href");
xmlSerializer.text(feature.getIconUrl());
xmlSerializer.endTag(null, "href");
xmlSerializer.endTag(null, "Icon");
xmlSerializer.endTag(null, "IconStyle");
} else {
xmlSerializer.startTag(null, "LineStyle");
xmlSerializer.startTag(null, "color");
int color = feature.getColor();
// Reverse the color because KML is ABGR and Android is ARGB
xmlSerializer.text(Integer.toHexString(
Color.argb(Color.alpha(color), Color.blue(color),
Color.green(color), Color.red(color))));
xmlSerializer.endTag(null, "color");
xmlSerializer.startTag(null, "width");
xmlSerializer.text(Integer.toString(feature.getLineWidth()));
xmlSerializer.endTag(null, "width");
xmlSerializer.endTag(null, "LineStyle");
if (feature.getType() == MyMapsFeature.SHAPE) {
xmlSerializer.startTag(null, "PolyStyle");
xmlSerializer.startTag(null, "color");
int fcolor = feature.getFillColor();
// Reverse the color because KML is ABGR and Android is ARGB
xmlSerializer.text(Integer.toHexString(Color.argb(Color.alpha(fcolor),
Color.blue(fcolor), Color.green(fcolor), Color.red(fcolor))));
xmlSerializer.endTag(null, "color");
xmlSerializer.startTag(null, "fill");
xmlSerializer.text("1");
xmlSerializer.endTag(null, "fill");
xmlSerializer.startTag(null, "outline");
xmlSerializer.text("1");
xmlSerializer.endTag(null, "outline");
xmlSerializer.endTag(null, "PolyStyle");
}
}
xmlSerializer.endTag(null, "Style");
xmlSerializer.startTag(null, "name");
xmlSerializer.text(feature.getTitle());
xmlSerializer.endTag(null, "name");
xmlSerializer.startTag(null, "description");
xmlSerializer.cdsect(feature.getDescription());
xmlSerializer.endTag(null, "description");
StringBuilder pointBuilder = new StringBuilder();
for (int i = 0; i < feature.getPointCount(); ++i) {
if (i > 0) {
pointBuilder.append('\n');
}
pointBuilder.append(feature.getPoint(i).getLongitudeE6() / 1e6);
pointBuilder.append(',');
pointBuilder.append(feature.getPoint(i).getLatitudeE6() / 1e6);
pointBuilder.append(",0.000000");
}
String pointString = pointBuilder.toString();
if (feature.getType() == MyMapsFeature.MARKER) {
xmlSerializer.startTag(null, "Point");
xmlSerializer.startTag(null, "coordinates");
xmlSerializer.text(pointString);
xmlSerializer.endTag(null, "coordinates");
xmlSerializer.endTag(null, "Point");
} else if (feature.getType() == MyMapsFeature.LINE) {
xmlSerializer.startTag(null, "LineString");
xmlSerializer.startTag(null, "tessellate");
xmlSerializer.text("1");
xmlSerializer.endTag(null, "tessellate");
xmlSerializer.startTag(null, "coordinates");
xmlSerializer.text(pointString);
xmlSerializer.endTag(null, "coordinates");
xmlSerializer.endTag(null, "LineString");
} else {
xmlSerializer.startTag(null, "Polygon");
xmlSerializer.startTag(null, "outerBoundaryIs");
xmlSerializer.startTag(null, "LinearRing");
xmlSerializer.startTag(null, "tessellate");
xmlSerializer.text("1");
xmlSerializer.endTag(null, "tessellate");
xmlSerializer.startTag(null, "coordinates");
xmlSerializer.text(pointString + "\n"
+ Double.toString(feature.getPoint(0).getLongitudeE6() / 1e6)
+ ","
+ Double.toString(feature.getPoint(0).getLatitudeE6() / 1e6)
+ ",0.000000");
xmlSerializer.endTag(null, "coordinates");
xmlSerializer.endTag(null, "LinearRing");
xmlSerializer.endTag(null, "outerBoundaryIs");
xmlSerializer.endTag(null, "Polygon");
}
xmlSerializer.endTag(null, "Placemark");
xmlSerializer.flush();
entry.setContent(writer.toString());
Log.d("My Google Maps", "Generated kml:\n" + entry.getContent());
Log.d("My Google Maps", "Edit URI: " + entry.getEditUri());
} catch (IOException e) {
e.printStackTrace();
}
return entry;
}
}
@@ -0,0 +1,169 @@
// Copyright 2010 Google Inc. All Rights Reserved.
package com.google.android.apps.mytracks.io.mymaps;
import com.google.android.apps.mytracks.io.AuthManager;
import com.google.android.apps.mytracks.io.gdata.GDataClientFactory;
import com.google.android.common.gdata.AndroidXmlParserFactory;
import com.google.wireless.gdata.client.GDataClient;
import com.google.wireless.gdata.client.HttpException;
import com.google.wireless.gdata.parser.xml.SimplePullParser.ParseException;
import com.google.wireless.gdata2.ConflictDetectedException;
import com.google.wireless.gdata2.client.AuthenticationException;
import android.content.Context;
import android.util.Log;
import java.io.IOException;
/**
* MyMapsGDataWrapper provides a wrapper around GData operations that maintains
* the GData client, and provides a method to run gdata queries with proper
* error handling. After a query is run, the wrapper can be queried about the
* error that occurred.
*/
class MyMapsGDataWrapper {
/**
* A QueryFunction is passed in when executing a query. The query function
* of the class is called with the GData client as a parameter. The
* function should execute whatever operations it desires on the client
* without concern for whether the client will throw an error.
*/
interface QueryFunction {
public abstract void query(MapsClient client)
throws AuthenticationException, IOException, ParseException,
ConflictDetectedException, Exception;
}
// The types of error that may be encountered
/** No error occurred. */
public static final int ERROR_NO_ERROR = 0;
/** There was an authentication error, the auth token may be invalid. */
public static final int ERROR_AUTH = 1;
/** There was an internal error on the server side. */
public static final int ERROR_INTERNAL = 2;
/** There was an error connecting to the server. */
public static final int ERROR_CONNECTION = 3;
/** The item queried did not exit. */
public static final int ERROR_NOT_FOUND = 4;
/** There was an error parsing or serializing locally. */
public static final int ERROR_LOCAL = 5;
/** There was a conflict, update the entry and try again. */
public static final int ERROR_CONFLICT = 6;
/**
* A query was run after cleaning up the wrapper, so the client was invalid.
*/
public static final int ERROR_CLEANED_UP = 7;
/** An unknown error occurred. */
public static final int ERROR_UNKNOWN = 100;
private final GDataClient androidGdataClient;
private final AuthManager auth;
private final MapsClient client;
private String errorMessage;
private int errorType;
private boolean retryOnAuthFailure;
private int retriesPending;
private boolean cleanupCalled;
public MyMapsGDataWrapper(Context context, AuthManager auth) {
androidGdataClient = GDataClientFactory.getGDataClient(context);
this.auth = auth;
client =
new MapsClient(androidGdataClient, new XmlMapsGDataParserFactory(
new AndroidXmlParserFactory()));
errorType = ERROR_NO_ERROR;
errorMessage = null;
retryOnAuthFailure = false;
retriesPending = 0;
cleanupCalled = false;
}
public boolean runQuery(final QueryFunction query) {
if (client == null) {
errorType = ERROR_CLEANED_UP;
errorMessage = "GData Wrapper has already been cleaned up!";
return false;
}
try {
query.query(client);
errorType = ERROR_NO_ERROR;
errorMessage = null;
return true;
} catch (AuthenticationException e) {
Log.e(MyMapsConstants.TAG, "Exception", e);
errorType = ERROR_AUTH;
errorMessage = e.getMessage();
} catch (HttpException e) {
Log.e(MyMapsConstants.TAG, "HttpException", e);
errorMessage = e.getMessage();
if (errorMessage != null && errorMessage.contains("401")) {
errorType = ERROR_AUTH;
} else {
errorType = ERROR_CONNECTION;
}
} catch (IOException e) {
Log.e(MyMapsConstants.TAG, "Exception", e);
errorMessage = e.getMessage();
if (errorMessage != null && errorMessage.contains("503")) {
errorType = ERROR_INTERNAL;
} else {
errorType = ERROR_CONNECTION;
}
} catch (ParseException e) {
Log.e(MyMapsConstants.TAG, "Exception", e);
errorType = ERROR_LOCAL;
errorMessage = e.getMessage();
} catch (ConflictDetectedException e) {
Log.e(MyMapsConstants.TAG, "Exception", e);
errorType = ERROR_CONFLICT;
errorMessage = e.getMessage();
} catch (Exception e) {
Log.e(MyMapsConstants.TAG, "Exception", e);
errorType = ERROR_UNKNOWN;
errorMessage = e.getMessage();
e.printStackTrace();
}
Log.d(MyMapsConstants.TAG, "GData error encountered: " + errorMessage);
if (errorType == ERROR_AUTH && auth != null) {
Runnable whenFinished = null;
if (retryOnAuthFailure) {
retriesPending++;
whenFinished = new Runnable() {
public void run() {
retriesPending--;
retryOnAuthFailure = false;
runQuery(query);
if (cleanupCalled && retriesPending == 0) {
cleanUp();
}
}
};
}
auth.invalidateAndRefresh(whenFinished);
}
return false;
}
public int getErrorType() {
return errorType;
}
public String getErrorMessage() {
return errorMessage;
}
// cleanUp must be called when done using this wrapper to close the client.
// Note that the cleanup will be delayed if auth failure retries were
// requested and there is a pending retry.
public void cleanUp() {
if (retriesPending == 0 && !cleanupCalled) {
androidGdataClient.close();
}
cleanupCalled = true;
}
public void setRetryOnAuthFailure(boolean retry) {
retryOnAuthFailure = retry;
}
}
@@ -0,0 +1,52 @@
// Copyright 2009 Google Inc. All Rights Reserved.
package com.google.android.apps.mytracks.io.mymaps;
/**
* Metadata about a "my maps" map.
*/
class MyMapsMapMetadata {
private String title;
private String description;
private String gdataEditUri;
private boolean searchable;
public MyMapsMapMetadata() {
title = "";
description = "";
gdataEditUri = "";
searchable = false;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = new String(title);
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = new String(description);
}
public boolean getSearchable() {
return searchable;
}
public void setSearchable(boolean searchable) {
this.searchable = searchable;
}
public String getGDataEditUri() {
return gdataEditUri;
}
public void setGDataEditUri(String editUri) {
this.gdataEditUri = new String(editUri);
}
}
@@ -0,0 +1,163 @@
// Copyright 2009 Google Inc. All Rights Reserved.
package com.google.android.apps.mytracks.io.mymaps;
import com.google.wireless.gdata.data.Entry;
import com.google.wireless.gdata.data.Feed;
import com.google.wireless.gdata.data.XmlUtils;
import com.google.wireless.gdata.parser.ParseException;
import com.google.wireless.gdata.parser.xml.XmlGDataParser;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
import java.io.InputStream;
/**
* Parser for XML gdata maps data.
*/
class XmlMapsGDataParser extends XmlGDataParser {
public XmlMapsGDataParser(InputStream is, XmlPullParser xpp)
throws ParseException {
super(is, xpp);
}
@Override
protected Feed createFeed() {
return new Feed();
}
@Override
protected Entry createEntry() {
return new MapFeatureEntry();
}
@Override
protected void handleExtraElementInFeed(Feed feed) {
// Do nothing
}
@Override
protected void handleExtraLinkInEntry(
String rel, String type, String href, Entry entry)
throws XmlPullParserException, IOException {
if (!(entry instanceof MapFeatureEntry)) {
throw new IllegalArgumentException("Expected MapFeatureEntry!");
}
if (rel.endsWith("#view")) {
return;
}
super.handleExtraLinkInEntry(rel, type, href, entry);
}
/**
* Parses the current entry in the XML document. Assumes that the parser is
* currently pointing just after an &lt;entry&gt;.
*
* @param plainEntry The entry that will be filled.
* @throws XmlPullParserException Thrown if the XML cannot be parsed.
* @throws IOException Thrown if the underlying inputstream cannot be read.
*/
@Override
protected void handleEntry(Entry plainEntry)
throws XmlPullParserException, IOException, ParseException {
XmlPullParser parser = getParser();
if (!(plainEntry instanceof MapFeatureEntry)) {
throw new IllegalArgumentException("Expected MapFeatureEntry!");
}
MapFeatureEntry entry = (MapFeatureEntry) plainEntry;
int eventType = parser.getEventType();
entry.setPrivacy("public");
while (eventType != XmlPullParser.END_DOCUMENT) {
switch (eventType) {
case XmlPullParser.START_TAG:
String name = parser.getName();
if ("entry".equals(name)) {
// stop parsing here.
return;
} else if ("id".equals(name)) {
entry.setId(XmlUtils.extractChildText(parser));
} else if ("title".equals(name)) {
entry.setTitle(XmlUtils.extractChildText(parser));
} else if ("link".equals(name)) {
String rel = parser.getAttributeValue(null /* ns */, "rel");
String type = parser.getAttributeValue(null /* ns */, "type");
String href = parser.getAttributeValue(null /* ns */, "href");
if ("edit".equals(rel)) {
entry.setEditUri(href);
} else if ("alternate".equals(rel) && "text/html".equals(type)) {
entry.setHtmlUri(href);
} else {
handleExtraLinkInEntry(rel, type, href, entry);
}
} else if ("summary".equals(name)) {
entry.setSummary(XmlUtils.extractChildText(parser));
} else if ("content".equals(name)) {
StringBuilder contentBuilder = new StringBuilder();
int parentDepth = parser.getDepth();
while (parser.getEventType() != XmlPullParser.END_DOCUMENT) {
int etype = parser.next();
switch (etype) {
case XmlPullParser.START_TAG:
contentBuilder.append('<');
contentBuilder.append(parser.getName());
contentBuilder.append('>');
break;
case XmlPullParser.TEXT:
contentBuilder.append("<![CDATA[");
contentBuilder.append(parser.getText());
contentBuilder.append("]]>");
break;
case XmlPullParser.END_TAG:
if (parser.getDepth() > parentDepth) {
contentBuilder.append("</");
contentBuilder.append(parser.getName());
contentBuilder.append('>');
}
break;
}
if (etype == XmlPullParser.END_TAG
&& parser.getDepth() == parentDepth) {
break;
}
}
entry.setContent(contentBuilder.toString());
} else if ("category".equals(name)) {
String category = parser.getAttributeValue(null /* ns */, "term");
if (category != null && category.length() > 0) {
entry.setCategory(category);
}
String categoryScheme =
parser.getAttributeValue(null /* ns */, "scheme");
if (categoryScheme != null && category.length() > 0) {
entry.setCategoryScheme(categoryScheme);
}
} else if ("published".equals(name)) {
entry.setPublicationDate(XmlUtils.extractChildText(parser));
} else if ("updated".equals(name)) {
entry.setUpdateDate(XmlUtils.extractChildText(parser));
} else if ("deleted".equals(name)) {
entry.setDeleted(true);
} else if ("draft".equals(name)) {
String draft = XmlUtils.extractChildText(parser);
entry.setPrivacy("yes".equals(draft) ? "unlisted" : "public");
} else if ("customProperty".equals(name)) {
String attrName = parser.getAttributeValue(null, "name");
String attrValue = XmlUtils.extractChildText(parser);
entry.setAttribute(attrName, attrValue);
} else if ("deleted".equals(name)) {
entry.setDeleted(true);
} else {
handleExtraElementInEntry(entry);
}
break;
default:
break;
}
eventType = parser.next();
}
}
}
@@ -0,0 +1,94 @@
// Copyright 2010 Google Inc. All Rights Reserved.
package com.google.android.apps.mytracks.io.mymaps;
import com.google.wireless.gdata.client.GDataParserFactory;
import com.google.wireless.gdata.data.Entry;
import com.google.wireless.gdata.parser.GDataParser;
import com.google.wireless.gdata.parser.ParseException;
import com.google.wireless.gdata.parser.xml.XmlGDataParser;
import com.google.wireless.gdata.parser.xml.XmlParserFactory;
import com.google.wireless.gdata.serializer.GDataSerializer;
import com.google.wireless.gdata.serializer.xml.XmlEntryGDataSerializer;
import android.util.Log;
import org.xmlpull.v1.XmlPullParserException;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* Factory of Xml parsers for gdata maps data.
*/
class XmlMapsGDataParserFactory implements GDataParserFactory {
private XmlParserFactory xmlFactory;
public XmlMapsGDataParserFactory(XmlParserFactory xmlFactory) {
this.xmlFactory = xmlFactory;
}
@Override
public GDataParser createParser(InputStream is) throws ParseException {
is = maybeLogCommunication(is);
try {
return new XmlGDataParser(is, xmlFactory.createParser());
} catch (XmlPullParserException e) {
e.printStackTrace();
return null;
}
}
@SuppressWarnings({ "unchecked", "rawtypes" })
@Override
public GDataParser createParser(Class cls, InputStream is)
throws ParseException {
is = maybeLogCommunication(is);
try {
return createParserForClass(cls, is);
} catch (XmlPullParserException e) {
e.printStackTrace();
return null;
}
}
private InputStream maybeLogCommunication(InputStream is)
throws ParseException {
if (MapsClient.LOG_COMMUNICATION) {
StringBuilder builder = new StringBuilder();
byte[] buffer = new byte[2048];
try {
for (int n = is.read(buffer); n >= 0; n = is.read(buffer)) {
String part = new String(buffer, 0, n);
builder.append(part);
Log.d("Response part", part);
}
} catch (IOException e) {
throw new ParseException("Could not read stream", e);
}
String whole = builder.toString();
Log.d("Response", whole);
is = new ByteArrayInputStream(whole.getBytes());
}
return is;
}
private GDataParser createParserForClass(
Class<? extends Entry> cls, InputStream is)
throws ParseException, XmlPullParserException {
if (cls == MapFeatureEntry.class) {
return new XmlMapsGDataParser(is, xmlFactory.createParser());
} else {
return new XmlGDataParser(is, xmlFactory.createParser());
}
}
@Override
public GDataSerializer createSerializer(Entry en) {
if (en.getClass() == MapFeatureEntry.class) {
return new XmlMapsGDataSerializer(xmlFactory, en);
} else {
return new XmlEntryGDataSerializer(xmlFactory, en);
}
}
}
@@ -0,0 +1,259 @@
// Copyright 2010 Google Inc. All Rights Reserved.
package com.google.android.apps.mytracks.io.mymaps;
import com.google.wireless.gdata.data.Entry;
import com.google.wireless.gdata.data.StringUtils;
import com.google.wireless.gdata.parser.ParseException;
import com.google.wireless.gdata.parser.xml.XmlGDataParser;
import com.google.wireless.gdata.parser.xml.XmlParserFactory;
import com.google.wireless.gdata.serializer.xml.XmlEntryGDataSerializer;
import android.util.Log;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Map;
/**
* Serializer of maps data for GData.
*/
class XmlMapsGDataSerializer extends XmlEntryGDataSerializer {
private static final String APP_NAMESPACE = "http://www.w3.org/2007/app";
private MapFeatureEntry entry;
private XmlParserFactory factory;
private OutputStream stream;
public XmlMapsGDataSerializer(XmlParserFactory factory, Entry entry) {
super(factory, entry);
this.factory = factory;
this.entry = (MapFeatureEntry) entry;
}
@Override
public void serialize(OutputStream out, int format)
throws IOException, ParseException {
XmlSerializer serializer = null;
try {
serializer = factory.createSerializer();
} catch (XmlPullParserException e) {
throw new ParseException("Unable to create XmlSerializer.", e);
}
ByteArrayOutputStream printStream;
if (MapsClient.LOG_COMMUNICATION) {
printStream = new ByteArrayOutputStream();
serializer.setOutput(printStream, "UTF-8");
} else {
serializer.setOutput(out, "UTF-8");
}
serializer.startDocument("UTF-8", Boolean.FALSE);
declareEntryNamespaces(serializer);
serializer.startTag(XmlGDataParser.NAMESPACE_ATOM_URI, "entry");
stream = MapsClient.LOG_COMMUNICATION ? printStream : out;
serializeEntryContents(serializer, format);
serializer.endTag(XmlGDataParser.NAMESPACE_ATOM_URI, "entry");
serializer.endDocument();
serializer.flush();
if (MapsClient.LOG_COMMUNICATION) {
Log.d("Request", printStream.toString());
out.write(printStream.toByteArray());
stream = out;
}
}
private final void declareEntryNamespaces(XmlSerializer serializer)
throws IOException {
serializer.setPrefix(
"" /* default ns */, XmlGDataParser.NAMESPACE_ATOM_URI);
serializer.setPrefix(
XmlGDataParser.NAMESPACE_GD, XmlGDataParser.NAMESPACE_GD_URI);
declareExtraEntryNamespaces(serializer);
}
private final void serializeEntryContents(XmlSerializer serializer,
int format) throws IOException {
if (format != FORMAT_CREATE) {
serializeId(serializer, entry.getId());
}
serializeTitle(serializer, entry.getTitle());
if (format != FORMAT_CREATE) {
serializeLink(serializer,
"edit" /* rel */, entry.getEditUri(), null /* type */);
serializeLink(serializer,
"alternate" /* rel */, entry.getHtmlUri(), "text/html" /* type */);
}
serializeSummary(serializer, entry.getSummary());
serializeContent(serializer, entry.getContent());
serializeAuthor(serializer, entry.getAuthor(), entry.getEmail());
serializeCategory(serializer,
entry.getCategory(), entry.getCategoryScheme());
if (format == FORMAT_FULL) {
serializePublicationDate(serializer, entry.getPublicationDate());
}
if (format != FORMAT_CREATE) {
serializeUpdateDate(serializer, entry.getUpdateDate());
}
serializeExtraEntryContents(serializer, format);
}
private static void serializeId(XmlSerializer serializer, String id)
throws IOException {
if (StringUtils.isEmpty(id)) {
return;
}
serializer.startTag(null /* ns */, "id");
serializer.text(id);
serializer.endTag(null /* ns */, "id");
}
private static void serializeTitle(XmlSerializer serializer, String title)
throws IOException {
if (StringUtils.isEmpty(title)) {
return;
}
serializer.startTag(null /* ns */, "title");
serializer.text(title);
serializer.endTag(null /* ns */, "title");
}
public static void serializeLink(XmlSerializer serializer, String rel,
String href, String type) throws IOException {
if (StringUtils.isEmpty(href)) {
return;
}
serializer.startTag(null /* ns */, "link");
serializer.attribute(null /* ns */, "rel", rel);
serializer.attribute(null /* ns */, "href", href);
if (!StringUtils.isEmpty(type)) {
serializer.attribute(null /* ns */, "type", type);
}
serializer.endTag(null /* ns */, "link");
}
private static void serializeSummary(XmlSerializer serializer, String summary)
throws IOException {
if (StringUtils.isEmpty(summary)) {
return;
}
serializer.startTag(null /* ns */, "summary");
serializer.text(summary);
serializer.endTag(null /* ns */, "summary");
}
private void serializeContent(XmlSerializer serializer, String content)
throws IOException {
if (content == null) {
return;
}
serializer.startTag(null /* ns */, "content");
if (content.contains("</Placemark>")) {
serializer.attribute(
null /* ns */, "type", "application/vnd.google-earth.kml+xml");
serializer.flush();
stream.write(content.getBytes());
} else {
serializer.text(content);
}
serializer.endTag(null /* ns */, "content");
}
private static void serializeAuthor(XmlSerializer serializer, String author,
String email) throws IOException {
if (StringUtils.isEmpty(author) || StringUtils.isEmpty(email)) {
return;
}
serializer.startTag(null /* ns */, "author");
serializer.startTag(null /* ns */, "name");
serializer.text(author);
serializer.endTag(null /* ns */, "name");
serializer.startTag(null /* ns */, "email");
serializer.text(email);
serializer.endTag(null /* ns */, "email");
serializer.endTag(null /* ns */, "author");
}
private static void serializeCategory(XmlSerializer serializer,
String category, String categoryScheme) throws IOException {
if (StringUtils.isEmpty(category) && StringUtils.isEmpty(categoryScheme)) {
return;
}
serializer.startTag(null /* ns */, "category");
if (!StringUtils.isEmpty(category)) {
serializer.attribute(null /* ns */, "term", category);
}
if (!StringUtils.isEmpty(categoryScheme)) {
serializer.attribute(null /* ns */, "scheme", categoryScheme);
}
serializer.endTag(null /* ns */, "category");
}
private static void serializePublicationDate(XmlSerializer serializer,
String publicationDate) throws IOException {
if (StringUtils.isEmpty(publicationDate)) {
return;
}
serializer.startTag(null /* ns */, "published");
serializer.text(publicationDate);
serializer.endTag(null /* ns */, "published");
}
private static void serializeUpdateDate(XmlSerializer serializer,
String updateDate) throws IOException {
if (StringUtils.isEmpty(updateDate)) {
return;
}
serializer.startTag(null /* ns */, "updated");
serializer.text(updateDate);
serializer.endTag(null /* ns */, "updated");
}
@Override
protected void serializeExtraEntryContents(XmlSerializer serializer,
int format) throws IOException {
Map<String, String> attrs = entry.getAllAttributes();
for (Map.Entry<String, String> attr : attrs.entrySet()) {
serializer.startTag("http://schemas.google.com/g/2005", "customProperty");
serializer.attribute(null, "name", attr.getKey());
serializer.text(attr.getValue());
serializer.endTag("http://schemas.google.com/g/2005", "customProperty");
}
String privacy = entry.getPrivacy();
if (!StringUtils.isEmpty(privacy)) {
serializer.setPrefix("app", APP_NAMESPACE);
if ("public".equals(privacy)) {
serializer.startTag(APP_NAMESPACE, "control");
serializer.startTag(APP_NAMESPACE, "draft");
serializer.text("no");
serializer.endTag(APP_NAMESPACE, "draft");
serializer.endTag(APP_NAMESPACE, "control");
}
if ("unlisted".equals(privacy)) {
serializer.startTag(APP_NAMESPACE, "control");
serializer.startTag(APP_NAMESPACE, "draft");
serializer.text("yes");
serializer.endTag(APP_NAMESPACE, "draft");
serializer.endTag(APP_NAMESPACE, "control");
}
}
}
}
@@ -16,7 +16,7 @@
package com.google.android.apps.mytracks.services; package com.google.android.apps.mytracks.services;
import static com.google.android.apps.mytracks.MyTracksConstants.TAG; import static com.google.android.apps.mytracks.Constants.TAG;
import android.content.Context; import android.content.Context;
import android.media.AudioManager; import android.media.AudioManager;
@@ -16,7 +16,7 @@
package com.google.android.apps.mytracks.services; package com.google.android.apps.mytracks.services;
import com.google.android.apps.mytracks.MyTracksConstants; import com.google.android.apps.mytracks.Constants;
import android.util.Log; import android.util.Log;
@@ -77,7 +77,7 @@ public class PeriodicTaskExecuter {
} }
Date start = new Date(next); Date start = new Date(next);
Log.i(MyTracksConstants.TAG, Log.i(Constants.TAG,
task.getClass().getSimpleName() + " scheduled to start at " + start task.getClass().getSimpleName() + " scheduled to start at " + start
+ " every " + interval + " milliseconds."); + " every " + interval + " milliseconds.");
timer.scheduleAtFixedRate(new PeriodicTimerTask(), start, interval); timer.scheduleAtFixedRate(new PeriodicTimerTask(), start, interval);
@@ -87,7 +87,7 @@ public class PeriodicTaskExecuter {
* Cleans up this object. * Cleans up this object.
*/ */
public void shutdown() { public void shutdown() {
Log.i(MyTracksConstants.TAG, Log.i(Constants.TAG,
task.getClass().getSimpleName() + " shutting down."); task.getClass().getSimpleName() + " shutting down.");
if (timer != null) { if (timer != null) {
timer.cancel(); timer.cancel();
@@ -15,7 +15,7 @@
*/ */
package com.google.android.apps.mytracks.services; package com.google.android.apps.mytracks.services;
import com.google.android.apps.mytracks.MyTracksConstants; import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.MyTracksSettings; import com.google.android.apps.mytracks.MyTracksSettings;
import com.google.android.maps.mytracks.R; import com.google.android.maps.mytracks.R;
@@ -47,7 +47,7 @@ public class PreferenceManager implements OnSharedPreferenceChangeListener {
this.sharedPreferences = service.getSharedPreferences( this.sharedPreferences = service.getSharedPreferences(
MyTracksSettings.SETTINGS_NAME, 0); MyTracksSettings.SETTINGS_NAME, 0);
if (sharedPreferences == null) { if (sharedPreferences == null) {
Log.w(MyTracksConstants.TAG, Log.w(Constants.TAG,
"TrackRecordingService: Couldn't get shared preferences."); "TrackRecordingService: Couldn't get shared preferences.");
throw new IllegalStateException("Couldn't get shared preferences"); throw new IllegalStateException("Couldn't get shared preferences");
} }
@@ -88,7 +88,7 @@ public class PreferenceManager implements OnSharedPreferenceChangeListener {
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
String key) { String key) {
if (service == null) { if (service == null) {
Log.w(MyTracksConstants.TAG, Log.w(Constants.TAG,
"onSharedPreferenceChanged: a preference change (key = " + key "onSharedPreferenceChanged: a preference change (key = " + key
+ ") after a call to shutdown()"); + ") after a call to shutdown()");
return; return;
@@ -98,7 +98,7 @@ public class PreferenceManager implements OnSharedPreferenceChangeListener {
sharedPreferences.getInt( sharedPreferences.getInt(
minRecordingDistanceKey, minRecordingDistanceKey,
MyTracksSettings.DEFAULT_MIN_RECORDING_DISTANCE)); MyTracksSettings.DEFAULT_MIN_RECORDING_DISTANCE));
Log.d(MyTracksConstants.TAG, Log.d(Constants.TAG,
"TrackRecordingService: minRecordingDistance = " "TrackRecordingService: minRecordingDistance = "
+ service.getMinRecordingDistance()); + service.getMinRecordingDistance());
} }
@@ -15,7 +15,7 @@
*/ */
package com.google.android.apps.mytracks.services; package com.google.android.apps.mytracks.services;
import com.google.android.apps.mytracks.MyTracksConstants; import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.content.WaypointCreationRequest; import com.google.android.apps.mytracks.content.WaypointCreationRequest;
import com.google.android.apps.mytracks.util.UnitConversions; import com.google.android.apps.mytracks.util.UnitConversions;
@@ -81,7 +81,7 @@ public class SplitManager {
if (splitFrequency >= 0) { if (splitFrequency >= 0) {
nextSplitDistance = Double.MAX_VALUE; nextSplitDistance = Double.MAX_VALUE;
Log.d(MyTracksConstants.TAG, Log.d(Constants.TAG,
"SplitManager: Distance splits disabled."); "SplitManager: Distance splits disabled.");
return; return;
} }
@@ -94,7 +94,7 @@ public class SplitManager {
int index = (int) (dist / splitFrequency); int index = (int) (dist / splitFrequency);
index -= 1; index -= 1;
nextSplitDistance = splitFrequency * index; nextSplitDistance = splitFrequency * index;
Log.d(MyTracksConstants.TAG, Log.d(Constants.TAG,
"SplitManager: Next split distance: " + nextSplitDistance); "SplitManager: Next split distance: " + nextSplitDistance);
} }
@@ -126,7 +126,7 @@ public class SplitManager {
* @param splitFrequency The frequency in time or distance * @param splitFrequency The frequency in time or distance
*/ */
public void setSplitFrequency(int splitFrequency) { public void setSplitFrequency(int splitFrequency) {
Log.d(MyTracksConstants.TAG, Log.d(Constants.TAG,
"setSplitFrequency: splitFrequency = " + splitFrequency); "setSplitFrequency: splitFrequency = " + splitFrequency);
this.splitFrequency = splitFrequency; this.splitFrequency = splitFrequency;
@@ -1,12 +1,12 @@
/* /*
* Copyright 2009 Google Inc. * Copyright 2009 Google Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); you may not * 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 * use this file except in compliance with the License. You may obtain a copy of
* the License at * the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
@@ -16,7 +16,9 @@
package com.google.android.apps.mytracks.services; package com.google.android.apps.mytracks.services;
import com.google.android.apps.mytracks.MyTracksConstants; import static com.google.android.apps.mytracks.Constants.TAG;
import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.MyTracksSettings; import com.google.android.apps.mytracks.MyTracksSettings;
import com.google.android.apps.mytracks.stats.TripStatistics; import com.google.android.apps.mytracks.stats.TripStatistics;
import com.google.android.apps.mytracks.util.StringUtils; import com.google.android.apps.mytracks.util.StringUtils;
@@ -99,7 +101,7 @@ public class StatusAnnouncerTask implements PeriodicTask {
* Called when the TTS engine is initialized. * Called when the TTS engine is initialized.
*/ */
protected void onTtsInit(int status) { protected void onTtsInit(int status) {
Log.i(MyTracksConstants.TAG, "TrackRecordingService.TTS init: " + status); Log.i(TAG, "TrackRecordingService.TTS init: " + status);
this.ready = status == TextToSpeech.SUCCESS; this.ready = status == TextToSpeech.SUCCESS;
if (ready) { if (ready) {
@@ -111,7 +113,7 @@ public class StatusAnnouncerTask implements PeriodicTask {
languageAvailability == TextToSpeech.LANG_NOT_SUPPORTED) { languageAvailability == TextToSpeech.LANG_NOT_SUPPORTED) {
// English is probably supported. // English is probably supported.
// TODO: Somehow use announcement strings from English too. // TODO: Somehow use announcement strings from English too.
Log.w(MyTracksConstants.TAG, "Default language not available, using English."); Log.w(TAG, "Default language not available, using English.");
speechLanguage = Locale.ENGLISH; speechLanguage = Locale.ENGLISH;
} }
tts.setLanguage(speechLanguage); tts.setLanguage(speechLanguage);
@@ -129,7 +131,7 @@ public class StatusAnnouncerTask implements PeriodicTask {
@Override @Override
public void run(TrackRecordingService service) { public void run(TrackRecordingService service) {
if (service == null) { if (service == null) {
Log.e(MyTracksConstants.TAG, "StatusAnnouncer TrackRecordingService not initialized"); Log.e(TAG, "StatusAnnouncer TrackRecordingService not initialized");
return; return;
} }
@@ -143,23 +145,22 @@ public class StatusAnnouncerTask implements PeriodicTask {
*/ */
protected void runWithStatistics(TripStatistics statistics) { protected void runWithStatistics(TripStatistics statistics) {
if (statistics == null) { if (statistics == null) {
Log.e(MyTracksConstants.TAG, "StatusAnnouncer stats not initialized."); Log.e(TAG, "StatusAnnouncer stats not initialized.");
return; return;
} }
if (!ready || tts == null) { if (!ready || tts == null) {
Log.e(MyTracksConstants.TAG, "StatusAnnouncer Tts not ready."); Log.e(TAG, "StatusAnnouncer Tts not ready.");
return; return;
} }
if (!speechAllowed) { if (!speechAllowed) {
Log.i(MyTracksConstants.TAG, Log.i(Constants.TAG,
"Not making announcement - not allowed at this time"); "Not making announcement - not allowed at this time");
return; return;
} }
String announcement = getAnnouncement(statistics); String announcement = getAnnouncement(statistics);
Log.d(MyTracksConstants.TAG, "Announcement: " + announcement); Log.d(Constants.TAG, "Announcement: " + announcement);
speakAnnouncment(announcement); speakAnnouncment(announcement);
} }
@@ -179,7 +180,7 @@ public class StatusAnnouncerTask implements PeriodicTask {
boolean metricUnits = true; boolean metricUnits = true;
boolean reportSpeed = true; boolean reportSpeed = true;
if (preferences != null) { if (preferences != null) {
metricUnits = metricUnits =
preferences.getBoolean(context.getString(R.string.metric_units_key), preferences.getBoolean(context.getString(R.string.metric_units_key),
true); true);
reportSpeed = reportSpeed =
@@ -218,7 +219,7 @@ public class StatusAnnouncerTask implements PeriodicTask {
speed = String.format("%.1f", s); speed = String.format("%.1f", s);
} else { } else {
double pace = 3600000.0 / s; double pace = 3600000.0 / s;
Log.w(MyTracksConstants.TAG, Log.w(Constants.TAG,
"Converted speed: " + s + " to pace: " + pace); "Converted speed: " + s + " to pace: " + pace);
speed = stringUtils.formatTimeLong((long) pace); speed = stringUtils.formatTimeLong((long) pace);
} }
@@ -237,7 +238,7 @@ public class StatusAnnouncerTask implements PeriodicTask {
@Override @Override
public void start() { public void start() {
Log.i(MyTracksConstants.TAG, "Starting TTS"); Log.i(Constants.TAG, "Starting TTS");
if (tts == null) { if (tts == null) {
// We can't have this class also be the listener, otherwise it's unsafe to // We can't have this class also be the listener, otherwise it's unsafe to
// reference it in Cupcake (even if we don't instantiate it). // reference it in Cupcake (even if we don't instantiate it).
@@ -264,7 +265,7 @@ public class StatusAnnouncerTask implements PeriodicTask {
tts = null; tts = null;
} }
Log.i(MyTracksConstants.TAG, "TTS shut down"); Log.i(Constants.TAG, "TTS shut down");
} }
/** /**
@@ -15,7 +15,7 @@
*/ */
package com.google.android.apps.mytracks.services; package com.google.android.apps.mytracks.services;
import com.google.android.apps.mytracks.MyTracksConstants; import com.google.android.apps.mytracks.Constants;
import android.util.Log; import android.util.Log;
@@ -49,14 +49,14 @@ public class TaskExecuterManager {
*/ */
public void setFrequency(int frequency, TrackRecordingService service) { public void setFrequency(int frequency, TrackRecordingService service) {
this.frequency = frequency; this.frequency = frequency;
Log.i(MyTracksConstants.TAG, "Frequency set to " + frequency Log.i(Constants.TAG, "Frequency set to " + frequency
+ " for task " + task.getClass().getSimpleName()); + " for task " + task.getClass().getSimpleName());
if (frequency == -1) { if (frequency == -1) {
if (executer != null) { if (executer != null) {
executer.shutdown(); executer.shutdown();
executer = null; executer = null;
Log.i(MyTracksConstants.TAG, Log.i(Constants.TAG,
"Shut down service: " + task.getClass().getSimpleName()); "Shut down service: " + task.getClass().getSimpleName());
} }
} else { } else {
@@ -15,20 +15,21 @@
*/ */
package com.google.android.apps.mytracks.services; package com.google.android.apps.mytracks.services;
import static com.google.android.apps.mytracks.MyTracksConstants.RESUME_TRACK_EXTRA_NAME; import static com.google.android.apps.mytracks.Constants.TAG;
import static com.google.android.apps.mytracks.Constants.RESUME_TRACK_EXTRA_NAME;
import com.google.android.apps.mytracks.MyTracks; 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.MyTracksSettings; import com.google.android.apps.mytracks.MyTracksSettings;
import com.google.android.apps.mytracks.content.MyTracksLocation; import com.google.android.apps.mytracks.content.MyTracksLocation;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils; import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.content.Sensor; 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.Track;
import com.google.android.apps.mytracks.content.TracksColumns; import com.google.android.apps.mytracks.content.TracksColumns;
import com.google.android.apps.mytracks.content.Waypoint; import com.google.android.apps.mytracks.content.Waypoint;
import com.google.android.apps.mytracks.content.WaypointCreationRequest; import com.google.android.apps.mytracks.content.WaypointCreationRequest;
import com.google.android.apps.mytracks.content.WaypointsColumns; import com.google.android.apps.mytracks.content.WaypointsColumns;
import com.google.android.apps.mytracks.content.Sensor.SensorDataSet;
import com.google.android.apps.mytracks.services.sensors.SensorManager; import com.google.android.apps.mytracks.services.sensors.SensorManager;
import com.google.android.apps.mytracks.services.sensors.SensorManagerFactory; import com.google.android.apps.mytracks.services.sensors.SensorManagerFactory;
import com.google.android.apps.mytracks.stats.TripStatistics; import com.google.android.apps.mytracks.stats.TripStatistics;
@@ -86,8 +87,8 @@ public class TrackRecordingService extends Service implements LocationListener {
private int minRequiredAccuracy = private int minRequiredAccuracy =
MyTracksSettings.DEFAULT_MIN_REQUIRED_ACCURACY; MyTracksSettings.DEFAULT_MIN_REQUIRED_ACCURACY;
private int autoResumeTrackTimeout = private int autoResumeTrackTimeout =
MyTracksSettings.DEFAULT_AUTO_RESUME_TRACK_TIMEOUT; MyTracksSettings.DEFAULT_AUTO_RESUME_TRACK_TIMEOUT;
private long recordingTrackId = -1; private long recordingTrackId = -1;
private long currentWaypointId = -1; private long currentWaypointId = -1;
@@ -117,9 +118,9 @@ public class TrackRecordingService extends Service implements LocationListener {
private SplitManager splitManager; private SplitManager splitManager;
private SensorManager sensorManager; private SensorManager sensorManager;
private PreferenceManager prefManager; private PreferenceManager prefManager;
/** /**
* The interval in milliseconds that we have requested to be notified of gps * The interval in milliseconds that we have requested to be notified of gps
* readings. * readings.
@@ -144,7 +145,7 @@ public class TrackRecordingService extends Service implements LocationListener {
if (isRecording()) { if (isRecording()) {
handler.post(new Runnable() { handler.post(new Runnable() {
public void run() { public void run() {
Log.d(MyTracksConstants.TAG, Log.d(Constants.TAG,
"Re-registering location listener with TrackRecordingService."); "Re-registering location listener with TrackRecordingService.");
unregisterLocationListener(); unregisterLocationListener();
registerLocationListener(); registerLocationListener();
@@ -168,7 +169,7 @@ public class TrackRecordingService extends Service implements LocationListener {
* The most recent recording track. * The most recent recording track.
*/ */
private Track recordingTrack; private Track recordingTrack;
/** /**
* Is the service currently recording a track? * Is the service currently recording a track?
*/ */
@@ -269,7 +270,7 @@ public class TrackRecordingService extends Service implements LocationListener {
// Insert failed, most likely because of SqlLite error code 5 // Insert failed, most likely because of SqlLite error code 5
// (SQLite_BUSY). This is expected to happen extremely rarely (if our // (SQLite_BUSY). This is expected to happen extremely rarely (if our
// listener gets invoked twice at about the same time). // listener gets invoked twice at about the same time).
Log.w(MyTracksConstants.TAG, Log.w(TAG,
"Caught SQLiteException: " + e.getMessage(), e); "Caught SQLiteException: " + e.getMessage(), e);
return false; return false;
} }
@@ -314,15 +315,15 @@ public class TrackRecordingService extends Service implements LocationListener {
try { try {
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
if (pm == null) { if (pm == null) {
Log.e(MyTracksConstants.TAG, Log.e(TAG,
"TrackRecordingService: Power manager not found!"); "TrackRecordingService: Power manager not found!");
return; return;
} }
if (wakeLock == null) { if (wakeLock == null) {
wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
MyTracksConstants.TAG); TAG);
if (wakeLock == null) { if (wakeLock == null) {
Log.e(MyTracksConstants.TAG, Log.e(TAG,
"TrackRecordingService: Could not create wake lock (null)."); "TrackRecordingService: Could not create wake lock (null).");
return; return;
} }
@@ -330,12 +331,12 @@ public class TrackRecordingService extends Service implements LocationListener {
if (!wakeLock.isHeld()) { if (!wakeLock.isHeld()) {
wakeLock.acquire(); wakeLock.acquire();
if (!wakeLock.isHeld()) { if (!wakeLock.isHeld()) {
Log.e(MyTracksConstants.TAG, Log.e(TAG,
"TrackRecordingService: Could not acquire wake lock."); "TrackRecordingService: Could not acquire wake lock.");
} }
} }
} catch (RuntimeException e) { } catch (RuntimeException e) {
Log.e(MyTracksConstants.TAG, Log.e(TAG,
"TrackRecordingService: Caught unexpected exception: " "TrackRecordingService: Caught unexpected exception: "
+ e.getMessage(), e); + e.getMessage(), e);
} }
@@ -376,40 +377,40 @@ public class TrackRecordingService extends Service implements LocationListener {
public void registerLocationListener() { public void registerLocationListener() {
if (locationManager == null) { if (locationManager == null) {
Log.e(MyTracksConstants.TAG, Log.e(TAG,
"TrackRecordingService: Do not have any location manager."); "TrackRecordingService: Do not have any location manager.");
return; return;
} }
Log.d(MyTracksConstants.TAG, Log.d(TAG,
"Preparing to register location listener w/ TrackRecordingService..."); "Preparing to register location listener w/ TrackRecordingService...");
try { try {
long desiredInterval = locationListenerPolicy.getDesiredPollingInterval(); long desiredInterval = locationListenerPolicy.getDesiredPollingInterval();
locationManager.requestLocationUpdates( locationManager.requestLocationUpdates(
MyTracksConstants.GPS_PROVIDER, desiredInterval, Constants.GPS_PROVIDER, desiredInterval,
locationListenerPolicy.getMinDistance(), locationListenerPolicy.getMinDistance(),
// , 0 /* minDistance, get all updates to properly time pauses */ // , 0 /* minDistance, get all updates to properly time pauses */
TrackRecordingService.this); TrackRecordingService.this);
currentRecordingInterval = desiredInterval; currentRecordingInterval = desiredInterval;
Log.d(MyTracksConstants.TAG, Log.d(TAG,
"...location listener now registered w/ TrackRecordingService @ " "...location listener now registered w/ TrackRecordingService @ "
+ currentRecordingInterval); + currentRecordingInterval);
} catch (RuntimeException e) { } catch (RuntimeException e) {
Log.e(MyTracksConstants.TAG, Log.e(TAG,
"Could not register location listener: " + e.getMessage(), e); "Could not register location listener: " + e.getMessage(), e);
} }
} }
public void unregisterLocationListener() { public void unregisterLocationListener() {
if (locationManager == null) { if (locationManager == null) {
Log.e(MyTracksConstants.TAG, Log.e(TAG,
"TrackRecordingService: Do not have any location manager."); "TrackRecordingService: Do not have any location manager.");
return; return;
} }
locationManager.removeUpdates(this); locationManager.removeUpdates(this);
Log.d(MyTracksConstants.TAG, Log.d(TAG,
"Location listener now unregistered w/ TrackRecordingService."); "Location listener now unregistered w/ TrackRecordingService.");
} }
private Track getRecordingTrack() { private Track getRecordingTrack() {
if (recordingTrackId < 0) { if (recordingTrackId < 0) {
return null; return null;
@@ -419,9 +420,9 @@ public class TrackRecordingService extends Service implements LocationListener {
} }
private void restoreStats(Track track) { private void restoreStats(Track track) {
Log.d(MyTracksConstants.TAG, Log.d(TAG,
"Restoring stats of track with ID: " + track.getId()); "Restoring stats of track with ID: " + track.getId());
TripStatistics stats = track.getStatistics(); TripStatistics stats = track.getStatistics();
statsBuilder = new TripStatisticsBuilder(stats.getStartTime()); statsBuilder = new TripStatisticsBuilder(stats.getStartTime());
statsBuilder.setMinRecordingDistance(minRecordingDistance); statsBuilder.setMinRecordingDistance(minRecordingDistance);
@@ -446,7 +447,7 @@ public class TrackRecordingService extends Service implements LocationListener {
Cursor cursor = null; Cursor cursor = null;
try { try {
cursor = providerUtils.getLocationsCursor( cursor = providerUtils.getLocationsCursor(
recordingTrackId, -1, MyTracksConstants.MAX_LOADED_TRACK_POINTS, recordingTrackId, -1, Constants.MAX_LOADED_TRACK_POINTS,
true); true);
if (cursor != null) { if (cursor != null) {
if (cursor.moveToLast()) { if (cursor.moveToLast()) {
@@ -465,10 +466,10 @@ public class TrackRecordingService extends Service implements LocationListener {
statsBuilder.pauseAt(stats.getStopTime()); statsBuilder.pauseAt(stats.getStopTime());
statsBuilder.resumeAt(System.currentTimeMillis()); statsBuilder.resumeAt(System.currentTimeMillis());
} else { } else {
Log.e(MyTracksConstants.TAG, "Could not get track points cursor."); Log.e(TAG, "Could not get track points cursor.");
} }
} catch (RuntimeException e) { } catch (RuntimeException e) {
Log.e(MyTracksConstants.TAG, "Error while restoring track.", e); Log.e(TAG, "Error while restoring track.", e);
} finally { } finally {
if (cursor != null) { if (cursor != null) {
cursor.close(); cursor.close();
@@ -493,12 +494,12 @@ public class TrackRecordingService extends Service implements LocationListener {
} }
private void onLocationChangedAsync(Location location) { private void onLocationChangedAsync(Location location) {
Log.d(MyTracksConstants.TAG, "TrackRecordingService.onLocationChanged"); Log.d(TAG, "TrackRecordingService.onLocationChanged");
try { try {
// Don't record if the service has been asked to pause recording: // Don't record if the service has been asked to pause recording:
if (!isRecording) { if (!isRecording) {
Log.w(MyTracksConstants.TAG, Log.w(TAG,
"Not recording because recording has been paused."); "Not recording because recording has been paused.");
return; return;
} }
@@ -506,14 +507,14 @@ public class TrackRecordingService extends Service implements LocationListener {
// This should never happen, but just in case (we really don't want the // This should never happen, but just in case (we really don't want the
// service to crash): // service to crash):
if (location == null) { if (location == null) {
Log.w(MyTracksConstants.TAG, Log.w(TAG,
"Location changed, but location is null."); "Location changed, but location is null.");
return; return;
} }
// Don't record if the accuracy is too bad: // Don't record if the accuracy is too bad:
if (location.getAccuracy() > minRequiredAccuracy) { if (location.getAccuracy() > minRequiredAccuracy) {
Log.d(MyTracksConstants.TAG, Log.d(TAG,
"Not recording. Bad accuracy."); "Not recording. Bad accuracy.");
return; return;
} }
@@ -521,7 +522,7 @@ public class TrackRecordingService extends Service implements LocationListener {
// At least one track must be available for appending points: // At least one track must be available for appending points:
recordingTrack = getRecordingTrack(); recordingTrack = getRecordingTrack();
if (recordingTrack == null) { if (recordingTrack == null) {
Log.d(MyTracksConstants.TAG, Log.d(TAG,
"Not recording. No track to append to available."); "Not recording. No track to append to available.");
return; return;
} }
@@ -555,7 +556,7 @@ public class TrackRecordingService extends Service implements LocationListener {
// maxRecordingDistance = 0 // maxRecordingDistance = 0
if (distanceToLast == 0 && !hasSensorData) { if (distanceToLast == 0 && !hasSensorData) {
if (isMoving) { if (isMoving) {
Log.d(MyTracksConstants.TAG, "Found two identical locations."); Log.d(TAG, "Found two identical locations.");
isMoving = false; isMoving = false;
if (lastLocation != null && lastRecordedLocation != null if (lastLocation != null && lastRecordedLocation != null
&& !lastRecordedLocation.equals(lastLocation)) { && !lastRecordedLocation.equals(lastLocation)) {
@@ -570,7 +571,7 @@ public class TrackRecordingService extends Service implements LocationListener {
lastRecordedLocationId++; lastRecordedLocationId++;
} }
} else { } else {
Log.d(MyTracksConstants.TAG, Log.d(TAG,
"Not recording. More than two identical locations."); "Not recording. More than two identical locations.");
} }
} else if (distanceToLastRecorded > minRecordingDistance } else if (distanceToLastRecorded > minRecordingDistance
@@ -595,8 +596,8 @@ public class TrackRecordingService extends Service implements LocationListener {
&& recordingTrack.getStartId() >= 0; && recordingTrack.getStartId() >= 0;
if (startNewSegment) { if (startNewSegment) {
// Insert a separator point to indicate start of new track: // Insert a separator point to indicate start of new track:
Log.d(MyTracksConstants.TAG, "Inserting a separator."); Log.d(TAG, "Inserting a separator.");
Location separator = new Location(MyTracksConstants.GPS_PROVIDER); Location separator = new Location(Constants.GPS_PROVIDER);
separator.setLongitude(0); separator.setLongitude(0);
separator.setLatitude(100); separator.setLatitude(100);
separator.setTime(lastRecordedLocation.getTime()); separator.setTime(lastRecordedLocation.getTime());
@@ -608,7 +609,7 @@ public class TrackRecordingService extends Service implements LocationListener {
return; return;
} }
} else { } else {
Log.d(MyTracksConstants.TAG, String.format( Log.d(TAG, String.format(
"Not recording. Distance to last recorded point (%f m) is less than" "Not recording. Distance to last recorded point (%f m) is less than"
+ " %d m.", distanceToLastRecorded, minRecordingDistance)); + " %d m.", distanceToLastRecorded, minRecordingDistance));
// Return here so that the location is NOT recorded as the last location. // Return here so that the location is NOT recorded as the last location.
@@ -616,11 +617,11 @@ public class TrackRecordingService extends Service implements LocationListener {
} }
} catch (Error e) { } catch (Error e) {
// Probably important enough to rethrow. // Probably important enough to rethrow.
Log.e(MyTracksConstants.TAG, "Error in onLocationChanged", e); Log.e(TAG, "Error in onLocationChanged", e);
throw e; throw e;
} catch (RuntimeException e) { } catch (RuntimeException e) {
// Safe usually to trap exceptions. // Safe usually to trap exceptions.
Log.e(MyTracksConstants.TAG, Log.e(TAG,
"Trapping exception in onLocationChanged", e); "Trapping exception in onLocationChanged", e);
throw e; throw e;
} }
@@ -657,7 +658,7 @@ public class TrackRecordingService extends Service implements LocationListener {
@Override @Override
public void onCreate() { public void onCreate() {
super.onCreate(); super.onCreate();
Log.d(MyTracksConstants.TAG, "TrackRecordingService.onCreate"); Log.d(TAG, "TrackRecordingService.onCreate");
providerUtils = MyTracksProviderUtils.Factory.get(this); providerUtils = MyTracksProviderUtils.Factory.get(this);
notificationManager = notificationManager =
(NotificationManager) getSystemService(NOTIFICATION_SERVICE); (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
@@ -682,7 +683,7 @@ public class TrackRecordingService extends Service implements LocationListener {
} else { } else {
if (recordingTrackId != -1) { if (recordingTrackId != -1) {
// Make sure we have consistent state in shared preferences. // Make sure we have consistent state in shared preferences.
Log.w(MyTracksConstants.TAG, "TrackRecordingService.onCreate: " Log.w(TAG, "TrackRecordingService.onCreate: "
+ "Resetting an orphaned recording track = " + recordingTrackId); + "Resetting an orphaned recording track = " + recordingTrackId);
} }
prefManager.setRecordingTrack(recordingTrackId = -1); prefManager.setRecordingTrack(recordingTrackId = -1);
@@ -697,7 +698,7 @@ public class TrackRecordingService extends Service implements LocationListener {
* the announcements, otherwise this method is no-op. * the announcements, otherwise this method is no-op.
*/ */
private void setUpAnnouncer() { private void setUpAnnouncer() {
Log.d(MyTracksConstants.TAG, "TrackRecordingService.setUpAnnouncer: " Log.d(TAG, "TrackRecordingService.setUpAnnouncer: "
+ announcementExecuter); + announcementExecuter);
if (announcementFrequency != -1 && recordingTrackId != -1) { if (announcementFrequency != -1 && recordingTrackId != -1) {
handler.post(new Runnable() { handler.post(new Runnable() {
@@ -721,9 +722,9 @@ public class TrackRecordingService extends Service implements LocationListener {
}); });
} }
} }
private void shutdownAnnouncer() { private void shutdownAnnouncer() {
Log.d(MyTracksConstants.TAG, "TrackRecordingService.shutdownAnnouncer: " Log.d(TAG, "TrackRecordingService.shutdownAnnouncer: "
+ announcementExecuter); + announcementExecuter);
if (announcementExecuter != null) { if (announcementExecuter != null) {
try { try {
@@ -736,7 +737,7 @@ public class TrackRecordingService extends Service implements LocationListener {
@Override @Override
public void onDestroy() { public void onDestroy() {
Log.d(MyTracksConstants.TAG, "TrackRecordingService.onDestroy"); Log.d(TAG, "TrackRecordingService.onDestroy");
isRecording = false; isRecording = false;
showNotification(); showNotification();
@@ -764,29 +765,29 @@ public class TrackRecordingService extends Service implements LocationListener {
// This should be the last operation. // This should be the last operation.
releaseWakeLock(); releaseWakeLock();
super.onDestroy(); super.onDestroy();
} }
@Override @Override
public IBinder onBind(Intent intent) { public IBinder onBind(Intent intent) {
Log.d(MyTracksConstants.TAG, "TrackRecordingService.onBind"); Log.d(TAG, "TrackRecordingService.onBind");
return binder; return binder;
} }
@Override @Override
public boolean onUnbind(Intent intent) { public boolean onUnbind(Intent intent) {
Log.d(MyTracksConstants.TAG, "TrackRecordingService.onUnbind"); Log.d(TAG, "TrackRecordingService.onUnbind");
return super.onUnbind(intent); return super.onUnbind(intent);
} }
@Override @Override
public boolean stopService(Intent name) { public boolean stopService(Intent name) {
Log.d(MyTracksConstants.TAG, "TrackRecordingService.stopService"); Log.d(TAG, "TrackRecordingService.stopService");
unregisterLocationListener(); unregisterLocationListener();
return super.stopService(name); return super.stopService(name);
} }
@Override @Override
public void onStart(Intent intent, int startId) { public void onStart(Intent intent, int startId) {
handleStartCommand(intent, startId); handleStartCommand(intent, startId);
@@ -799,50 +800,50 @@ public class TrackRecordingService extends Service implements LocationListener {
} }
private void handleStartCommand(Intent intent, int startId) { private void handleStartCommand(Intent intent, int startId) {
Log.d(MyTracksConstants.TAG, Log.d(TAG,
"TrackRecordingService.handleStartCommand: " + startId); "TrackRecordingService.handleStartCommand: " + startId);
// Check if called on phone reboot with resume intent. // Check if called on phone reboot with resume intent.
if (intent != null && if (intent != null &&
intent.getBooleanExtra(RESUME_TRACK_EXTRA_NAME, false)) { intent.getBooleanExtra(RESUME_TRACK_EXTRA_NAME, false)) {
Log.d(MyTracksConstants.TAG, "TrackRecordingService: requested resume"); Log.d(TAG, "TrackRecordingService: requested resume");
// Make sure that the current track exists and is fresh enough. // Make sure that the current track exists and is fresh enough.
if (recordingTrack == null || !shouldResumeTrack(recordingTrack)) { if (recordingTrack == null || !shouldResumeTrack(recordingTrack)) {
Log.i(MyTracksConstants.TAG, Log.i(TAG,
"TrackRecordingService: Not resuming, because the previous track (" "TrackRecordingService: Not resuming, because the previous track ("
+ recordingTrack + ") doesn't exist or is too old"); + recordingTrack + ") doesn't exist or is too old");
isRecording = false; isRecording = false;
prefManager.setRecordingTrack(recordingTrackId = -1); prefManager.setRecordingTrack(recordingTrackId = -1);
stopSelfResult(startId); stopSelfResult(startId);
return; return;
} }
Log.i(MyTracksConstants.TAG, "TrackRecordingService: resuming"); Log.i(TAG, "TrackRecordingService: resuming");
} }
} }
private void setAutoResumeTrackRetries( private void setAutoResumeTrackRetries(
SharedPreferences sharedPreferences, int retryAttempts) { SharedPreferences sharedPreferences, int retryAttempts) {
Log.d(MyTracksConstants.TAG, Log.d(TAG,
"Updating auto-resume retry attempts to: " + retryAttempts); "Updating auto-resume retry attempts to: " + retryAttempts);
prefManager.setAutoResumeTrackCurrentRetry(retryAttempts); prefManager.setAutoResumeTrackCurrentRetry(retryAttempts);
} }
private boolean shouldResumeTrack(Track track) { private boolean shouldResumeTrack(Track track) {
Log.d(MyTracksConstants.TAG, "shouldResumeTrack: autoResumeTrackTimeout = " Log.d(TAG, "shouldResumeTrack: autoResumeTrackTimeout = "
+ autoResumeTrackTimeout); + autoResumeTrackTimeout);
// Check if we haven't exceeded the maximum number of retry attempts. // Check if we haven't exceeded the maximum number of retry attempts.
SharedPreferences sharedPreferences = SharedPreferences sharedPreferences =
getSharedPreferences(MyTracksSettings.SETTINGS_NAME, 0); getSharedPreferences(MyTracksSettings.SETTINGS_NAME, 0);
int retries = sharedPreferences.getInt( int retries = sharedPreferences.getInt(
getString(R.string.auto_resume_track_current_retry_key), 0); getString(R.string.auto_resume_track_current_retry_key), 0);
Log.d(MyTracksConstants.TAG, Log.d(TAG,
"shouldResumeTrack: Attempting to auto-resume the track (" "shouldResumeTrack: Attempting to auto-resume the track ("
+ (retries + 1) + "/" + MAX_AUTO_RESUME_TRACK_RETRY_ATTEMPTS + ")"); + (retries + 1) + "/" + MAX_AUTO_RESUME_TRACK_RETRY_ATTEMPTS + ")");
if (retries >= MAX_AUTO_RESUME_TRACK_RETRY_ATTEMPTS) { if (retries >= MAX_AUTO_RESUME_TRACK_RETRY_ATTEMPTS) {
Log.i(MyTracksConstants.TAG, Log.i(TAG,
"shouldResumeTrack: Not resuming because exceeded the maximum " "shouldResumeTrack: Not resuming because exceeded the maximum "
+ "number of auto-resume retries"); + "number of auto-resume retries");
return false; return false;
@@ -853,13 +854,13 @@ public class TrackRecordingService extends Service implements LocationListener {
// Check for special cases. // Check for special cases.
if (autoResumeTrackTimeout == 0) { if (autoResumeTrackTimeout == 0) {
// Never resume. // Never resume.
Log.d(MyTracksConstants.TAG, Log.d(TAG,
"shouldResumeTrack: Auto-resume disabled (never resume)"); "shouldResumeTrack: Auto-resume disabled (never resume)");
return false; return false;
} else if (autoResumeTrackTimeout == -1) { } else if (autoResumeTrackTimeout == -1) {
// Always resume. // Always resume.
Log.d(MyTracksConstants.TAG, Log.d(TAG,
"shouldResumeTrack: Auto-resume forced (always resume)"); "shouldResumeTrack: Auto-resume forced (always resume)");
return true; return true;
} }
@@ -867,11 +868,11 @@ public class TrackRecordingService extends Service implements LocationListener {
// Check if the last modified time is within the acceptable range. // Check if the last modified time is within the acceptable range.
long lastModified = long lastModified =
track.getStatistics() != null ? track.getStatistics().getStopTime() : 0; track.getStatistics() != null ? track.getStatistics().getStopTime() : 0;
Log.d(MyTracksConstants.TAG, Log.d(TAG,
"shouldResumeTrack: lastModified = " + lastModified "shouldResumeTrack: lastModified = " + lastModified
+ ", autoResumeTrackTimeout: " + autoResumeTrackTimeout); + ", autoResumeTrackTimeout: " + autoResumeTrackTimeout);
return lastModified > 0 && System.currentTimeMillis() - lastModified <= return lastModified > 0 && System.currentTimeMillis() - lastModified <=
autoResumeTrackTimeout * 60 * 1000; autoResumeTrackTimeout * 60 * 1000;
} }
public boolean isRecording() { public boolean isRecording() {
@@ -897,7 +898,8 @@ public class TrackRecordingService extends Service implements LocationListener {
} }
wpt.setTrackId(recordingTrackId); wpt.setTrackId(recordingTrackId);
wpt.setLength(length); wpt.setLength(length);
if (lastValidLocation == null) { if (lastLocation == null
|| statsBuilder == null || statsBuilder.getStatistics() == null) {
// A null location is ok, and expected on track start. // A null location is ok, and expected on track start.
// Make it an impossible location. // Make it an impossible location.
Location l = new Location(""); Location l = new Location("");
@@ -905,11 +907,9 @@ public class TrackRecordingService extends Service implements LocationListener {
l.setLongitude(180); l.setLongitude(180);
wpt.setLocation(l); wpt.setLocation(l);
} else { } else {
// A null location is ok, and expected on track start.
wpt.setLocation(lastLocation); wpt.setLocation(lastLocation);
if (lastLocation != null) { wpt.setDuration(lastLocation.getTime()
wpt.setDuration(lastLocation.getTime() - statsBuilder.getStatistics().getStartTime()); - statsBuilder.getStatistics().getStartTime());
}
} }
Uri uri = providerUtils.insertWaypoint(wpt); Uri uri = providerUtils.insertWaypoint(wpt);
return Long.parseLong(uri.getLastPathSegment()); return Long.parseLong(uri.getLastPathSegment());
@@ -962,27 +962,27 @@ public class TrackRecordingService extends Service implements LocationListener {
// Create a new stats keeper for the next marker. // Create a new stats keeper for the next marker.
waypointStatsBuilder = new TripStatisticsBuilder(time); waypointStatsBuilder = new TripStatisticsBuilder(time);
} }
private ServiceBinder binder = new ServiceBinder(this); private ServiceBinder binder = new ServiceBinder(this);
/** /**
* TODO: There is a bug in Android that leaks Binder instances. This bug is * TODO: There is a bug in Android that leaks Binder instances. This bug is
* especially visible if we have a non-static class, as there is no way to * especially visible if we have a non-static class, as there is no way to
* nullify reference to the outer class (the service). * nullify reference to the outer class (the service).
* A workaround is to use a static class and explicitly clear service * A workaround is to use a static class and explicitly clear service
* and detach it from the underlying Binder. With this approach, we minimize * and detach it from the underlying Binder. With this approach, we minimize
* the leak to 24 bytes per each service instance. * the leak to 24 bytes per each service instance.
* *
* For more details, see the following bug: * For more details, see the following bug:
* http://code.google.com/p/android/issues/detail?id=6426. * http://code.google.com/p/android/issues/detail?id=6426.
*/ */
private static class ServiceBinder extends ITrackRecordingService.Stub { private static class ServiceBinder extends ITrackRecordingService.Stub {
private TrackRecordingService service; private TrackRecordingService service;
public ServiceBinder(TrackRecordingService service) { public ServiceBinder(TrackRecordingService service) {
this.service = service; this.service = service;
} }
/** /**
* Clears the reference to the outer class to minimize the leak. * Clears the reference to the outer class to minimize the leak.
*/ */
@@ -990,7 +990,7 @@ public class TrackRecordingService extends Service implements LocationListener {
this.service = null; this.service = null;
attachInterface(null, null); attachInterface(null, null);
} }
@Override @Override
public boolean isRecording() { public boolean isRecording() {
checkService(); checkService();
@@ -1005,13 +1005,13 @@ public class TrackRecordingService extends Service implements LocationListener {
@Override @Override
public long getRecordingTrackId() { public long getRecordingTrackId() {
checkService(); checkService();
return service.recordingTrackId; return service.recordingTrackId;
} }
@Override @Override
public boolean hasRecorded() { public boolean hasRecorded() {
checkService(); checkService();
return service.providerUtils.getLastTrackId() >= 0; return service.providerUtils.getLastTrackId() >= 0;
} }
@@ -1049,19 +1049,19 @@ public class TrackRecordingService extends Service implements LocationListener {
@Override @Override
public void recordLocation(Location loc) { public void recordLocation(Location loc) {
checkService(); checkService();
service.onLocationChanged(loc); service.onLocationChanged(loc);
} }
@Override @Override
public byte[] getSensorData() { public byte[] getSensorData() {
checkService(); checkService();
if (service.sensorManager == null) { if (service.sensorManager == null) {
Log.d(MyTracksConstants.TAG, "No sensor manager for data."); Log.d(TAG, "No sensor manager for data.");
return null; return null;
} }
if (service.sensorManager.getSensorDataSet() == null) { if (service.sensorManager.getSensorDataSet() == null) {
Log.d(MyTracksConstants.TAG, "Sensor data set is null."); Log.d(TAG, "Sensor data set is null.");
return null; return null;
} }
return service.sensorManager.getSensorDataSet().toByteArray(); return service.sensorManager.getSensorDataSet().toByteArray();
@@ -1069,9 +1069,9 @@ public class TrackRecordingService extends Service implements LocationListener {
@Override @Override
public int getSensorState() { public int getSensorState() {
checkService(); checkService();
if (service.sensorManager == null) { if (service.sensorManager == null) {
Log.d(MyTracksConstants.TAG, "No sensor manager for data."); Log.d(TAG, "No sensor manager for data.");
return Sensor.SensorState.NONE.getNumber(); return Sensor.SensorState.NONE.getNumber();
} }
return service.sensorManager.getSensorState().getNumber(); return service.sensorManager.getSensorState().getNumber();
@@ -1079,7 +1079,7 @@ public class TrackRecordingService extends Service implements LocationListener {
} }
public long startNewTrack() { public long startNewTrack() {
Log.d(MyTracksConstants.TAG, "TrackRecordingService.startNewTrack"); Log.d(TAG, "TrackRecordingService.startNewTrack");
if (recordingTrackId != -1 || isRecording) { if (recordingTrackId != -1 || isRecording) {
throw new IllegalStateException("A track is already in progress!"); throw new IllegalStateException("A track is already in progress!");
} }
@@ -1129,7 +1129,7 @@ public class TrackRecordingService extends Service implements LocationListener {
} }
private void endCurrentTrack() { private void endCurrentTrack() {
Log.d(MyTracksConstants.TAG, "TrackRecordingService.endCurrentTrack"); Log.d(TAG, "TrackRecordingService.endCurrentTrack");
if (recordingTrackId == -1 || !isRecording) { if (recordingTrackId == -1 || !isRecording) {
throw new IllegalStateException("No recording track in progress!"); throw new IllegalStateException("No recording track in progress!");
} }
@@ -1156,12 +1156,12 @@ public class TrackRecordingService extends Service implements LocationListener {
showNotification(); showNotification();
long recordedTrackId = recordingTrackId; long recordedTrackId = recordingTrackId;
prefManager.setRecordingTrack(recordingTrackId = -1); prefManager.setRecordingTrack(recordingTrackId = -1);
if (sensorManager != null) { if (sensorManager != null) {
sensorManager.shutdown(); sensorManager.shutdown();
sensorManager = null; sensorManager = null;
} }
releaseWakeLock(); releaseWakeLock();
// Notify the world that we're no longer recording. // Notify the world that we're no longer recording.
@@ -1243,11 +1243,11 @@ public class TrackRecordingService extends Service implements LocationListener {
LocationListenerPolicy locationListenerPolicy) { LocationListenerPolicy locationListenerPolicy) {
this.locationListenerPolicy = locationListenerPolicy; this.locationListenerPolicy = locationListenerPolicy;
} }
public int getAutoResumeTrackTimeout() { public int getAutoResumeTrackTimeout() {
return autoResumeTrackTimeout; return autoResumeTrackTimeout;
} }
public void setAutoResumeTrackTimeout(int autoResumeTrackTimeout) { public void setAutoResumeTrackTimeout(int autoResumeTrackTimeout) {
this.autoResumeTrackTimeout = autoResumeTrackTimeout; this.autoResumeTrackTimeout = autoResumeTrackTimeout;
} }
@@ -15,17 +15,17 @@
*/ */
package com.google.android.apps.mytracks.services.sensors; package com.google.android.apps.mytracks.services.sensors;
import static com.google.android.apps.mytracks.MyTracksConstants.TAG; import static com.google.android.apps.mytracks.Constants.TAG;
import com.dsi.ant.AntDefine;
import com.dsi.ant.AntMesg;
import com.dsi.ant.exception.AntInterfaceException;
import com.google.android.apps.mytracks.MyTracksSettings; import com.google.android.apps.mytracks.MyTracksSettings;
import com.google.android.apps.mytracks.content.Sensor; import com.google.android.apps.mytracks.content.Sensor;
import com.google.android.apps.mytracks.services.sensors.ant.AntChannelIdMessage; import com.google.android.apps.mytracks.services.sensors.ant.AntChannelIdMessage;
import com.google.android.apps.mytracks.services.sensors.ant.AntChannelResponseMessage; import com.google.android.apps.mytracks.services.sensors.ant.AntChannelResponseMessage;
import com.google.android.maps.mytracks.R; import com.google.android.maps.mytracks.R;
import com.dsi.ant.AntDefine;
import com.dsi.ant.AntMesg;
import com.dsi.ant.exception.AntInterfaceException;
import android.content.Context; import android.content.Context;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.util.Log; import android.util.Log;
@@ -15,14 +15,14 @@
*/ */
package com.google.android.apps.mytracks.services.sensors; package com.google.android.apps.mytracks.services.sensors;
import static com.google.android.apps.mytracks.MyTracksConstants.TAG; import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.MyTracksSettings;
import com.google.android.apps.mytracks.content.Sensor;
import com.google.android.maps.mytracks.R;
import com.dsi.ant.AntDefine; import com.dsi.ant.AntDefine;
import com.dsi.ant.AntMesg; import com.dsi.ant.AntMesg;
import com.dsi.ant.exception.AntInterfaceException; import com.dsi.ant.exception.AntInterfaceException;
import com.google.android.apps.mytracks.MyTracksSettings;
import com.google.android.apps.mytracks.content.Sensor;
import com.google.android.maps.mytracks.R;
import android.content.Context; import android.content.Context;
import android.content.SharedPreferences; import android.content.SharedPreferences;
@@ -82,10 +82,10 @@ public class AntSRMSensorManager extends AntSensorManager {
@Override @Override
public void handleMessage(byte[] antMessage) { public void handleMessage(byte[] antMessage) {
// Parse channel number // Parse channel number
byte receivedChannel = (byte) (antMessage[AntMesg.MESG_DATA_OFFSET] byte recievedChannel = (byte) (antMessage[AntMesg.MESG_DATA_OFFSET]
& AntDefine.CHANNEL_NUMBER_MASK); & AntDefine.CHANNEL_NUMBER_MASK);
if (receivedChannel != channel) { if (recievedChannel != channel) {
Log.d(TAG, "Unexpected channel: " + receivedChannel); Log.d(Constants.TAG, "Unexpected channel: " + recievedChannel);
return; return;
} }
switch (antMessage[AntMesg.MESG_ID_OFFSET]) { switch (antMessage[AntMesg.MESG_ID_OFFSET]) {
@@ -99,17 +99,18 @@ public class AntSRMSensorManager extends AntSensorManager {
handleChannelId(antMessage); handleChannelId(antMessage);
break; break;
default: default:
Log.e(TAG, "Unexpected message id: " + antMessage[3]); Log.e(Constants.TAG,
"Unexpected message id: " + antMessage[3]);
} }
} }
private void handleBroadcastData(byte[] antMessage) { private void handleBroadcastData(byte[] antMessage) {
if (deviceId == WILDCARD) { if (deviceId == WILDCARD) {
try { try {
Log.d(TAG, "Requesting channel id id."); Log.d(Constants.TAG, "Requesting channel id id.");
getAntReceiver().ANTRequestMessage(channel, AntMesg.MESG_CHANNEL_ID_ID); getAntReceiver().ANTRequestMessage(channel, AntMesg.MESG_CHANNEL_ID_ID);
} catch (AntInterfaceException e) { } catch (AntInterfaceException e) {
Log.e(TAG, "Failed to request channel id id", e); Log.e(Constants.TAG, "Failed to request channel id id", e);
} }
} }
setSensorState(Sensor.SensorState.CONNECTED); setSensorState(Sensor.SensorState.CONNECTED);
@@ -121,14 +122,15 @@ public class AntSRMSensorManager extends AntSensorManager {
parseSensorData(antMessage); parseSensorData(antMessage);
break; break;
default: default:
Log.e(TAG, "Unexpected message type: " + antMessage[MESSAGE_TYPE_INDEX]); Log.e(Constants.TAG,
"Unexpected message type: " + antMessage[MESSAGE_TYPE_INDEX]);
} }
} }
private void handleChannelId(byte[] antMessage) { private void handleChannelId(byte[] antMessage) {
// Store the device id. // Store the device id.
deviceId = antMessage[3]; deviceId = antMessage[3];
Log.i(TAG, "Found device id: " + deviceId); Log.i(Constants.TAG, "Found device id: " + deviceId);
SharedPreferences prefs = context.getSharedPreferences( SharedPreferences prefs = context.getSharedPreferences(
MyTracksSettings.SETTINGS_NAME, Context.MODE_PRIVATE); MyTracksSettings.SETTINGS_NAME, Context.MODE_PRIVATE);
@@ -141,34 +143,38 @@ public class AntSRMSensorManager extends AntSensorManager {
if (antMessage[3] == AntMesg.MESG_EVENT_ID if (antMessage[3] == AntMesg.MESG_EVENT_ID
&& antMessage[4] == AntDefine.EVENT_RX_SEARCH_TIMEOUT) { && antMessage[4] == AntDefine.EVENT_RX_SEARCH_TIMEOUT) {
// Search timeout // Search timeout
Log.w(TAG, "Search timed out. Unassigning channel."); Log.w(Constants.TAG, "Search timed out. Unassigning channel.");
try { try {
getAntReceiver().ANTUnassignChannel(channel); getAntReceiver().ANTUnassignChannel(channel);
} catch (AntInterfaceException e) { } catch (AntInterfaceException e) {
Log.e(TAG, "Failed to unassign ANT channel", e); Log.e(Constants.TAG, "Failed to unassign ANT channel", e);
} }
setSensorState(Sensor.SensorState.DISCONNECTED); setSensorState(Sensor.SensorState.DISCONNECTED);
} else if (antMessage[3] == AntMesg.MESG_UNASSIGN_CHANNEL_ID) { } else if (antMessage[3] == AntMesg.MESG_UNASSIGN_CHANNEL_ID) {
setSensorState(Sensor.SensorState.DISCONNECTED); setSensorState(Sensor.SensorState.DISCONNECTED);
Log.i(TAG, "Disconnected from the sensor: " + getSensorState()); Log.i(Constants.TAG,
"Disconnected from the sensor: " + getSensorState());
} }
} }
private void parseSensorData(byte[] antMessage) { private void parseSensorData(byte[] antMessage) {
if (antMessage.length != 11) { if (antMessage.length != 11) {
Log.e(TAG, "Unexpected ant message length: " + antMessage.length); Log.e(Constants.TAG,
"Unexpected ant message length: " + antMessage.length);
return; return;
} }
int newMessageId = antMessage[MESSAGE_ID_INDEX] & 0xFF; int newMessageId = antMessage[MESSAGE_ID_INDEX] & 0xFF;
if (lastMessageId == newMessageId) { if (lastMessageId == newMessageId) {
// Repeated message. // Repeated message.
Log.i(TAG, String.format("SRM ignoring repeat: 0x%X", newMessageId)); Log.i(Constants.TAG,
String.format("SRM ignoring repeat: 0x%X", newMessageId));
return; return;
} }
if (newMessageId < lastMessageId) { if (newMessageId < lastMessageId) {
if (!(newMessageId < 20 && lastMessageId > 200)) { if (!(newMessageId < 20 && lastMessageId > 200)) {
Log.i(TAG, String.format("SRM ignoring repeat: 0x%X", newMessageId)); Log.i(Constants.TAG,
String.format("SRM ignoring repeat: 0x%X", newMessageId));
return; return;
} // else assume the byte overflowed to 0. } // else assume the byte overflowed to 0.
} }
@@ -15,16 +15,16 @@
*/ */
package com.google.android.apps.mytracks.services.sensors; package com.google.android.apps.mytracks.services.sensors;
import static com.google.android.apps.mytracks.MyTracksConstants.TAG; import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.content.Sensor;
import com.google.android.apps.mytracks.content.Sensor.SensorDataSet;
import com.google.android.apps.mytracks.services.sensors.ant.AntStartupMessage;
import com.dsi.ant.AntDefine; import com.dsi.ant.AntDefine;
import com.dsi.ant.AntInterface; import com.dsi.ant.AntInterface;
import com.dsi.ant.AntInterfaceIntent; import com.dsi.ant.AntInterfaceIntent;
import com.dsi.ant.AntMesg; import com.dsi.ant.AntMesg;
import com.dsi.ant.exception.AntInterfaceException; import com.dsi.ant.exception.AntInterfaceException;
import com.google.android.apps.mytracks.content.Sensor;
import com.google.android.apps.mytracks.content.Sensor.SensorDataSet;
import com.google.android.apps.mytracks.services.sensors.ant.AntStartupMessage;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
import android.content.Context; import android.content.Context;
@@ -84,7 +84,7 @@ public abstract class AntSensorManager extends SensorManager {
@Override @Override
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
String antAction = intent.getAction(); String antAction = intent.getAction();
Log.i(TAG, "enter status onReceive" + antAction); Log.i(Constants.TAG, "enter status onReceive" + antAction);
} }
}; };
@@ -93,12 +93,12 @@ public abstract class AntSensorManager extends SensorManager {
@Override @Override
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
String antAction = intent.getAction(); String antAction = intent.getAction();
Log.i(TAG, "enter data onReceive" + antAction); Log.i(Constants.TAG, "enter data onReceive" + antAction);
if (antAction.equals(AntInterfaceIntent.ANT_RX_MESSAGE_ACTION)) { if (antAction.equals(AntInterfaceIntent.ANT_RX_MESSAGE_ACTION)) {
byte[] antMessage = intent.getByteArrayExtra(AntInterfaceIntent.ANT_MESSAGE); byte[] antMessage = intent.getByteArrayExtra(AntInterfaceIntent.ANT_MESSAGE);
if (DEBUGGING) { if (DEBUGGING) {
Log.d(TAG, "Received RX message " + messageToString(antMessage)); Log.d(Constants.TAG, "Received RX message " + messageToString(antMessage));
} }
handleMessage(antMessage); handleMessage(antMessage);
@@ -119,7 +119,7 @@ public abstract class AntSensorManager extends SensorManager {
@Override @Override
public void onServiceDisconnected() { public void onServiceDisconnected() {
Log.d(TAG, "ANT interface reports disconnection"); Log.d(Constants.TAG, "ANT interface reports disconnection");
} }
}; };
@@ -129,14 +129,14 @@ public abstract class AntSensorManager extends SensorManager {
@Override @Override
public void onDestroy() { public void onDestroy() {
Log.i(TAG, "destroying AntSensorManager"); Log.i(Constants.TAG, "destroying AntSensorManager");
context.unregisterReceiver(statusReceiver); context.unregisterReceiver(statusReceiver);
context.unregisterReceiver(dataReceiver); context.unregisterReceiver(dataReceiver);
try { try {
antReceiver.releaseInterface(); antReceiver.releaseInterface();
} catch (AntInterfaceException e) { } catch (AntInterfaceException e) {
Log.e(TAG, "failed to release ANT interface", e); Log.e(Constants.TAG, "failed to release ANT interface", e);
} }
antReceiver.destroy(); antReceiver.destroy();
@@ -177,7 +177,7 @@ public abstract class AntSensorManager extends SensorManager {
antReceiver = AntInterface.getInstance(context, antServiceListener); antReceiver = AntInterface.getInstance(context, antServiceListener);
if (antReceiver == null) { if (antReceiver == null) {
Log.e(TAG, "Failed to get ANT Receiver"); Log.e(Constants.TAG, "Failed to get ANT Receiver");
return; return;
} }
@@ -190,11 +190,11 @@ public abstract class AntSensorManager extends SensorManager {
* to initiate any ANT commands. * to initiate any ANT commands.
*/ */
private synchronized void serviceConnected() { private synchronized void serviceConnected() {
Log.d(TAG, "ANT service connected"); Log.d(Constants.TAG, "ANT service connected");
try { try {
if (!antReceiver.claimInterface()) { if (!antReceiver.claimInterface()) {
Log.e(TAG, "failed to claim ANT interface"); Log.e(Constants.TAG, "failed to claim ANT interface");
return; return;
} }
@@ -202,14 +202,14 @@ public abstract class AntSensorManager extends SensorManager {
// Make sure not to call AntInterface.enable() again, if it has been // Make sure not to call AntInterface.enable() again, if it has been
// already called before // already called before
if (antInterrupted == false) { if (antInterrupted == false) {
Log.i(TAG, "Powering on Radio"); Log.i(Constants.TAG, "Powering on Radio");
antReceiver.enable(); antReceiver.enable();
} }
} else { } else {
Log.i(TAG, "Radio already enabled"); Log.i(Constants.TAG, "Radio already enabled");
} }
} catch (AntInterfaceException e) { } catch (AntInterfaceException e) {
Log.e(TAG, "failed to enable ANT", e); Log.e(Constants.TAG, "failed to enable ANT", e);
} }
try { try {
@@ -220,7 +220,7 @@ public abstract class AntSensorManager extends SensorManager {
// that message. // that message.
antReceiver.ANTResetSystem(); antReceiver.ANTResetSystem();
} catch (AntInterfaceException e) { } catch (AntInterfaceException e) {
Log.e(TAG, "failed to reset ANT (expected exception)", e); Log.e(Constants.TAG, "failed to reset ANT (expected exception)", e);
} }
} }
@@ -232,7 +232,7 @@ public abstract class AntSensorManager extends SensorManager {
protected void handleMessage(byte[] antMessage) { protected void handleMessage(byte[] antMessage) {
int len = antMessage[0]; int len = antMessage[0];
if (len != antMessage.length - 2 || antMessage.length <= 2) { if (len != antMessage.length - 2 || antMessage.length <= 2) {
Log.e(TAG, "Invalid message: " + messageToString(antMessage)); Log.e(Constants.TAG, "Invalid message: " + messageToString(antMessage));
return; return;
} }
@@ -253,7 +253,8 @@ public abstract class AntSensorManager extends SensorManager {
*/ */
protected boolean handleMessage(byte messageId, byte[] messageData) { protected boolean handleMessage(byte messageId, byte[] messageData) {
if (messageId == AntMesg.MESG_STARTUP_MESG_ID) { if (messageId == AntMesg.MESG_STARTUP_MESG_ID) {
Log.d(TAG, String.format("Received startup message (reason %02x); initializing channel", Log.d(Constants.TAG, String.format(
"Received startup message (reason %02x); initializing channel",
new AntStartupMessage(messageData).getMessage())); new AntStartupMessage(messageData).getMessage()));
setupAntSensorChannels(); setupAntSensorChannels();
return true; return true;
@@ -304,13 +305,13 @@ public abstract class AntSensorManager extends SensorManager {
return true; return true;
} catch (AntInterfaceException e) { } catch (AntInterfaceException e) {
Log.e(TAG, "failed to setup ANT channel", e); Log.e(Constants.TAG, "failed to setup ANT channel", e);
return false; return false;
} }
} }
private void registerForAntIntents() { private void registerForAntIntents() {
Log.i(TAG, "Registering for ant intents."); Log.i(Constants.TAG, "Registering for ant intents.");
// Register for ANT intent broadcasts. // Register for ANT intent broadcasts.
IntentFilter statusIntentFilter = new IntentFilter(); IntentFilter statusIntentFilter = new IntentFilter();
statusIntentFilter.addAction(AntInterfaceIntent.ANT_ENABLED_ACTION); statusIntentFilter.addAction(AntInterfaceIntent.ANT_ENABLED_ACTION);
@@ -16,8 +16,7 @@
package com.google.android.apps.mytracks.services.sensors; package com.google.android.apps.mytracks.services.sensors;
import static com.google.android.apps.mytracks.MyTracksConstants.TAG; import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.content.Sensor; import com.google.android.apps.mytracks.content.Sensor;
import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothAdapter;
@@ -86,7 +85,7 @@ public class BluetoothConnectionManager {
*/ */
private synchronized void setState(Sensor.SensorState state) { private synchronized void setState(Sensor.SensorState state) {
// TODO pretty print this. // TODO pretty print this.
Log.d(TAG, "setState(" + state + ")"); Log.d(Constants.TAG, "setState(" + state + ")");
this.state = state; this.state = state;
// Give the new state to the Handler so the UI Activity can update // Give the new state to the Handler so the UI Activity can update
@@ -105,7 +104,7 @@ public class BluetoothConnectionManager {
* in listening (server) mode. Called by the Activity onResume() * in listening (server) mode. Called by the Activity onResume()
*/ */
public synchronized void start() { public synchronized void start() {
Log.d(TAG, "BluetoothConnectionManager.start()"); Log.d(Constants.TAG, "BluetoothConnectionManager.start()");
// Cancel any thread attempting to make a connection // Cancel any thread attempting to make a connection
if (connectThread != null) { if (connectThread != null) {
@@ -128,7 +127,7 @@ public class BluetoothConnectionManager {
* @param device The BluetoothDevice to connect * @param device The BluetoothDevice to connect
*/ */
public synchronized void connect(BluetoothDevice device) { public synchronized void connect(BluetoothDevice device) {
Log.d(TAG, "connect to: " + device); Log.d(Constants.TAG, "connect to: " + device);
// Cancel any thread attempting to make a connection // Cancel any thread attempting to make a connection
if (state == Sensor.SensorState.CONNECTING) { if (state == Sensor.SensorState.CONNECTING) {
@@ -158,7 +157,7 @@ public class BluetoothConnectionManager {
*/ */
public synchronized void connected(BluetoothSocket socket, public synchronized void connected(BluetoothSocket socket,
BluetoothDevice device) { BluetoothDevice device) {
Log.d(TAG, "connected"); Log.d(Constants.TAG, "connected");
// Cancel the thread that completed the connection // Cancel the thread that completed the connection
if (connectThread != null) { if (connectThread != null) {
@@ -190,7 +189,7 @@ public class BluetoothConnectionManager {
* Stop all threads * Stop all threads
*/ */
public synchronized void stop() { public synchronized void stop() {
Log.d(TAG, "stop()"); Log.d(Constants.TAG, "stop()");
if (connectThread != null) { if (connectThread != null) {
connectThread.cancel(); connectThread.cancel();
connectThread = null; connectThread = null;
@@ -227,7 +226,7 @@ public class BluetoothConnectionManager {
*/ */
private void connectionFailed() { private void connectionFailed() {
setState(Sensor.SensorState.DISCONNECTED); setState(Sensor.SensorState.DISCONNECTED);
Log.i(TAG, "Bluetooth connection failed."); Log.i(Constants.TAG, "Bluetooth connection failed.");
} }
/** /**
@@ -235,7 +234,7 @@ public class BluetoothConnectionManager {
*/ */
private void connectionLost() { private void connectionLost() {
setState(Sensor.SensorState.DISCONNECTED); setState(Sensor.SensorState.DISCONNECTED);
Log.i(TAG, "Bluetooth connection lost."); Log.i(Constants.TAG, "Bluetooth connection lost.");
} }
/** /**
@@ -256,7 +255,7 @@ public class BluetoothConnectionManager {
try { try {
tmp = getSocket(); tmp = getSocket();
} catch (IOException e) { } catch (IOException e) {
Log.e(TAG, "create() failed", e); Log.e(Constants.TAG, "create() failed", e);
} }
socket = tmp; socket = tmp;
} }
@@ -269,22 +268,22 @@ public class BluetoothConnectionManager {
insecure.setAccessible(true); insecure.setAccessible(true);
return (BluetoothSocket) insecure.invoke(device, 1); return (BluetoothSocket) insecure.invoke(device, 1);
} catch (SecurityException e) { } catch (SecurityException e) {
Log.e(TAG, "Unable to get insecure connect.", e); Log.e(Constants.TAG, "Unable to get insecure connect.", e);
} catch (NoSuchMethodException e) { } catch (NoSuchMethodException e) {
Log.e(TAG, "Unable to get insecure connect.", e); Log.e(Constants.TAG, "Unable to get insecure connect.", e);
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
Log.e(TAG, "Unable to get insecure connect.", e); Log.e(Constants.TAG, "Unable to get insecure connect.", e);
} catch (IllegalAccessException e) { } catch (IllegalAccessException e) {
Log.e(TAG, "Unable to get insecure connect.", e); Log.e(Constants.TAG, "Unable to get insecure connect.", e);
} catch (InvocationTargetException e) { } catch (InvocationTargetException e) {
Log.e(TAG, "Unable to get insecure connect.", e); Log.e(Constants.TAG, "Unable to get insecure connect.", e);
} }
return device.createRfcommSocketToServiceRecord(SPP_UUID); return device.createRfcommSocketToServiceRecord(SPP_UUID);
} }
@Override @Override
public void run() { public void run() {
Log.d(TAG, "BEGIN mConnectThread"); Log.d(Constants.TAG, "BEGIN mConnectThread");
// Always cancel discovery because it will slow down a connection // Always cancel discovery because it will slow down a connection
adapter.cancelDiscovery(); adapter.cancelDiscovery();
@@ -300,7 +299,8 @@ public class BluetoothConnectionManager {
try { try {
socket.close(); socket.close();
} catch (IOException e2) { } catch (IOException e2) {
Log.e(TAG, "unable to close() socket during connection failure", e2); Log.e(Constants.TAG,
"unable to close() socket during connection failure", e2);
} }
// Start the service over to restart listening mode // Start the service over to restart listening mode
BluetoothConnectionManager.this.start(); BluetoothConnectionManager.this.start();
@@ -320,7 +320,7 @@ public class BluetoothConnectionManager {
try { try {
socket.close(); socket.close();
} catch (IOException e) { } catch (IOException e) {
Log.e(TAG, "close() of connect socket failed", e); Log.e(Constants.TAG, "close() of connect socket failed", e);
} }
} }
} }
@@ -335,7 +335,7 @@ public class BluetoothConnectionManager {
private final OutputStream mmOutStream; private final OutputStream mmOutStream;
public ConnectedThread(BluetoothSocket socket) { public ConnectedThread(BluetoothSocket socket) {
Log.d(TAG, "create ConnectedThread"); Log.d(Constants.TAG, "create ConnectedThread");
btSocket = socket; btSocket = socket;
InputStream tmpIn = null; InputStream tmpIn = null;
OutputStream tmpOut = null; OutputStream tmpOut = null;
@@ -345,7 +345,7 @@ public class BluetoothConnectionManager {
tmpIn = socket.getInputStream(); tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream(); tmpOut = socket.getOutputStream();
} catch (IOException e) { } catch (IOException e) {
Log.e(TAG, "temp sockets not created", e); Log.e(Constants.TAG, "temp sockets not created", e);
} }
mmInStream = tmpIn; mmInStream = tmpIn;
@@ -354,7 +354,7 @@ public class BluetoothConnectionManager {
@Override @Override
public void run() { public void run() {
Log.i(TAG, "BEGIN mConnectedThread"); Log.i(Constants.TAG, "BEGIN mConnectedThread");
byte[] buffer = new byte[parser.getFrameSize()]; byte[] buffer = new byte[parser.getFrameSize()];
int bytes; int bytes;
int offset = 0; int offset = 0;
@@ -383,10 +383,11 @@ public class BluetoothConnectionManager {
// re-align // re-align
offset = parser.getFrameSize() - index; offset = parser.getFrameSize() - index;
System.arraycopy(buffer, index, buffer, 0, offset); System.arraycopy(buffer, index, buffer, 0, offset);
Log.w(TAG, "Misaligned data, found new message at " + index + " recovering..."); Log.w(Constants.TAG, "Misaligned data, found new message at " +
index + " recovering...");
continue; continue;
} }
Log.w(TAG, "Could not find valid data, dropping data"); Log.w(Constants.TAG, "Could not find valid data, dropping data");
offset = 0; offset = 0;
continue; continue;
} }
@@ -397,7 +398,7 @@ public class BluetoothConnectionManager {
handler.obtainMessage(MESSAGE_READ, bytes, -1, buffer) handler.obtainMessage(MESSAGE_READ, bytes, -1, buffer)
.sendToTarget(); .sendToTarget();
} catch (IOException e) { } catch (IOException e) {
Log.e(TAG, "disconnected", e); Log.e(Constants.TAG, "disconnected", e);
connectionLost(); connectionLost();
break; break;
} }
@@ -416,7 +417,7 @@ public class BluetoothConnectionManager {
// Share the sent message back to the UI Activity // Share the sent message back to the UI Activity
handler.obtainMessage(MESSAGE_WRITE, -1, -1, buffer).sendToTarget(); handler.obtainMessage(MESSAGE_WRITE, -1, -1, buffer).sendToTarget();
} catch (IOException e) { } catch (IOException e) {
Log.e(TAG, "Exception during write", e); Log.e(Constants.TAG, "Exception during write", e);
} }
} }
@@ -424,7 +425,7 @@ public class BluetoothConnectionManager {
try { try {
btSocket.close(); btSocket.close();
} catch (IOException e) { } catch (IOException e) {
Log.e(TAG, "close() of connect socket failed", e); Log.e(Constants.TAG, "close() of connect socket failed", e);
} }
} }
} }
@@ -15,8 +15,7 @@
*/ */
package com.google.android.apps.mytracks.services.sensors; package com.google.android.apps.mytracks.services.sensors;
import static com.google.android.apps.mytracks.MyTracksConstants.TAG; import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.MyTracksSettings; import com.google.android.apps.mytracks.MyTracksSettings;
import com.google.android.apps.mytracks.content.Sensor; import com.google.android.apps.mytracks.content.Sensor;
import com.google.android.maps.mytracks.R; import com.google.android.maps.mytracks.R;
@@ -51,7 +50,7 @@ public class BluetoothSensorManager extends SensorManager {
private Sensor.SensorDataSet sensorDataSet = null; private Sensor.SensorDataSet sensorDataSet = null;
private MessageParser parser; private MessageParser parser;
public BluetoothSensorManager( public BluetoothSensorManager(
Context context, MessageParser parser) { Context context, MessageParser parser) {
this.context = context; this.context = context;
@@ -67,7 +66,7 @@ public class BluetoothSensorManager extends SensorManager {
} }
private void setupSensor() { private void setupSensor() {
Log.d(TAG, "setupSensor()"); Log.d(Constants.TAG, "setupSensor()");
// Initialize the BluetoothSensorAdapter to perform bluetooth connections. // Initialize the BluetoothSensorAdapter to perform bluetooth connections.
connectionManager = new BluetoothConnectionManager(messageHandler, parser); connectionManager = new BluetoothConnectionManager(messageHandler, parser);
@@ -79,7 +78,7 @@ public class BluetoothSensorManager extends SensorManager {
public void setupChannel() { public void setupChannel() {
if (!isEnabled() || connectionManager == null) { if (!isEnabled() || connectionManager == null) {
Log.w(TAG, "Disabled manager onStartTrack"); Log.w(Constants.TAG, "Disabled manager onStartTrack");
return; return;
} }
SharedPreferences prefs = SharedPreferences prefs =
@@ -89,7 +88,7 @@ public class BluetoothSensorManager extends SensorManager {
if (address == null) { if (address == null) {
return; return;
} }
Log.w(TAG, "Connecting to bluetooth sensor: " + address); Log.w(Constants.TAG, "Connecting to bluetooth sensor: " + address);
// Get the BluetoothDevice object // Get the BluetoothDevice object
BluetoothDevice device = bluetoothAdapter.getRemoteDevice(address); BluetoothDevice device = bluetoothAdapter.getRemoteDevice(address);
// Attempt to connect to the device // Attempt to connect to the device
@@ -103,7 +102,7 @@ public class BluetoothSensorManager extends SensorManager {
// already // already
if (connectionManager.getState() == Sensor.SensorState.NONE) { if (connectionManager.getState() == Sensor.SensorState.NONE) {
// Start the Bluetooth sensor services // Start the Bluetooth sensor services
Log.w(TAG, "Disabled manager onStartTrack"); Log.w(Constants.TAG, "Disabled manager onStartTrack");
connectionManager.start(); connectionManager.start();
} }
} }
@@ -133,7 +132,7 @@ public class BluetoothSensorManager extends SensorManager {
switch (msg.what) { switch (msg.what) {
case BluetoothConnectionManager.MESSAGE_STATE_CHANGE: case BluetoothConnectionManager.MESSAGE_STATE_CHANGE:
// TODO should we update the SensorManager state var? // TODO should we update the SensorManager state var?
Log.i(TAG, "MESSAGE_STATE_CHANGE: " + msg.arg1); Log.i(Constants.TAG, "MESSAGE_STATE_CHANGE: " + msg.arg1);
break; break;
case BluetoothConnectionManager.MESSAGE_WRITE: case BluetoothConnectionManager.MESSAGE_WRITE:
break; break;
@@ -142,14 +141,15 @@ public class BluetoothSensorManager extends SensorManager {
try { try {
readBuf = (byte[]) msg.obj; readBuf = (byte[]) msg.obj;
sensorDataSet = parser.parseBuffer(readBuf); sensorDataSet = parser.parseBuffer(readBuf);
Log.d(TAG, "MESSAGE_READ: " + sensorDataSet.toString()); Log.d(Constants.TAG, "MESSAGE_READ: " + sensorDataSet.toString());
} catch (IllegalArgumentException iae) { } catch (IllegalArgumentException iae) {
sensorDataSet = null; sensorDataSet = null;
Log.i(TAG, "Got bad sensor data: " + new String(readBuf, 0, readBuf.length), Log.i(Constants.TAG,
"Got bad sensor data: " + new String(readBuf, 0, readBuf.length),
iae); iae);
} catch (RuntimeException re) { } catch (RuntimeException re) {
sensorDataSet = null; sensorDataSet = null;
Log.i(TAG, "Unexpected exception on read.", re); Log.i(Constants.TAG, "Unexpected exception on read.", re);
} }
break; break;
case BluetoothConnectionManager.MESSAGE_DEVICE_NAME: case BluetoothConnectionManager.MESSAGE_DEVICE_NAME:
@@ -15,14 +15,13 @@
*/ */
package com.google.android.apps.mytracks.services.sensors; package com.google.android.apps.mytracks.services.sensors;
import static com.google.android.apps.mytracks.MyTracksConstants.TAG; import java.util.Timer;
import java.util.TimerTask;
import com.google.android.apps.mytracks.content.Sensor;
import android.util.Log; import android.util.Log;
import java.util.Timer; import com.google.android.apps.mytracks.Constants;
import java.util.TimerTask; import com.google.android.apps.mytracks.content.Sensor;
/** /**
* Manage the connection to a sensor. * Manage the connection to a sensor.
@@ -51,17 +50,19 @@ public abstract class SensorManager {
private TimerTask checkSensorManager = new TimerTask() { private TimerTask checkSensorManager = new TimerTask() {
@Override @Override
public void run() { public void run() {
Log.i(TAG, "SensorManager state: " + getSensorState()); Log.i(Constants.TAG,
"SensorManager state: " + getSensorState());
switch (getSensorState()) { switch (getSensorState()) {
case CONNECTING: case CONNECTING:
long age = System.currentTimeMillis() - getSensorStateTimestamp(); long age = System.currentTimeMillis() - getSensorStateTimestamp();
if (age > 2 * RETRY_PERIOD) { if (age > 2 * RETRY_PERIOD) {
Log.i(TAG, "Retrying connecting SensorManager."); Log.i(Constants.TAG, "Retrying connecting SensorManager.");
setupChannel(); setupChannel();
} }
break; break;
case DISCONNECTED: case DISCONNECTED:
Log.i(TAG, "Re-registering disconnected SensorManager."); Log.i(Constants.TAG,
"Re-registering disconnected SensoManager.");
setupChannel(); setupChannel();
break; break;
} }
@@ -1,12 +1,12 @@
/* /*
* Copyright 2009 Google Inc. * Copyright 2009 Google Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); you may not * 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 * use this file except in compliance with the License. You may obtain a copy of
* the License at * the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
@@ -15,8 +15,7 @@
*/ */
package com.google.android.apps.mytracks.services.sensors; package com.google.android.apps.mytracks.services.sensors;
import static com.google.android.apps.mytracks.MyTracksConstants.TAG; import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.MyTracksSettings; import com.google.android.apps.mytracks.MyTracksSettings;
import com.google.android.maps.mytracks.R; import com.google.android.maps.mytracks.R;
@@ -30,7 +29,9 @@ import android.util.Log;
* @author Sandor Dornbush * @author Sandor Dornbush
*/ */
public class SensorManagerFactory { public class SensorManagerFactory {
private SensorManagerFactory() {}
private SensorManagerFactory() {
}
/** /**
* Get a new sensor manager. * Get a new sensor manager.
@@ -43,9 +44,9 @@ public class SensorManagerFactory {
if (prefs == null) { if (prefs == null) {
return null; return null;
} }
String sensor = prefs.getString(context.getString(R.string.sensor_type_key), null); String sensor = prefs.getString(context.getString(R.string.sensor_type_key), null);
Log.i(TAG, "Creating sensor of type: " + sensor); Log.i(Constants.TAG, "Creating sensor of type: " + sensor);
if (sensor == null) { if (sensor == null) {
return null; return null;
@@ -56,7 +57,7 @@ public class SensorManagerFactory {
} else if (sensor.equals(context.getString(R.string.zephyr_sensor_type))) { } else if (sensor.equals(context.getString(R.string.zephyr_sensor_type))) {
return new ZephyrSensorManager(context); return new ZephyrSensorManager(context);
} else { } else {
Log.w(TAG, "Unable to find sensor type: " + sensor); Log.w(Constants.TAG, "Unable to find sensor type: " + sensor);
return null; return null;
} }
} }
@@ -15,12 +15,11 @@
*/ */
package com.google.android.apps.mytracks.services.sensors; package com.google.android.apps.mytracks.services.sensors;
import static com.google.android.apps.mytracks.MyTracksConstants.TAG;
import com.google.android.apps.mytracks.content.Sensor;
import android.util.Log; import android.util.Log;
import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.content.Sensor;
/** /**
* An implementation of a SensorData parser for Zephyr HRM. * An implementation of a SensorData parser for Zephyr HRM.
* *
@@ -34,7 +33,7 @@ public class ZephyrMessageParser implements MessageParser {
for (int i = 0; i < buffer.length; i++) { for (int i = 0; i < buffer.length; i++) {
sb.append(String.format("%02X", buffer[i])); sb.append(String.format("%02X", buffer[i]));
} }
Log.w(TAG, "Got zephyr data: " + sb); Log.w(Constants.TAG, "Got zephyr data: " + sb);
// The provided units are 1/16 strides per minute. // The provided units are 1/16 strides per minute.
// TODO: Fix the cadence calculation. // TODO: Fix the cadence calculation.
// int cadence = SensorUtils.unsignedShortToInt(buffer, 56); // int cadence = SensorUtils.unsignedShortToInt(buffer, 56);
@@ -50,7 +49,7 @@ public class ZephyrMessageParser implements MessageParser {
.setCreationTime(System.currentTimeMillis()) .setCreationTime(System.currentTimeMillis())
.setHeartRate(b) .setHeartRate(b)
.build(); .build();
return sds; return sds;
} }
@@ -16,7 +16,9 @@
package com.google.android.apps.mytracks.stats; package com.google.android.apps.mytracks.stats;
import com.google.android.apps.mytracks.MyTracksConstants; import static com.google.android.apps.mytracks.Constants.TAG;
import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.MyTracksSettings; import com.google.android.apps.mytracks.MyTracksSettings;
import android.location.Location; import android.location.Location;
@@ -65,25 +67,25 @@ public class TripStatisticsBuilder {
* A buffer of the last speed readings in meters/second. * A buffer of the last speed readings in meters/second.
*/ */
private final DoubleBuffer speedBuffer = private final DoubleBuffer speedBuffer =
new DoubleBuffer(MyTracksConstants.SPEED_SMOOTHING_FACTOR); new DoubleBuffer(Constants.SPEED_SMOOTHING_FACTOR);
/** /**
* A buffer of the recent elevation readings in meters. * A buffer of the recent elevation readings in meters.
*/ */
private final DoubleBuffer elevationBuffer = private final DoubleBuffer elevationBuffer =
new DoubleBuffer(MyTracksConstants.ELEVATION_SMOOTHING_FACTOR); new DoubleBuffer(Constants.ELEVATION_SMOOTHING_FACTOR);
/** /**
* A buffer of the distance between recent gps readings in meters. * A buffer of the distance between recent gps readings in meters.
*/ */
private final DoubleBuffer distanceBuffer = private final DoubleBuffer distanceBuffer =
new DoubleBuffer(MyTracksConstants.DISTANCE_SMOOTHING_FACTOR); new DoubleBuffer(Constants.DISTANCE_SMOOTHING_FACTOR);
/** /**
* A buffer of the recent grade calculations. * A buffer of the recent grade calculations.
*/ */
private final DoubleBuffer gradeBuffer = private final DoubleBuffer gradeBuffer =
new DoubleBuffer(MyTracksConstants.GRADE_SMOOTHING_FACTOR); new DoubleBuffer(Constants.GRADE_SMOOTHING_FACTOR);
/** /**
* The total number of locations in this trip. * The total number of locations in this trip.
@@ -126,7 +128,7 @@ public class TripStatisticsBuilder {
*/ */
public boolean addLocation(Location currentLocation, long systemTime) { public boolean addLocation(Location currentLocation, long systemTime) {
if (paused) { if (paused) {
Log.w(MyTracksConstants.TAG, Log.w(TAG,
"Tried to account for location while track is paused"); "Tried to account for location while track is paused");
return false; return false;
} }
@@ -151,7 +153,7 @@ public class TripStatisticsBuilder {
// Don't do anything if we didn't move since last fix: // Don't do anything if we didn't move since last fix:
double distance = lastLocation.distanceTo(currentLocation); double distance = lastLocation.distanceTo(currentLocation);
if (distance < minRecordingDistance && if (distance < minRecordingDistance &&
currentSpeed < MyTracksConstants.MAX_NO_MOVEMENT_SPEED) { currentSpeed < Constants.MAX_NO_MOVEMENT_SPEED) {
lastLocation = currentLocation; lastLocation = currentLocation;
return false; return false;
} }
@@ -208,7 +210,7 @@ public class TripStatisticsBuilder {
// We are now sure the user is moving. // We are now sure the user is moving.
long timeDifference = updateTime - lastLocationTime; long timeDifference = updateTime - lastLocationTime;
if (timeDifference < 0) { if (timeDifference < 0) {
Log.e(MyTracksConstants.TAG, Log.e(TAG,
"Found negative time change: " + timeDifference); "Found negative time change: " + timeDifference);
} }
data.addMovingTime(timeDifference); data.addMovingTime(timeDifference);
@@ -224,7 +226,7 @@ public class TripStatisticsBuilder {
data.setMaxSpeed(movingSpeed); data.setMaxSpeed(movingSpeed);
} }
} else { } else {
Log.d(MyTracksConstants.TAG, Log.d(TAG,
"TripStatistics ignoring big change: Raw Speed: " + speed "TripStatistics ignoring big change: Raw Speed: " + speed
+ " old: " + lastLocationSpeed + " [" + toString() + "]"); + " old: " + lastLocationSpeed + " [" + toString() + "]");
} }
@@ -263,7 +265,7 @@ public class TripStatisticsBuilder {
// likely. Ignore any speeds that imply accelaration greater than 2g's // likely. Ignore any speeds that imply accelaration greater than 2g's
// Really who can accelerate faster? // Really who can accelerate faster?
double speedDifference = Math.abs(lastLocationSpeed - speed); double speedDifference = Math.abs(lastLocationSpeed - speed);
if (speedDifference > MyTracksConstants.MAX_ACCELERATION * timeDifference) { if (speedDifference > Constants.MAX_ACCELERATION * timeDifference) {
return false; return false;
} }
@@ -275,7 +277,7 @@ public class TripStatisticsBuilder {
double smoothedDiff = Math.abs(smoothedSpeed - speed); double smoothedDiff = Math.abs(smoothedSpeed - speed);
return !speedBuffer.isFull() || return !speedBuffer.isFull() ||
(speed < smoothedSpeed * 10 (speed < smoothedSpeed * 10
&& smoothedDiff < MyTracksConstants.MAX_ACCELERATION * timeDifference); && smoothedDiff < Constants.MAX_ACCELERATION * timeDifference);
} }
/** /**
@@ -15,7 +15,7 @@
*/ */
package com.google.android.apps.mytracks.util; package com.google.android.apps.mytracks.util;
import com.google.android.apps.mytracks.MyTracksConstants; import com.google.android.apps.mytracks.Constants;
import android.os.Build; import android.os.Build;
import android.util.Log; import android.util.Log;
@@ -72,7 +72,7 @@ public class ApiFeatures {
apiPlatformAdapter = new CupcakePlatformAdapter(); apiPlatformAdapter = new CupcakePlatformAdapter();
} }
Log.i(MyTracksConstants.TAG, "Using platform adapter " + apiPlatformAdapter.getClass()); Log.i(Constants.TAG, "Using platform adapter " + apiPlatformAdapter.getClass());
} }
public ApiPlatformAdapter getApiPlatformAdapter() { public ApiPlatformAdapter getApiPlatformAdapter() {
@@ -15,7 +15,7 @@
*/ */
package com.google.android.apps.mytracks.util; package com.google.android.apps.mytracks.util;
import com.google.android.apps.mytracks.MyTracksConstants; import com.google.android.apps.mytracks.Constants;
import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothClass; import android.bluetooth.BluetoothClass;
@@ -158,14 +158,14 @@ public abstract class BluetoothDeviceUtils {
public static BluetoothDeviceUtils getInstance() { public static BluetoothDeviceUtils getInstance() {
if (instance == null) { if (instance == null) {
if (!isBluetoothMethodSupported()) { if (!isBluetoothMethodSupported()) {
Log.d(MyTracksConstants.TAG, "Using dummy bluetooth utils"); Log.d(Constants.TAG, "Using dummy bluetooth utils");
instance = new DummyImpl(); instance = new DummyImpl();
} else { } else {
Log.d(MyTracksConstants.TAG, "Using real bluetooth utils"); Log.d(Constants.TAG, "Using real bluetooth utils");
try { try {
instance = new RealImpl(); instance = new RealImpl();
} catch (IllegalStateException ise) { } catch (IllegalStateException ise) {
Log.w(MyTracksConstants.TAG, "Oops, I mean, using dummy bluetooth utils", ise); Log.w(Constants.TAG, "Oops, I mean, using dummy bluetooth utils", ise);
instance = new DummyImpl(); instance = new DummyImpl();
} }
} }
@@ -15,7 +15,7 @@
*/ */
package com.google.android.apps.mytracks.util; package com.google.android.apps.mytracks.util;
import static com.google.android.apps.mytracks.MyTracksConstants.TAG; import static com.google.android.apps.mytracks.Constants.TAG;
import android.app.Notification; import android.app.Notification;
import android.app.NotificationManager; import android.app.NotificationManager;
import android.app.Service; import android.app.Service;
@@ -15,7 +15,7 @@
*/ */
package com.google.android.apps.mytracks.util; package com.google.android.apps.mytracks.util;
import com.google.android.apps.mytracks.MyTracksConstants; import com.google.android.apps.mytracks.Constants;
import android.os.Environment; import android.os.Environment;
@@ -49,7 +49,7 @@ public class FileUtils {
StringBuilder dirNameBuilder = new StringBuilder(); StringBuilder dirNameBuilder = new StringBuilder();
dirNameBuilder.append(Environment.getExternalStorageDirectory()); dirNameBuilder.append(Environment.getExternalStorageDirectory());
dirNameBuilder.append(File.separatorChar); dirNameBuilder.append(File.separatorChar);
dirNameBuilder.append(MyTracksConstants.SDCARD_TOP_DIR); dirNameBuilder.append(Constants.SDCARD_TOP_DIR);
for (String component : components) { for (String component : components) {
dirNameBuilder.append(File.separatorChar); dirNameBuilder.append(File.separatorChar);
dirNameBuilder.append(component); dirNameBuilder.append(component);
@@ -1,6 +1,6 @@
package com.google.android.apps.mytracks.util; package com.google.android.apps.mytracks.util;
import com.google.android.apps.mytracks.MyTracksConstants; import com.google.android.apps.mytracks.Constants;
import android.content.SharedPreferences.Editor; import android.content.SharedPreferences.Editor;
import android.os.StrictMode; import android.os.StrictMode;
@@ -21,7 +21,7 @@ public class GingerbreadPlatformAdapter extends EclairPlatformAdapter {
@Override @Override
public void enableStrictMode() { public void enableStrictMode() {
Log.d(MyTracksConstants.TAG, "Enabling strict mode"); Log.d(Constants.TAG, "Enabling strict mode");
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder() StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
.detectDiskWrites() .detectDiskWrites()
.detectNetwork() .detectNetwork()
@@ -15,7 +15,7 @@
*/ */
package com.google.android.apps.mytracks.util; package com.google.android.apps.mytracks.util;
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.content.Track;
import com.google.android.apps.mytracks.stats.TripStatistics; import com.google.android.apps.mytracks.stats.TripStatistics;
@@ -146,7 +146,7 @@ public class MyTracksUtils {
} }
idx++; idx++;
} }
Log.d(MyTracksConstants.TAG, "Decimating " + n + " points to " + i Log.d(Constants.TAG, "Decimating " + n + " points to " + i
+ " w/ tolerance = " + tolerance); + " w/ tolerance = " + tolerance);
} }
@@ -268,7 +268,7 @@ public class MyTracksUtils {
} }
} }
} catch (NameNotFoundException e) { } catch (NameNotFoundException e) {
Log.e(MyTracksConstants.TAG, "Unable to get signatures", e); Log.e(Constants.TAG, "Unable to get signatures", e);
} }
return false; return false;
} }
@@ -285,7 +285,7 @@ public class MyTracksUtils {
PackageManager.GET_META_DATA); PackageManager.GET_META_DATA);
return pi.versionName; return pi.versionName;
} catch (NameNotFoundException e) { } catch (NameNotFoundException e) {
Log.w(MyTracksConstants.TAG, "Failed to get version info.", e); Log.w(Constants.TAG, "Failed to get version info.", e);
return ""; return "";
} }
} }
@@ -295,19 +295,19 @@ public class MyTracksUtils {
* and gives up trying in case the wake lock cannot be acquired. * and gives up trying in case the wake lock cannot be acquired.
*/ */
public static WakeLock acquireWakeLock(Activity activity, WakeLock wakeLock) { public static WakeLock acquireWakeLock(Activity activity, WakeLock wakeLock) {
Log.i(MyTracksConstants.TAG, "MyTracksUtils: Acquiring wake lock."); Log.i(Constants.TAG, "MyTracksUtils: Acquiring wake lock.");
try { try {
PowerManager pm = (PowerManager) activity PowerManager pm = (PowerManager) activity
.getSystemService(Context.POWER_SERVICE); .getSystemService(Context.POWER_SERVICE);
if (pm == null) { if (pm == null) {
Log.e(MyTracksConstants.TAG, "MyTracksUtils: Power manager not found!"); Log.e(Constants.TAG, "MyTracksUtils: Power manager not found!");
return wakeLock; return wakeLock;
} }
if (wakeLock == null) { if (wakeLock == null) {
wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
MyTracksConstants.TAG); Constants.TAG);
if (wakeLock == null) { if (wakeLock == null) {
Log.e(MyTracksConstants.TAG, Log.e(Constants.TAG,
"MyTracksUtils: Could not create wake lock (null)."); "MyTracksUtils: Could not create wake lock (null).");
} }
return wakeLock; return wakeLock;
@@ -315,12 +315,12 @@ public class MyTracksUtils {
if (!wakeLock.isHeld()) { if (!wakeLock.isHeld()) {
wakeLock.acquire(); wakeLock.acquire();
if (!wakeLock.isHeld()) { if (!wakeLock.isHeld()) {
Log.e(MyTracksConstants.TAG, Log.e(Constants.TAG,
"MyTracksUtils: Could not acquire wake lock."); "MyTracksUtils: Could not acquire wake lock.");
} }
} }
} catch (RuntimeException e) { } catch (RuntimeException e) {
Log.e(MyTracksConstants.TAG, Log.e(Constants.TAG,
"MyTracksUtils: Caught unexpected exception: " + e.getMessage(), e); "MyTracksUtils: Caught unexpected exception: " + e.getMessage(), e);
} }
return wakeLock; return wakeLock;
@@ -165,7 +165,7 @@ public class MyTracksTest extends ActivityInstrumentationTestCase2<MyTracks>{
// Watch for MyTracksDetails activity. // Watch for MyTracksDetails activity.
ActivityMonitor monitor = getInstrumentation().addMonitor( ActivityMonitor monitor = getInstrumentation().addMonitor(
MyTracksDetails.class.getName(), null, false); TrackDetails.class.getName(), null, false);
// Now, stop the track and make sure that it is still selected, but // Now, stop the track and make sure that it is still selected, but
// no longer recording. // no longer recording.
@@ -173,7 +173,7 @@ public class MyTracksTest extends ActivityInstrumentationTestCase2<MyTracks>{
// Check if we got back MyTracksDetails activity. // Check if we got back MyTracksDetails activity.
Activity activity = getInstrumentation().waitForMonitor(monitor); Activity activity = getInstrumentation().waitForMonitor(monitor);
assertTrue(activity instanceof MyTracksDetails); assertTrue(activity instanceof TrackDetails);
// TODO: Update track name and other properties and test if they were // TODO: Update track name and other properties and test if they were
// properly saved. // properly saved.
@@ -4,21 +4,32 @@ package com.google.android.apps.mytracks.io;
import com.google.android.apps.mytracks.content.MyTracksLocation; import com.google.android.apps.mytracks.content.MyTracksLocation;
import com.google.android.apps.mytracks.content.Sensor; import com.google.android.apps.mytracks.content.Sensor;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.List;
import java.util.TimeZone;
import org.w3c.dom.Document; import org.w3c.dom.Document;
import org.w3c.dom.Element; import org.w3c.dom.Element;
import java.util.Date;
import java.util.List;
/** /**
* Tests for the GPX track exporter. * Tests for the GPX track exporter.
* *
* @author Sandor Dornbush * @author Sandor Dornbush
*/ */
public class TcxTrackWriterTest extends TrackFormatWriterTest { public class TcxTrackWriterTest extends TrackFormatWriterTest {
private DateFormat timestampFormatter;
@Override
public void setUp() throws Exception {
super.setUp();
timestampFormatter = new SimpleDateFormat(TcxTrackWriter.TIMESTAMP_FORMAT);
timestampFormatter.setTimeZone(TimeZone.getTimeZone("UTC"));
}
public void testXmlOutput() throws Exception { public void testXmlOutput() throws Exception {
TrackFormatWriter writer = new TcxTrackWriter(); TrackFormatWriter writer = new TcxTrackWriter(getContext());
String result = writeTrack(writer); String result = writeTrack(writer);
Document doc = parseXmlDocument(result); Document doc = parseXmlDocument(result);
@@ -58,8 +69,8 @@ public class TcxTrackWriterTest extends TrackFormatWriterTest {
getChildTextValue(posTag, "LatitudeDegrees")); getChildTextValue(posTag, "LatitudeDegrees"));
assertEquals(Double.toString(loc.getLongitude()), assertEquals(Double.toString(loc.getLongitude()),
getChildTextValue(posTag, "LongitudeDegrees")); getChildTextValue(posTag, "LongitudeDegrees"));
assertEquals(
TcxTrackWriter.TIMESTAMP_FORMAT.format(new Date(loc.getTime())), assertEquals(timestampFormatter.format(loc.getTime()),
getChildTextValue(tag, "Time")); getChildTextValue(tag, "Time"));
assertEquals(Double.toString(loc.getAltitude()), assertEquals(Double.toString(loc.getAltitude()),
getChildTextValue(tag, "AltitudeMeters")); getChildTextValue(tag, "AltitudeMeters"));
@@ -82,7 +82,6 @@ public class PreferenceBackupHelperTest extends TestCase {
return put(key, value); return put(key, value);
} }
@Override
public Editor putStringSet(String key, Set<String> value) { public Editor putStringSet(String key, Set<String> value) {
return put(key, value); return put(key, value);
} }
@@ -143,7 +142,6 @@ public class PreferenceBackupHelperTest extends TestCase {
return get(key, defValue); return get(key, defValue);
} }
@Override
public Set<String> getStringSet(String key, Set<String> defValue) { public Set<String> getStringSet(String key, Set<String> defValue) {
return get(key, defValue); return get(key, defValue);
} }
@@ -15,7 +15,7 @@
*/ */
package com.google.android.apps.mytracks.services; package com.google.android.apps.mytracks.services;
import static com.google.android.apps.mytracks.MyTracksConstants.RESUME_TRACK_EXTRA_NAME; import static com.google.android.apps.mytracks.Constants.RESUME_TRACK_EXTRA_NAME;
import com.google.android.apps.mytracks.MyTracksSettings; import com.google.android.apps.mytracks.MyTracksSettings;
import com.google.android.apps.mytracks.content.MyTracksProvider; import com.google.android.apps.mytracks.content.MyTracksProvider;
@@ -2,7 +2,7 @@
package com.google.android.apps.mytracks.stats; package com.google.android.apps.mytracks.stats;
import com.google.android.apps.mytracks.MyTracksConstants; import com.google.android.apps.mytracks.Constants;
import android.location.Location; import android.location.Location;
@@ -56,18 +56,18 @@ public class TripStatisticsBuilderTest extends TestCase {
assertEquals(10000 * i, stats.getTotalTime()); assertEquals(10000 * i, stats.getTotalTime());
assertEquals(10000 * i, stats.getMovingTime()); assertEquals(10000 * i, stats.getMovingTime());
assertEquals(i, builder.getSmoothedElevation(), assertEquals(i, builder.getSmoothedElevation(),
MyTracksConstants.ELEVATION_SMOOTHING_FACTOR / 2); Constants.ELEVATION_SMOOTHING_FACTOR / 2);
assertEquals(0.0, stats.getMinElevation()); assertEquals(0.0, stats.getMinElevation());
assertEquals(i, stats.getMaxElevation(), assertEquals(i, stats.getMaxElevation(),
MyTracksConstants.ELEVATION_SMOOTHING_FACTOR / 2); Constants.ELEVATION_SMOOTHING_FACTOR / 2);
assertEquals(i, stats.getTotalElevationGain(), assertEquals(i, stats.getTotalElevationGain(),
MyTracksConstants.ELEVATION_SMOOTHING_FACTOR); Constants.ELEVATION_SMOOTHING_FACTOR);
if (i > MyTracksConstants.SPEED_SMOOTHING_FACTOR) { if (i > Constants.SPEED_SMOOTHING_FACTOR) {
assertEquals(11.1f, stats.getMaxSpeed(), 0.1); assertEquals(11.1f, stats.getMaxSpeed(), 0.1);
} }
if ((i > MyTracksConstants.GRADE_SMOOTHING_FACTOR) if ((i > Constants.GRADE_SMOOTHING_FACTOR)
&& (i > MyTracksConstants.ELEVATION_SMOOTHING_FACTOR)) { && (i > Constants.ELEVATION_SMOOTHING_FACTOR)) {
assertEquals(0.009, stats.getMinGrade(), 0.0001); assertEquals(0.009, stats.getMinGrade(), 0.0001);
assertEquals(0.009, stats.getMaxGrade(), 0.0001); assertEquals(0.009, stats.getMaxGrade(), 0.0001);
} }
@@ -97,9 +97,9 @@ public class TripStatisticsBuilderTest extends TestCase {
public void testElevationGain() throws Exception { public void testElevationGain() throws Exception {
for (double i = 0; i < 1000; i++) { for (double i = 0; i < 1000; i++) {
double expectedGain; double expectedGain;
if (i < (MyTracksConstants.ELEVATION_SMOOTHING_FACTOR - 1)) { if (i < (Constants.ELEVATION_SMOOTHING_FACTOR - 1)) {
expectedGain = 0; expectedGain = 0;
} else if (i < MyTracksConstants.ELEVATION_SMOOTHING_FACTOR) { } else if (i < Constants.ELEVATION_SMOOTHING_FACTOR) {
expectedGain = 0.5; expectedGain = 0.5;
} else { } else {
expectedGain = 1.0; expectedGain = 1.0;
@@ -110,9 +110,9 @@ public class TripStatisticsBuilderTest extends TestCase {
TripStatistics data = builder.getStatistics(); TripStatistics data = builder.getStatistics();
assertEquals(0.0, data.getMinElevation(), 0.0); assertEquals(0.0, data.getMinElevation(), 0.0);
assertEquals(i, data.getMaxElevation(), assertEquals(i, data.getMaxElevation(),
MyTracksConstants.ELEVATION_SMOOTHING_FACTOR); Constants.ELEVATION_SMOOTHING_FACTOR);
assertEquals(i, data.getTotalElevationGain(), assertEquals(i, data.getTotalElevationGain(),
MyTracksConstants.ELEVATION_SMOOTHING_FACTOR); Constants.ELEVATION_SMOOTHING_FACTOR);
} }
} }
@@ -122,8 +122,8 @@ public class TripStatisticsBuilderTest extends TestCase {
// buffer. // buffer.
builder.updateElevation(i); builder.updateElevation(i);
builder.updateGrade(100, 100); builder.updateGrade(100, 100);
if ((i > MyTracksConstants.GRADE_SMOOTHING_FACTOR) if ((i > Constants.GRADE_SMOOTHING_FACTOR)
&& (i > MyTracksConstants.ELEVATION_SMOOTHING_FACTOR)) { && (i > Constants.ELEVATION_SMOOTHING_FACTOR)) {
assertEquals(1.0, builder.getStatistics().getMaxGrade()); assertEquals(1.0, builder.getStatistics().getMaxGrade());
assertEquals(1.0, builder.getStatistics().getMinGrade()); assertEquals(1.0, builder.getStatistics().getMinGrade());
} }
@@ -133,8 +133,8 @@ public class TripStatisticsBuilderTest extends TestCase {
// buffer. // buffer.
builder.updateElevation(i); builder.updateElevation(i);
builder.updateGrade(100, -100); builder.updateGrade(100, -100);
if ((i > MyTracksConstants.GRADE_SMOOTHING_FACTOR) if ((i > Constants.GRADE_SMOOTHING_FACTOR)
&& (i > MyTracksConstants.ELEVATION_SMOOTHING_FACTOR)) { && (i > Constants.ELEVATION_SMOOTHING_FACTOR)) {
assertEquals(1.0, builder.getStatistics().getMaxGrade()); assertEquals(1.0, builder.getStatistics().getMaxGrade());
assertEquals(-1.0, builder.getStatistics().getMinGrade()); assertEquals(-1.0, builder.getStatistics().getMinGrade());
} }
@@ -176,7 +176,7 @@ public class TripStatisticsBuilderTest extends TestCase {
for (int i = 0; i < 1000; i++) { for (int i = 0; i < 1000; i++) {
builder.updateSpeed(i + 1000, 4.0, i, 4.0); builder.updateSpeed(i + 1000, 4.0, i, 4.0);
assertEquals((i + 1) * 1000, builder.getStatistics().getMovingTime()); assertEquals((i + 1) * 1000, builder.getStatistics().getMovingTime());
if (i > MyTracksConstants.SPEED_SMOOTHING_FACTOR) { if (i > Constants.SPEED_SMOOTHING_FACTOR) {
assertEquals(4.0, builder.getStatistics().getMaxSpeed()); assertEquals(4.0, builder.getStatistics().getMaxSpeed());
} }
} }
@@ -15,7 +15,7 @@
*/ */
package com.google.android.apps.mytracks.util; package com.google.android.apps.mytracks.util;
import com.google.android.apps.mytracks.MyTracksConstants; import com.google.android.apps.mytracks.Constants;
import android.os.Environment; import android.os.Environment;
@@ -53,7 +53,7 @@ public class FileUtilsTest extends TestCase {
public void testBuildExternalDirectoryPath() { public void testBuildExternalDirectoryPath() {
String expectedName = Environment.getExternalStorageDirectory() String expectedName = Environment.getExternalStorageDirectory()
+ File.separator + File.separator
+ MyTracksConstants.SDCARD_TOP_DIR + Constants.SDCARD_TOP_DIR
+ File.separator + File.separator
+ "a" + "a"
+ File.separator + File.separator
+56
View File
@@ -0,0 +1,56 @@
#!/bin/bash
#
# 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.
# This script retrieves the value of a given named string from all indicated
# strings.xml files. If invoked in a project directory (a directory with a
# 'res' subdirectory), and if no strings.xml files are provided, the script
# will automatically analyze res/values*/strings.xml
PROGNAME=$(basename "$0")
function usage() {
echo "Usage: ${PROGNAME} string_name [file file..]" >&2
exit 2
}
function die() {
echo "${PROGNAME}: $@" >&2
exit 1
}
if [[ "$#" -lt 1 ]] ; then
usage
fi
name=$1
shift
files=
if [[ $# -eq 0 ]] ; then
if [[ -d res ]] ; then
files=res/values*/strings.xml
else
die "invoked outside of project root with no file arguments"
fi
else
files="$@"
fi
for file in $files ; do
echo === $file
xmllint --xpath /resources/string[@name=\"$name\"] $file
echo
done