When play track, add a containing folder to contain all the merged tracks

This commit is contained in:
Jimmy Shih
2013-10-02 15:22:00 -07:00
parent 7594f6b516
commit b182c1cb80
17 changed files with 503 additions and 369 deletions
+72 -62
View File
@@ -564,7 +564,7 @@ limitations under the License.
<string name="eula_body" <string name="eula_body"
translation_description="The body in the 'Terms of Service. See http://m.google.com/toscountry. translation_description="The body in the 'Terms of Service. See http://m.google.com/toscountry.
%1$s: host name, 'm.google.com'"> %1$s host name, 'm.google.com'">
By using Google\'s mobile products and services (&#8220;Services&#8221;), you agree to be bound By using Google\'s mobile products and services (&#8220;Services&#8221;), you agree to be bound
by a) the YouTube Terms of Use (%1$s/tos_youtube) for YouTube-related Services, b) the Google by a) the YouTube Terms of Use (%1$s/tos_youtube) for YouTube-related Services, b) the Google
Maps Terms and Conditions (%1$s/tos_maps) for mapping, local and location-based Services, c) the Maps Terms and Conditions (%1$s/tos_maps) for mapping, local and location-based Services, c) the
@@ -589,7 +589,7 @@ limitations under the License.
translation_description="The footer in the 'Terms of Service'. See translation_description="The footer in the 'Terms of Service'. See
http://m.google.com/toscountry. http://m.google.com/toscountry.
%1$s: host name, 'm.google.com'"> %1$s host name, 'm.google.com'">
Any required attribution or notice for the third party content may be found at Any required attribution or notice for the third party content may be found at
%1$s/legalnotices. %1$s/legalnotices.
</string> </string>
@@ -603,8 +603,8 @@ limitations under the License.
translation_description="When exporting all tracks to the external storage, the option to export translation_description="When exporting all tracks to the external storage, the option to export
as a certain file format. as a certain file format.
%1$s: the file format. E.g., 'KML'. %1$s the file format. E.g., 'KML'.
%2$s: the directory. E.g., '/MyTracks/kml'."> %2$s the directory. E.g., '/MyTracks/kml'.">
All as %1$s to %2$s All as %1$s to %2$s
</string> </string>
<string name="export_all_title" <string name="export_all_title"
@@ -638,14 +638,14 @@ limitations under the License.
translation_description="When exporting a track to the external storage, the option to export as translation_description="When exporting a track to the external storage, the option to export as
a certain file format. a certain file format.
%1$s: the file format. E.g., 'KML'. %1$s the file format. E.g., 'KML'.
%2$s: the directory. E.g., '/MyTracks/kml'."> %2$s the directory. E.g., '/MyTracks/kml'.">
as %1$s to %2$s as %1$s to %2$s
</string> </string>
<string name="export_external_storage_progress_message" <string name="export_external_storage_progress_message"
translation_description="When exporting tracks to the external storage, the progress message. translation_description="When exporting tracks to the external storage, the progress message.
%1$s: the directory. E.g., '/MyTracks/kml'."> %1$s the directory. E.g., '/MyTracks/kml'.">
Exporting to %1$s&#8230; Exporting to %1$s&#8230;
</string> </string>
<string name="export_external_storage_success" <string name="export_external_storage_success"
@@ -662,8 +662,8 @@ limitations under the License.
<string name="export_google_error" <string name="export_google_error"
translation_description="When exporting a track, the error message. translation_description="When exporting a track, the error message.
%1$s: service name. E.g, Google Maps. %1$s service name. E.g, Google Maps.
%2$s: service url. E.g, maps.google.com."> %2$s service url. E.g, maps.google.com.">
An error has occurred. Unable to export to %1$s (%2$s). Please try again. An error has occurred. Unable to export to %1$s (%2$s). Please try again.
</string> </string>
<string name="export_google_fusion_tables" <string name="export_google_fusion_tables"
@@ -702,8 +702,8 @@ limitations under the License.
translation_description="When sending a track to Google, the additional comment on the bottom of translation_description="When sending a track to Google, the additional comment on the bottom of
the result page. the result page.
%1$s: service name. E.g, Google Maps. %1$s service name. E.g, Google Maps.
%2$s: service url. E.g, maps.google.com."> %2$s service url. E.g, maps.google.com.">
Track exported to %1$s (%2$s). It may take a few minutes for it to appear. Track exported to %1$s (%2$s). It may take a few minutes for it to appear.
</string> </string>
<string name="export_title" <string name="export_title"
@@ -830,6 +830,10 @@ limitations under the License.
translation_description="The title on an alert dialog indicating success."> translation_description="The title on an alert dialog indicating success.">
Success Success
</string> </string>
<string name="generic_tracks"
translation_description="Generic title for a list of tracks.">
Tracks
</string>
<string name="generic_yes" <string name="generic_yes"
translation_description="The text on a button to say yes."> translation_description="The text on a button to say yes.">
Yes Yes
@@ -933,14 +937,14 @@ limitations under the License.
translation_description="When importing from the external storage, the error message when the translation_description="When importing from the external storage, the error message when the
directory doesn't exist. directory doesn't exist.
%1$s: the directory. E.g., '/MyTracks/kml'."> %1$s the directory. E.g., '/MyTracks/kml'.">
%1$s does not exist. %1$s does not exist.
</string> </string>
<string name="import_no_file" <string name="import_no_file"
translation_description="When importing from the external storage, the message in the result translation_description="When importing from the external storage, the message in the result
dialog when there is no files to import. dialog when there is no files to import.
%1$s: the directory. E.g., '/MyTracks/kml'."> %1$s the directory. E.g., '/MyTracks/kml'.">
There were no files to import. Connect your device to your computer and place the files to There were no files to import. Connect your device to your computer and place the files to
import in %1$s. import in %1$s.
</string> </string>
@@ -952,15 +956,15 @@ limitations under the License.
<string name="import_progress_message" <string name="import_progress_message"
translation_description="When importing from the external storage, the progress message. translation_description="When importing from the external storage, the progress message.
%1$s: the directory. E.g., '/MyTracks/kml'."> %1$s the directory. E.g., '/MyTracks/kml'.">
Importing from %1$s&#8230; Importing from %1$s&#8230;
</string> </string>
<string name="import_selection_option" <string name="import_selection_option"
translation_description="When importing all from external storage, the option to import all the translation_description="When importing all from external storage, the option to import all the
files of a certain file format. files of a certain file format.
%1$s: the file format. E.g., 'KML'. %1$s the file format. E.g., 'KML'.
%2$s: the directory. E.g., '/MyTracks/kml'."> %2$s the directory. E.g., '/MyTracks/kml'.">
All %1$s from %2$s All %1$s from %2$s
</string> </string>
<string name="import_selection_title" <string name="import_selection_title"
@@ -978,7 +982,7 @@ limitations under the License.
<!-- List item --> <!-- List item -->
<string name="list_item_selected" <string name="list_item_selected"
translation_description="Title indicating the number of items selected in a list. translation_description="Title indicating the number of items selected in a list.
%1$d: an integer value. E.g., '2'."> %1$d an integer value. E.g., '2'.">
%1$d selected %1$d selected
</string> </string>
@@ -1012,26 +1016,26 @@ limitations under the License.
translation_description="When inserting a marker to indicate the end of a track, the marker's translation_description="When inserting a marker to indicate the end of a track, the marker's
name. E.g., 'track_name (End)'. name. E.g., 'track_name (End)'.
%1$s track name. E.g., 'track_name'."> %1$s track name. E.g., 'Grand Canyon trail'.">
%1$s (End) %1$s (End)
</string> </string>
<string name="marker_label_start" <string name="marker_label_start"
translation_description="When inserting a marker to indicate the start of a track, the marker's translation_description="When inserting a marker to indicate the start of a track, the marker's
name. E.g., 'track_name (Start)'. name. E.g., 'track_name (Start)'.
%1$s track name. E.g., 'track_name'."> %1$s track name. E.g., 'Grand Canyon trail'.">
%1$s (Start) %1$s (Start)
</string> </string>
<string name="marker_name_format" <string name="marker_name_format"
translation_description="When adding a marker, the string format for the default name. translation_description="When adding a marker, the string format for the default name.
%1$d: number. E.g., '1'."> %1$d number. E.g., '1'.">
Marker %1$d Marker %1$d
</string> </string>
<string name="marker_split_name_format" <string name="marker_split_name_format"
translation_description="When adding a split marker, the string format for the default name. translation_description="When adding a split marker, the string format for the default name.
%1$d: number. E.g., '1'."> %1$d number. E.g., '1'.">
Split %1$d Split %1$d
</string> </string>
@@ -1334,7 +1338,7 @@ limitations under the License.
translation_description="For a marker returned in the search result, the text field indicating translation_description="For a marker returned in the search result, the text field indicating
the track that the marker belongs to. the track that the marker belongs to.
%1$s: track name. E.g., 'Grand Canyon trail'."> %1$s track name. E.g., 'Grand Canyon trail'.">
In track &#8216;%1$s&#8217;. In track &#8216;%1$s&#8217;.
</string> </string>
<string name="search_voice_prompt" <string name="search_voice_prompt"
@@ -1348,9 +1352,9 @@ limitations under the License.
translation_description="When sending a track to Google, a note indicating it is created by translation_description="When sending a track to Google, a note indicating it is created by
Google My Tracks on Android. Google My Tracks on Android.
%1$s: the html anchor opening tag. Place this placeholder before the app name, %1$s the html anchor opening tag. Place this placeholder before the app name,
'Google My Tracks'. 'Google My Tracks'.
%2$s: the html anchor closing tag. Place this placeholder after the app name, %2$s the html anchor closing tag. Place this placeholder after the app name,
'Google My Tracks'."> 'Google My Tracks'.">
Created by %1$sGoogle My Tracks%2$s on Android. Created by %1$sGoogle My Tracks%2$s on Android.
</string> </string>
@@ -1376,15 +1380,15 @@ limitations under the License.
<string name="send_google_progress_message" <string name="send_google_progress_message"
translation_description="When sending a track to a Google service, the progress message. translation_description="When sending a track to a Google service, the progress message.
%1$s: service name. 'Google Maps', 'Google Fusion Tables', or 'Google Spreadsheets'."> %1$s service name. 'Google Maps', 'Google Fusion Tables', or 'Google Spreadsheets'.">
Sending to %1$s&#8230; Sending to %1$s&#8230;
</string> </string>
<string name="send_google_track_part_label" <string name="send_google_track_part_label"
translation_description="When sending a track to Google, the label to name segments of a large translation_description="When sending a track to Google, the label to name segments of a large
track. E.g., 'track_name (Part 1)'. track. E.g., 'track_name (Part 1)'.
%1$s: track name. E.g., 'track_name'. %1$s track name. E.g., 'Grand Canyon trail'.
%2$d: part number. E.g., '1'."> %2$d part number. E.g., '1'.">
%1$s (Part %2$d) %1$s (Part %2$d)
</string> </string>
@@ -1405,7 +1409,7 @@ limitations under the License.
translation_description="In the 'Sensor state' page, the value for the 'Cadence'. Cadence is the translation_description="In the 'Sensor state' page, the value for the 'Cadence'. Cadence is the
number of revolutions of the crank per minute. E.g., 'Cadence: 80 rpm'. number of revolutions of the crank per minute. E.g., 'Cadence: 80 rpm'.
%1$d: a number. E.g., '80'."> %1$d a number. E.g., '80'.">
%1$d rpm %1$d rpm
</string> </string>
<string name="sensor_state_connected" <string name="sensor_state_connected"
@@ -1434,7 +1438,7 @@ limitations under the License.
translation_description="In the 'Sensor state' page, the value for the 'Heart rate'. E.g., translation_description="In the 'Sensor state' page, the value for the 'Heart rate'. E.g.,
'Hear rate: 100 bpm'. 'Hear rate: 100 bpm'.
%1$d: a number. E.g., '100'."> %1$d a number. E.g., '100'.">
%1$d bpm %1$d bpm
</string> </string>
<string name="sensor_state_last_sensor_time" <string name="sensor_state_last_sensor_time"
@@ -1453,7 +1457,7 @@ limitations under the License.
translation_description="In the 'Sensor state' page, the value for the 'Power'. Power is the translation_description="In the 'Sensor state' page, the value for the 'Power'. Power is the
power output of the rider. E.g., 'Power: 50 W'. power output of the rider. E.g., 'Power: 50 W'.
%1$d: a number. E.g., '50'."> %1$d a number. E.g., '50'.">
%1$d W %1$d W
</string> </string>
<string name="sensor_state_sending" <string name="sensor_state_sending"
@@ -1644,7 +1648,7 @@ limitations under the License.
summary for the 'Percentage from average' option explaining that the medium speed range is set summary for the 'Percentage from average' option explaining that the medium speed range is set
as a percentage from the average speed. as a percentage from the average speed.
%1$d: an integer value. E.g., '15'."> %1$d an integer value. E.g., '15'.">
The medium speed range is %1$d %% from the average speed The medium speed range is %1$d %% from the average speed
</string> </string>
<string name="settings_map_slow" <string name="settings_map_slow"
@@ -1859,7 +1863,7 @@ limitations under the License.
translation_description="In the 'Sensor' settings, the summary to indicate that an ANT+ sensor translation_description="In the 'Sensor' settings, the summary to indicate that an ANT+ sensor
is paired. Note that ANT+ is a radio standard. is paired. Note that ANT+ is a radio standard.
%1$d: device id number. E.g., '1'."> %1$d device id number. E.g., '1'.">
Paired with %1$d Paired with %1$d
</string> </string>
<string name="settings_sensor_ant_reset_bike_cadence_sensor" <string name="settings_sensor_ant_reset_bike_cadence_sensor"
@@ -1921,7 +1925,7 @@ limitations under the License.
<string name="settings_sensor_connected" <string name="settings_sensor_connected"
translation_description="A message when a sensor is connected. translation_description="A message when a sensor is connected.
%1$s: sensor name. E.g., 'Polar Bluetooth'."> %1$s sensor name. E.g., 'Polar Bluetooth'.">
Connected to %1$s Connected to %1$s
</string> </string>
<string name="settings_sensor_type" <string name="settings_sensor_type"
@@ -2081,7 +2085,7 @@ limitations under the License.
translation_description="When sharing a track file with friends, the body of the message. Note translation_description="When sharing a track file with friends, the body of the message. Note
that \n is the new line character. that \n is the new line character.
%1$s: track description."> %1$s track description.">
I think you might be interested in this track.\n\nTo view this track, use Google Earth or other I think you might be interested in this track.\n\nTo view this track, use Google Earth or other
mapping software.\n\n%1$s mapping software.\n\n%1$s
</string> </string>
@@ -2094,8 +2098,8 @@ limitations under the License.
translation_description="When sharing a track URL with friends, the body of the message. Note translation_description="When sharing a track URL with friends, the body of the message. Note
that \n is the newline character. that \n is the newline character.
%1$s: url. E.g., 'https://maps.google.com/maps'. %1$s url. E.g., 'https://maps.google.com/maps'.
%2$s: track description."> %2$s track description.">
I think you might be interested in this track:\n\n%1$s\n\n%2$s I think you might be interested in this track:\n\n%1$s\n\n%2$s
</string> </string>
<string name="share_track_share_url_title" <string name="share_track_share_url_title"
@@ -2222,7 +2226,7 @@ limitations under the License.
<string name="track_name_format" <string name="track_name_format"
translation_description="When creating a new track, the string format to name the track. translation_description="When creating a new track, the string format to name the track.
%1$d: track number. E.g., '1'."> %1$d track number. E.g., '1'.">
Track %1$d Track %1$d
</string> </string>
<string name="track_record_notification" <string name="track_record_notification"
@@ -2230,7 +2234,13 @@ limitations under the License.
informing the user that My Tracks is actively recording his track."> informing the user that My Tracks is actively recording his track.">
Recording your track&#8230; Recording your track&#8230;
</string> </string>
<string name="track_markers"
translation_description="Title indicating a particular track's markers.
%1$s track name. E.g., 'Grand Canyon trail'.">
%1$s Markers
</string>
<!-- Track Delete --> <!-- Track Delete -->
<string name="track_delete_all_confirm_message" <string name="track_delete_all_confirm_message"
translation_description="When deleting all the tracks, the confirmation message."> translation_description="When deleting all the tracks, the confirmation message.">
@@ -2431,140 +2441,140 @@ limitations under the License.
<string name="value_float_feet" <string name="value_float_feet"
translation_description="Display a float value in feet (ft). translation_description="Display a float value in feet (ft).
%1$.2f: a float number. E.g., '2.22'."> %1$.2f a float number. E.g., '2.22'.">
%1$.2f ft %1$.2f ft
</string> </string>
<string name="value_float_kilometer" <string name="value_float_kilometer"
translation_description="Display a float value in kilometers (km). translation_description="Display a float value in kilometers (km).
%1$.2f: a float number. E.g., '2.22'."> %1$.2f a float number. E.g., '2.22'.">
%1$.2f km %1$.2f km
</string> </string>
<string name="value_float_meter" <string name="value_float_meter"
translation_description="Display a float value in meters (m). translation_description="Display a float value in meters (m).
%1$.2f: a float number. E.g., '2.22'."> %1$.2f a float number. E.g., '2.22'.">
%1$.2f m %1$.2f m
</string> </string>
<string name="value_float_mile" <string name="value_float_mile"
translation_description="Display a float value in miles (mi). translation_description="Display a float value in miles (mi).
%1$.2f: a float number. E.g., '2.22'."> %1$.2f a float number. E.g., '2.22'.">
%1$.2f mi %1$.2f mi
</string> </string>
<string name="value_float_mile_poor_gps" <string name="value_float_mile_poor_gps"
translation_description="In a setting picker, the string format to display a float value in translation_description="In a setting picker, the string format to display a float value in
miles (mi), recommended when having poor GPS signal. miles (mi), recommended when having poor GPS signal.
%1$.1f: a float number. E.g., '2.2'."> %1$.1f a float number. E.g., '2.2'.">
%1$.1f mi (poor GPS) %1$.1f mi (poor GPS)
</string> </string>
<string name="value_integer_feet" <string name="value_integer_feet"
translation_description="In a setting picker, the string format to display an integer value in translation_description="In a setting picker, the string format to display an integer value in
feet (ft). feet (ft).
%1$d: an integer value. E.g., '2'."> %1$d an integer value. E.g., '2'.">
%1$d ft %1$d ft
</string> </string>
<string name="value_integer_feet_excellent_gps" <string name="value_integer_feet_excellent_gps"
translation_description="In a setting picker, the string format to display an integer value in translation_description="In a setting picker, the string format to display an integer value in
feet (ft), recommended when having excellent GPS signal. feet (ft), recommended when having excellent GPS signal.
%1$d: an integer value. E.g., '2'."> %1$d an integer value. E.g., '2'.">
%1$d ft (excellent GPS) %1$d ft (excellent GPS)
</string> </string>
<string name="value_integer_feet_recommended" <string name="value_integer_feet_recommended"
translation_description="In a setting picker, the string format to display an integer value in translation_description="In a setting picker, the string format to display an integer value in
feet (ft) and that the value is the recommended value. feet (ft) and that the value is the recommended value.
%1$d: an integer value. E.g., '2'."> %1$d an integer value. E.g., '2'.">
%1$d ft (recommended) %1$d ft (recommended)
</string> </string>
<string name="value_integer_kilometer" <string name="value_integer_kilometer"
translation_description="In a setting picker, the string format to display an integer value in translation_description="In a setting picker, the string format to display an integer value in
kilometers (km). kilometers (km).
%1$d: an integer value. E.g., '2'."> %1$d an integer value. E.g., '2'.">
%1$d km %1$d km
</string> </string>
<string name="value_integer_kilogram" <string name="value_integer_kilogram"
translation_description="Display an integer value in kilogram (kg). translation_description="Display an integer value in kilogram (kg).
%1$d: an integer value. E.g., '2'."> %1$d an integer value. E.g., '2'.">
%1$d kg %1$d kg
</string> </string>
<string name="value_integer_kilometer_hour" <string name="value_integer_kilometer_hour"
translation_description="Display an integer value in kilometers per hour (km/h). translation_description="Display an integer value in kilometers per hour (km/h).
%1$d: an integer value. E.g., '2'."> %1$d an integer value. E.g., '2'.">
%1$d km/h %1$d km/h
</string> </string>
<string name="value_integer_meter" <string name="value_integer_meter"
translation_description="In a setting picker, the string format to display an integer value in translation_description="In a setting picker, the string format to display an integer value in
meters (m). meters (m).
%1$d: an integer value. E.g., '2'."> %1$d an integer value. E.g., '2'.">
%1$d m %1$d m
</string> </string>
<string name="value_integer_meter_excellent_gps" <string name="value_integer_meter_excellent_gps"
translation_description="In a setting picker, the string format to display an integer value in translation_description="In a setting picker, the string format to display an integer value in
meters (m), recommended when having excellent GPS signal. meters (m), recommended when having excellent GPS signal.
%1$d: an integer value. E.g., '2'."> %1$d an integer value. E.g., '2'.">
%1$d m (excellent GPS) %1$d m (excellent GPS)
</string> </string>
<string name="value_integer_meter_poor_gps" <string name="value_integer_meter_poor_gps"
translation_description="In a setting picker, the string format to display an integer value in translation_description="In a setting picker, the string format to display an integer value in
meters (m), recommended when having poor GPS signal. meters (m), recommended when having poor GPS signal.
%1$d: an integer value. E.g., '2'."> %1$d an integer value. E.g., '2'.">
%1$d m (poor GPS) %1$d m (poor GPS)
</string> </string>
<string name="value_integer_meter_recommended" <string name="value_integer_meter_recommended"
translation_description="In a setting picker, the string format to display an integer value in translation_description="In a setting picker, the string format to display an integer value in
meters (m) and that the value is the recommended value. meters (m) and that the value is the recommended value.
%1$d: an integer value. E.g., '2'."> %1$d an integer value. E.g., '2'.">
%1$d m (recommended) %1$d m (recommended)
</string> </string>
<string name="value_integer_mile" <string name="value_integer_mile"
translation_description="In a setting picker, the string format to display an integer value in translation_description="In a setting picker, the string format to display an integer value in
miles (mi). miles (mi).
%1$d: an integer value. E.g., '2'."> %1$d an integer value. E.g., '2'.">
%1$d mi %1$d mi
</string> </string>
<string name="value_integer_mile_hour" <string name="value_integer_mile_hour"
translation_description="Display an integer value in miles per hour (mi/h). translation_description="Display an integer value in miles per hour (mi/h).
%1$d: an integer value. E.g., '2'."> %1$d an integer value. E.g., '2'.">
%1$d mi/h %1$d mi/h
</string> </string>
<string name="value_integer_minute" <string name="value_integer_minute"
translation_description="In a setting picker, the string format to display an integer value in translation_description="In a setting picker, the string format to display an integer value in
minutes (min). minutes (min).
%1$d: an integer value. E.g., '2'."> %1$d an integer value. E.g., '2'.">
%1$d min %1$d min
</string> </string>
<string name="value_integer_percent" <string name="value_integer_percent"
translation_description="To display a value in percent like 2 %. %% is the escape sequence for translation_description="To display a value in percent like 2 %. %% is the escape sequence for
the percent symbol. the percent symbol.
%1$d: an integer value. E.g., '2'."> %1$d an integer value. E.g., '2'.">
%1$d %% %1$d %%
</string> </string>
<string name="value_integer_pound" <string name="value_integer_pound"
translation_description="Display an integer value in pound (lb). translation_description="Display an integer value in pound (lb).
%1$d: an integer value. E.g., '2'."> %1$d an integer value. E.g., '2'.">
%1$d lb %1$d lb
</string> </string>
<string name="value_integer_second" <string name="value_integer_second"
translation_description="In a setting picker, the string format to display an integer value in translation_description="In a setting picker, the string format to display an integer value in
seconds (s). seconds (s).
%1$d: an integer value. E.g., '2'."> %1$d an integer value. E.g., '2'.">
%1$d s %1$d s
</string> </string>
<string name="value_never" <string name="value_never"
@@ -2762,9 +2772,9 @@ limitations under the License.
<string name="voice_template" <string name="voice_template"
translation_description="For the voice announcement, the template to make an announcement. translation_description="For the voice announcement, the template to make an announcement.
%1$s: distance string. E.g., '2.2 kilometers'. %1$s distance string. E.g., '2.2 kilometers'.
%2$s: time string. E.g., '20 minutes 1 second'. %2$s time string. E.g., '20 minutes 1 second'.
%3$s: speed/pace string. E.g., '2.2 miles per hour' for speed and %3$s speed/pace string. E.g., '2.2 miles per hour' for speed and
'30 minutes 1 second per kilometer' for pace."> '30 minutes 1 second per kilometer' for pace.">
My Tracks %1$s in %2$s at %3$s. My Tracks %1$s in %2$s at %3$s.
</string> </string>
@@ -52,7 +52,8 @@ import java.util.ArrayList;
public class MyTracksProvider extends ContentProvider { public class MyTracksProvider extends ContentProvider {
private static final String TAG = MyTracksProvider.class.getSimpleName(); private static final String TAG = MyTracksProvider.class.getSimpleName();
private static final int DATABASE_VERSION = 22; @VisibleForTesting
static final int DATABASE_VERSION = 22;
@VisibleForTesting @VisibleForTesting
static final String DATABASE_NAME = "mytracks.db"; static final String DATABASE_NAME = "mytracks.db";
@@ -34,6 +34,7 @@ import com.google.android.apps.mytracks.util.UnitConversions;
import com.google.android.maps.mytracks.R; import com.google.android.maps.mytracks.R;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import android.content.Context;
import android.location.Location; import android.location.Location;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
@@ -188,7 +189,7 @@ public class ChartFragment extends Fragment implements TrackDataListener {
public void onSampledInTrackPoint(Location location) { public void onSampledInTrackPoint(Location location) {
if (isResumed()) { if (isResumed()) {
double[] data = new double[ChartView.NUM_SERIES + 1]; double[] data = new double[ChartView.NUM_SERIES + 1];
fillDataPoint(location, data); fillDataPoint(getActivity(), location, data);
pendingPoints.add(data); pendingPoints.add(data);
} }
} }
@@ -196,14 +197,14 @@ public class ChartFragment extends Fragment implements TrackDataListener {
@Override @Override
public void onSampledOutTrackPoint(Location location) { public void onSampledOutTrackPoint(Location location) {
if (isResumed()) { if (isResumed()) {
fillDataPoint(location, null); fillDataPoint(getActivity(), location, null);
} }
} }
@Override @Override
public void onSegmentSplit(Location location) { public void onSegmentSplit(Location location) {
if (isResumed()) { if (isResumed()) {
fillDataPoint(location, null); fillDataPoint(getActivity(), location, null);
} }
} }
@@ -437,11 +438,12 @@ public class ChartFragment extends Fragment implements TrackDataListener {
* data[5] = cadence <br> * data[5] = cadence <br>
* data[6] = power <br> * data[6] = power <br>
* *
* @param context the context
* @param location the location * @param location the location
* @param data the data point to fill in, can be null * @param data the data point to fill in, can be null
*/ */
@VisibleForTesting @VisibleForTesting
void fillDataPoint(Location location, double data[]) { void fillDataPoint(Context context, Location location, double data[]) {
double timeOrDistance = Double.NaN; double timeOrDistance = Double.NaN;
double elevation = Double.NaN; double elevation = Double.NaN;
double speed = Double.NaN; double speed = Double.NaN;
@@ -451,8 +453,9 @@ public class ChartFragment extends Fragment implements TrackDataListener {
double power = Double.NaN; double power = Double.NaN;
if (tripStatisticsUpdater != null) { if (tripStatisticsUpdater != null) {
tripStatisticsUpdater.addLocation(location, recordingDistanceInterval, PreferencesUtils int weight = PreferencesUtils.getInt(
.getInt(getActivity(), R.string.stats_weight_key, PreferencesUtils.STATS_WEIGHT_DEFAULT)); context, R.string.stats_weight_key, PreferencesUtils.STATS_WEIGHT_DEFAULT);
tripStatisticsUpdater.addLocation(location, recordingDistanceInterval, weight);
TripStatistics tripStatistics = tripStatisticsUpdater.getTripStatistics(); TripStatistics tripStatistics = tripStatisticsUpdater.getTripStatistics();
if (chartByDistance) { if (chartByDistance) {
double distance = tripStatistics.getTotalDistance() * UnitConversions.M_TO_KM; double distance = tripStatistics.getTotalDistance() * UnitConversions.M_TO_KM;
@@ -18,25 +18,25 @@ import java.util.Locale;
public enum TrackFileFormat implements Parcelable { public enum TrackFileFormat implements Parcelable {
KML { KML {
@Override @Override
public TrackWriter newTrackWriter(Context context, boolean inZip) { public TrackWriter newTrackWriter(Context context, boolean playTrack) {
return new KmlTrackWriter(context, inZip); return new KmlTrackWriter(context, playTrack);
} }
}, },
GPX { GPX {
@Override @Override
public TrackWriter newTrackWriter(Context context, boolean inZip) { public TrackWriter newTrackWriter(Context context, boolean playTrack) {
return new GpxTrackWriter(context); return new GpxTrackWriter(context);
} }
}, },
CSV { CSV {
@Override @Override
public TrackWriter newTrackWriter(Context context, boolean inZip) { public TrackWriter newTrackWriter(Context context, boolean playTrack) {
return new CsvTrackWriter(context); return new CsvTrackWriter(context);
} }
}, },
TCX { TCX {
@Override @Override
public TrackWriter newTrackWriter(Context context, boolean inZip) { public TrackWriter newTrackWriter(Context context, boolean playTrack) {
return new TcxTrackWriter(context); return new TcxTrackWriter(context);
} }
}; };
@@ -66,7 +66,7 @@ public enum TrackFileFormat implements Parcelable {
/** /**
* Creates a new track writer for the format. * Creates a new track writer for the format.
*/ */
public abstract TrackWriter newTrackWriter(Context context, boolean inZip); public abstract TrackWriter newTrackWriter(Context context, boolean playTrack);
/** /**
* Returns the mime type for each format. * Returns the mime type for each format.
@@ -46,7 +46,7 @@ import java.text.NumberFormat;
* "Segment","Point","Latitude (deg)","Longitude (deg)","Altitude (m)","Bearing * "Segment","Point","Latitude (deg)","Longitude (deg)","Altitude (m)","Bearing
* (deg)","Accuracy (m)","Speed (m/s)","Time","Power (W)","Cadence (rpm)","Heart * (deg)","Accuracy (m)","Speed (m/s)","Time","Power (W)","Cadence (rpm)","Heart
* rate (bpm)","Battery level (%)"<br> * rate (bpm)","Battery level (%)"<br>
* *
* @author Rodrigo Damazio * @author Rodrigo Damazio
*/ */
public class CsvTrackWriter implements TrackWriter { public class CsvTrackWriter implements TrackWriter {
@@ -85,12 +85,13 @@ public class CsvTrackWriter implements TrackWriter {
printWriter = null; printWriter = null;
} }
} }
@Override @Override
public void writeHeader(Track track) { public void writeHeader(Track[] tracks) {
writeCommaSeparatedLine(context.getString(R.string.generic_name), writeCommaSeparatedLine(context.getString(R.string.generic_name),
context.getString(R.string.track_edit_activity_type_hint), context.getString(R.string.track_edit_activity_type_hint),
context.getString(R.string.generic_description)); context.getString(R.string.generic_description));
Track track = tracks[0];
writeCommaSeparatedLine(track.getName(), track.getCategory(), track.getDescription()); writeCommaSeparatedLine(track.getName(), track.getCategory(), track.getDescription());
writeCommaSeparatedLine(); writeCommaSeparatedLine();
} }
@@ -101,7 +102,7 @@ public class CsvTrackWriter implements TrackWriter {
} }
@Override @Override
public void writeBeginWaypoints() { public void writeBeginWaypoints(Track track) {
writeCommaSeparatedLine(context.getString(R.string.generic_name), writeCommaSeparatedLine(context.getString(R.string.generic_name),
context.getString(R.string.marker_edit_marker_type_hint), context.getString(R.string.marker_edit_marker_type_hint),
context.getString(R.string.generic_description), context.getString(R.string.generic_description),
@@ -122,20 +123,24 @@ public class CsvTrackWriter implements TrackWriter {
@Override @Override
public void writeWaypoint(Waypoint waypoint) { public void writeWaypoint(Waypoint waypoint) {
Location location = waypoint.getLocation(); Location location = waypoint.getLocation();
writeCommaSeparatedLine(waypoint.getName(), writeCommaSeparatedLine(waypoint.getName(), waypoint.getCategory(), waypoint.getDescription(),
waypoint.getCategory(), Double.toString(location.getLatitude()), Double.toString(location.getLongitude()),
waypoint.getDescription(), getAltitude(location), getBearing(location), getAccuracy(location), getSpeed(location),
Double.toString(location.getLatitude()),
Double.toString(location.getLongitude()),
getAltitude(location),
getBearing(location),
getAccuracy(location),
getSpeed(location),
StringUtils.formatDateTimeIso8601(location.getTime())); StringUtils.formatDateTimeIso8601(location.getTime()));
} }
@Override @Override
public void writeBeginTrack(Track track, Location firstPoint) { public void writeBeginTracks() {
// Do nothing
}
@Override
public void writeEndTracks() {
// Do nothing
}
@Override
public void writeBeginTrack(Track track, Location startLocation) {
writeCommaSeparatedLine(context.getString(R.string.description_track_segment), writeCommaSeparatedLine(context.getString(R.string.description_track_segment),
context.getString(R.string.description_track_point), context.getString(R.string.description_track_point),
context.getString(R.string.description_location_latitude), context.getString(R.string.description_location_latitude),
@@ -151,7 +156,7 @@ public class CsvTrackWriter implements TrackWriter {
} }
@Override @Override
public void writeEndTrack(Track track, Location lastPoint) { public void writeEndTrack(Track track, Location endLocation) {
// Do nothing // Do nothing
} }
@@ -196,39 +201,31 @@ public class CsvTrackWriter implements TrackWriter {
} }
} }
pointIndex++; pointIndex++;
writeCommaSeparatedLine(Integer.toString(segmentIndex), writeCommaSeparatedLine(Integer.toString(segmentIndex), Integer.toString(pointIndex),
Integer.toString(pointIndex), Double.toString(location.getLatitude()), Double.toString(location.getLongitude()),
Double.toString(location.getLatitude()), getAltitude(location), getBearing(location), getAccuracy(location), getSpeed(location),
Double.toString(location.getLongitude()), StringUtils.formatDateTimeIso8601(location.getTime()), power, cadence, heartRate);
getAltitude(location),
getBearing(location),
getAccuracy(location),
getSpeed(location),
StringUtils.formatDateTimeIso8601(location.getTime()),
power,
cadence,
heartRate);
} }
private String getAltitude(Location location) { private String getAltitude(Location location) {
return location.hasAltitude() ? Double.toString(location.getAltitude()) : null; return location.hasAltitude() ? Double.toString(location.getAltitude()) : null;
} }
private String getBearing(Location location) { private String getBearing(Location location) {
return location.hasBearing() ? Double.toString(location.getBearing()) : null; return location.hasBearing() ? Double.toString(location.getBearing()) : null;
} }
private String getAccuracy(Location location) { private String getAccuracy(Location location) {
return location.hasAccuracy() ? SHORT_FORMAT.format(location.getAccuracy()) : null; return location.hasAccuracy() ? SHORT_FORMAT.format(location.getAccuracy()) : null;
} }
private String getSpeed(Location location) { private String getSpeed(Location location) {
return location.hasSpeed() ? SHORT_FORMAT.format(location.getSpeed()) : null; return location.hasSpeed() ? SHORT_FORMAT.format(location.getSpeed()) : null;
} }
/** /**
* Writes a single line of a CSV file. * Writes a single line of a CSV file.
* *
* @param values the values to be written as CSV * @param values the values to be written as CSV
*/ */
private void writeCommaSeparatedLine(String... values) { private void writeCommaSeparatedLine(String... values) {
@@ -22,11 +22,8 @@ import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils.LocationIterator; import com.google.android.apps.mytracks.content.MyTracksProviderUtils.LocationIterator;
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.file.TrackFileFormat;
import com.google.android.apps.mytracks.util.LocationUtils; import com.google.android.apps.mytracks.util.LocationUtils;
import com.google.common.annotations.VisibleForTesting;
import android.content.Context;
import android.database.Cursor; import android.database.Cursor;
import android.location.Location; import android.location.Location;
import android.util.Log; import android.util.Log;
@@ -51,20 +48,11 @@ public class FileTrackExporter implements TrackExporter {
/** /**
* Constructor. * Constructor.
* *
* @param context the context
* @param myTracksProviderUtils the my tracks provider utils * @param myTracksProviderUtils the my tracks provider utils
* @param tracks the tracks * @param tracks the tracks
* @param trackFileFormat the track file format * @param trackWriter the track writer
* @param trackExporterListener the track export listener * @param trackExporterListener the track export listener
*/ */
public FileTrackExporter(MyTracksProviderUtils myTracksProviderUtils,
Track[] tracks, TrackFileFormat trackFileFormat, Context context, boolean inZip,
TrackExporterListener trackExporterListener) {
this(myTracksProviderUtils, tracks, trackFileFormat.newTrackWriter(context, inZip),
trackExporterListener);
}
@VisibleForTesting
public FileTrackExporter(MyTracksProviderUtils myTracksProviderUtils, Track[] tracks, public FileTrackExporter(MyTracksProviderUtils myTracksProviderUtils, Track[] tracks,
TrackWriter trackWriter, TrackExporterListener trackExporterListener) { TrackWriter trackWriter, TrackExporterListener trackExporterListener) {
this.myTracksProviderUtils = myTracksProviderUtils; this.myTracksProviderUtils = myTracksProviderUtils;
@@ -77,13 +65,17 @@ public class FileTrackExporter implements TrackExporter {
public boolean writeTrack(OutputStream outputStream) { public boolean writeTrack(OutputStream outputStream) {
try { try {
trackWriter.prepare(outputStream); trackWriter.prepare(outputStream);
trackWriter.writeHeader(tracks[0]); trackWriter.writeHeader(tracks);
long startTime = tracks[0].getTripStatistics().getStartTime();
for (int i = 0; i < tracks.length; i++) { for (int i = 0; i < tracks.length; i++) {
writeWaypoints(tracks[i]); writeWaypoints(tracks[i]);
}
trackWriter.writeBeginTracks();
long startTime = tracks[0].getTripStatistics().getStartTime();
for (int i = 0; i < tracks.length; i++) {
long offset = tracks[i].getTripStatistics().getStartTime() - startTime; long offset = tracks[i].getTripStatistics().getStartTime() - startTime;
writeLocations(tracks[i], offset); writeLocations(tracks[i], offset);
} }
trackWriter.writeEndTracks();
trackWriter.writeFooter(); trackWriter.writeFooter();
trackWriter.close(); trackWriter.close();
return true; return true;
@@ -117,7 +109,7 @@ public class FileTrackExporter implements TrackExporter {
throw new InterruptedException(); throw new InterruptedException();
} }
if (!hasWaypoints) { if (!hasWaypoints) {
trackWriter.writeBeginWaypoints(); trackWriter.writeBeginWaypoints(track);
hasWaypoints = true; hasWaypoints = true;
} }
Waypoint waypoint = myTracksProviderUtils.createWaypoint(cursor); Waypoint waypoint = myTracksProviderUtils.createWaypoint(cursor);
@@ -78,7 +78,7 @@ public class GpxTrackWriter implements TrackWriter {
} }
@Override @Override
public void writeHeader(Track track) { public void writeHeader(Track[] tracks) {
if (printWriter != null) { if (printWriter != null) {
printWriter.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"); printWriter.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
printWriter.println("<gpx"); printWriter.println("<gpx");
@@ -94,6 +94,7 @@ public class GpxTrackWriter implements TrackWriter {
+ " http://www.topografix.com/GPX/Private/TopoGrafix/0/1" + " http://www.topografix.com/GPX/Private/TopoGrafix/0/1"
+ " http://www.topografix.com/GPX/Private/TopoGrafix/0/1/topografix.xsd\">"); + " http://www.topografix.com/GPX/Private/TopoGrafix/0/1/topografix.xsd\">");
printWriter.println("<metadata>"); printWriter.println("<metadata>");
Track track = tracks[0];
printWriter.println("<name>" + StringUtils.formatCData(track.getName()) + "</name>"); printWriter.println("<name>" + StringUtils.formatCData(track.getName()) + "</name>");
printWriter.println("<desc>" + StringUtils.formatCData(track.getDescription()) + "</desc>"); printWriter.println("<desc>" + StringUtils.formatCData(track.getDescription()) + "</desc>");
printWriter.println("</metadata>"); printWriter.println("</metadata>");
@@ -108,48 +109,7 @@ public class GpxTrackWriter implements TrackWriter {
} }
@Override @Override
public void writeBeginTrack(Track track, Location firstLocation) { public void writeBeginWaypoints(Track track) {
if (printWriter != null) {
printWriter.println("<trk>");
printWriter.println("<name>" + StringUtils.formatCData(track.getName()) + "</name>");
printWriter.println("<desc>" + StringUtils.formatCData(track.getDescription()) + "</desc>");
printWriter.println("<type>" + StringUtils.formatCData(track.getCategory()) + "</type>");
printWriter.println("<extensions><topografix:color>c0c0c0</topografix:color></extensions>");
}
}
@Override
public void writeEndTrack(Track track, Location lastLocation) {
if (printWriter != null) {
printWriter.println("</trk>");
}
}
@Override
public void writeOpenSegment() {
printWriter.println("<trkseg>");
}
@Override
public void writeCloseSegment() {
printWriter.println("</trkseg>");
}
@Override
public void writeLocation(Location location) {
if (printWriter != null) {
printWriter.println("<trkpt " + formatLocation(location) + ">");
if (location.hasAltitude()) {
printWriter.println("<ele>" + ELEVATION_FORMAT.format(location.getAltitude()) + "</ele>");
}
printWriter.println(
"<time>" + StringUtils.formatDateTimeIso8601(location.getTime()) + "</time>");
printWriter.println("</trkpt>");
}
}
@Override
public void writeBeginWaypoints() {
// Do nothing // Do nothing
} }
@@ -179,6 +139,57 @@ public class GpxTrackWriter implements TrackWriter {
} }
} }
@Override
public void writeBeginTracks() {
// Do nothing
}
@Override
public void writeEndTracks() {
// Do nothing
}
@Override
public void writeBeginTrack(Track track, Location startLocation) {
if (printWriter != null) {
printWriter.println("<trk>");
printWriter.println("<name>" + StringUtils.formatCData(track.getName()) + "</name>");
printWriter.println("<desc>" + StringUtils.formatCData(track.getDescription()) + "</desc>");
printWriter.println("<type>" + StringUtils.formatCData(track.getCategory()) + "</type>");
printWriter.println("<extensions><topografix:color>c0c0c0</topografix:color></extensions>");
}
}
@Override
public void writeEndTrack(Track track, Location endLocation) {
if (printWriter != null) {
printWriter.println("</trk>");
}
}
@Override
public void writeOpenSegment() {
printWriter.println("<trkseg>");
}
@Override
public void writeCloseSegment() {
printWriter.println("</trkseg>");
}
@Override
public void writeLocation(Location location) {
if (printWriter != null) {
printWriter.println("<trkpt " + formatLocation(location) + ">");
if (location.hasAltitude()) {
printWriter.println("<ele>" + ELEVATION_FORMAT.format(location.getAltitude()) + "</ele>");
}
printWriter.println(
"<time>" + StringUtils.formatDateTimeIso8601(location.getTime()) + "</time>");
printWriter.println("</trkpt>");
}
}
/** /**
* Formats a location with latitude and longitude coordinates. * Formats a location with latitude and longitude coordinates.
* *
@@ -70,7 +70,7 @@ public class KmlTrackWriter implements TrackWriter {
TRACK_ICON = "http://earth.google.com/images/kml-icons/track-directional/track-0.png"; TRACK_ICON = "http://earth.google.com/images/kml-icons/track-directional/track-0.png";
private final Context context; private final Context context;
private final boolean inKmz; private final boolean playTrack;
private final DescriptionGenerator descriptionGenerator; private final DescriptionGenerator descriptionGenerator;
private final MyTracksProviderUtils myTracksProviderUtils; private final MyTracksProviderUtils myTracksProviderUtils;
@@ -82,14 +82,14 @@ public class KmlTrackWriter implements TrackWriter {
private boolean hasCadence; private boolean hasCadence;
private boolean hasHeartRate; private boolean hasHeartRate;
public KmlTrackWriter(Context context, boolean inKmz) { public KmlTrackWriter(Context context, boolean playTrack) {
this(context, inKmz, new DescriptionGeneratorImpl(context)); this(context, playTrack, new DescriptionGeneratorImpl(context));
} }
@VisibleForTesting @VisibleForTesting
KmlTrackWriter(Context context, boolean inKmz, DescriptionGenerator descriptionGenerator) { KmlTrackWriter(Context context, boolean playTrack, DescriptionGenerator descriptionGenerator) {
this.context = context; this.context = context;
this.inKmz = inKmz; this.playTrack = playTrack;
this.descriptionGenerator = descriptionGenerator; this.descriptionGenerator = descriptionGenerator;
this.myTracksProviderUtils = MyTracksProviderUtils.Factory.get(context); this.myTracksProviderUtils = MyTracksProviderUtils.Factory.get(context);
} }
@@ -113,7 +113,7 @@ public class KmlTrackWriter implements TrackWriter {
} }
@Override @Override
public void writeHeader(Track track) { public void writeHeader(Track[] tracks) {
if (printWriter != null) { if (printWriter != null) {
printWriter.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"); printWriter.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
printWriter.println("<kml xmlns=\"http://www.opengis.net/kml/2.2\""); printWriter.println("<kml xmlns=\"http://www.opengis.net/kml/2.2\"");
@@ -122,6 +122,7 @@ public class KmlTrackWriter implements TrackWriter {
printWriter.println("<Document>"); printWriter.println("<Document>");
printWriter.println("<open>1</open>"); printWriter.println("<open>1</open>");
printWriter.println("<visibility>1</visibility>"); printWriter.println("<visibility>1</visibility>");
Track track = tracks[0];
printWriter.println("<name>" + StringUtils.formatCData(track.getName()) + "</name>"); printWriter.println("<name>" + StringUtils.formatCData(track.getName()) + "</name>");
printWriter.println("<atom:author><atom:name>" printWriter.println("<atom:author><atom:name>"
+ StringUtils.formatCData(context.getString(R.string.send_google_by_my_tracks, "", "")) + StringUtils.formatCData(context.getString(R.string.send_google_by_my_tracks, "", ""))
@@ -148,10 +149,11 @@ public class KmlTrackWriter implements TrackWriter {
} }
@Override @Override
public void writeBeginWaypoints() { public void writeBeginWaypoints(Track track) {
if (printWriter != null) { if (printWriter != null) {
printWriter.println("<Folder><name>" printWriter.println("<Folder><name>"
+ StringUtils.formatCData(context.getString(R.string.menu_markers)) + "</name>"); + StringUtils.formatCData(context.getString(R.string.track_markers, track.getName()))
+ "</name>");
printWriter.println("<open>1</open>"); printWriter.println("<open>1</open>");
} }
} }
@@ -181,11 +183,31 @@ public class KmlTrackWriter implements TrackWriter {
} }
@Override @Override
public void writeBeginTrack(Track track, Location firstLocation) { public void writeBeginTracks() {
if (printWriter != null && playTrack) {
printWriter.println("<Folder id=\"" + GoogleEarthUtils.TOUR_FEATURE_ID_VALUE + "\">");
printWriter.println("<name>" + context.getString(R.string.generic_tracks) + "</name>");
printWriter.println("<open>1</open>");
}
}
@Override
public void writeEndTracks() {
if (printWriter != null && playTrack) {
printWriter.println("</Folder>");
}
}
@Override
public void writeBeginTrack(Track track, Location startLocation) {
if (printWriter != null) { if (printWriter != null) {
String name = context.getString(R.string.marker_label_start, track.getName()); String name = context.getString(R.string.marker_label_start, track.getName());
writePlacemark(name, "", "", START_STYLE, firstLocation); writePlacemark(name, "", "", START_STYLE, startLocation);
printWriter.println("<Placemark id=\"" + GoogleEarthUtils.TOUR_FEATURE_ID_VALUE + "\">"); if (playTrack) {
printWriter.println("<Placemark>");
} else {
printWriter.println("<Placemark id=\"" + GoogleEarthUtils.TOUR_FEATURE_ID_VALUE + "\">");
}
printWriter.println("<name>" + StringUtils.formatCData(track.getName()) + "</name>"); printWriter.println("<name>" + StringUtils.formatCData(track.getName()) + "</name>");
printWriter.println( printWriter.println(
"<description>" + StringUtils.formatCData(track.getDescription()) + "</description>"); "<description>" + StringUtils.formatCData(track.getDescription()) + "</description>");
@@ -198,13 +220,13 @@ public class KmlTrackWriter implements TrackWriter {
} }
@Override @Override
public void writeEndTrack(Track track, Location lastLocation) { public void writeEndTrack(Track track, Location endLocation) {
if (printWriter != null) { if (printWriter != null) {
printWriter.println("</gx:MultiTrack>"); printWriter.println("</gx:MultiTrack>");
printWriter.println("</Placemark>"); printWriter.println("</Placemark>");
String name = context.getString(R.string.marker_label_end, track.getName()); String name = context.getString(R.string.marker_label_end, track.getName());
String description = descriptionGenerator.generateTrackDescription(track, null, null, false); String description = descriptionGenerator.generateTrackDescription(track, null, null, false);
writePlacemark(name, "", description, END_STYLE, lastLocation); writePlacemark(name, "", description, END_STYLE, endLocation);
} }
} }
@@ -353,12 +375,12 @@ public class KmlTrackWriter implements TrackWriter {
+ StringUtils.formatDateTimeIso8601(location.getTime()) + "</when></TimeStamp>"); + StringUtils.formatDateTimeIso8601(location.getTime()) + "</when></TimeStamp>");
printWriter.println("<styleUrl>#" + styleName + "</styleUrl>"); printWriter.println("<styleUrl>#" + styleName + "</styleUrl>");
writeCategory(category); writeCategory(category);
if (inKmz) { if (playTrack) {
printWriter.println("<Icon><href>" + Uri.decode(photoUrl) + "</href></Icon>");
} else {
Uri uri = Uri.parse(photoUrl); Uri uri = Uri.parse(photoUrl);
printWriter.println("<Icon><href>" + KmzTrackExporter.KMZ_IMAGES_DIR + File.separatorChar printWriter.println("<Icon><href>" + KmzTrackExporter.KMZ_IMAGES_DIR + File.separatorChar
+ uri.getLastPathSegment() + "</href></Icon>"); + uri.getLastPathSegment() + "</href></Icon>");
} else {
printWriter.println("<Icon><href>" + Uri.decode(photoUrl) + "</href></Icon>");
} }
printWriter.print("<ViewVolume>"); printWriter.print("<ViewVolume>");
@@ -184,7 +184,7 @@ public class SaveAsyncTask extends AsyncTask<Void, Integer, Boolean> {
return false; return false;
} }
Track track = tracks[0]; Track track = tracks[0];
boolean useKmz = !playTrack && trackFileFormat == TrackFileFormat.KML; boolean useKmz = trackFileFormat == TrackFileFormat.KML && !playTrack;
String extension = useKmz ? KmzTrackExporter.KMZ_EXTENSION : trackFileFormat.getExtension(); String extension = useKmz ? KmzTrackExporter.KMZ_EXTENSION : trackFileFormat.getExtension();
// Make sure the file doesn't exist yet (possibly by changing the filename) // Make sure the file doesn't exist yet (possibly by changing the filename)
@@ -195,7 +195,7 @@ public class SaveAsyncTask extends AsyncTask<Void, Integer, Boolean> {
} }
FileTrackExporter fileTrackExporter = new FileTrackExporter(myTracksProviderUtils, tracks, FileTrackExporter fileTrackExporter = new FileTrackExporter(myTracksProviderUtils, tracks,
trackFileFormat, context, useKmz, new TrackExporterListener() { trackFileFormat.newTrackWriter(context, playTrack), new TrackExporterListener() {
@Override @Override
public void onProgressUpdate(int number, int max) { public void onProgressUpdate(int number, int max) {
@@ -111,7 +111,7 @@ public class TcxTrackWriter implements TrackWriter {
} }
@Override @Override
public void writeHeader(Track track) { public void writeHeader(Track[] tracks) {
if (printWriter != null) { if (printWriter != null) {
printWriter.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"); printWriter.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
printWriter.println("<TrainingCenterDatabase" printWriter.println("<TrainingCenterDatabase"
@@ -142,7 +142,32 @@ public class TcxTrackWriter implements TrackWriter {
} }
@Override @Override
public void writeBeginTrack(Track track, Location firstPoint) { public void writeBeginWaypoints(Track track) {
// Do nothing
}
@Override
public void writeEndWaypoints() {
// Do nothing
}
@Override
public void writeWaypoint(Waypoint waypoint) {
// Do nothing
}
@Override
public void writeBeginTracks() {
// Do nothing
}
@Override
public void writeEndTracks() {
// Do nothing
}
@Override
public void writeBeginTrack(Track track, Location startLocation) {
sportType = getSportType(track.getCategory()); sportType = getSportType(track.getCategory());
if (printWriter != null) { if (printWriter != null) {
String startTime = StringUtils.formatDateTimeIso8601( String startTime = StringUtils.formatDateTimeIso8601(
@@ -164,7 +189,7 @@ public class TcxTrackWriter implements TrackWriter {
} }
@Override @Override
public void writeEndTrack(Track track, Location lastPoint) { public void writeEndTrack(Track track, Location endLocation) {
if (printWriter != null) { if (printWriter != null) {
printWriter.println("</Lap>"); printWriter.println("</Lap>");
printWriter.println("<Notes>" + StringUtils.formatCData(track.getDescription()) + "</Notes>"); printWriter.println("<Notes>" + StringUtils.formatCData(track.getDescription()) + "</Notes>");
@@ -261,21 +286,6 @@ public class TcxTrackWriter implements TrackWriter {
} }
} }
@Override
public void writeBeginWaypoints() {
// Do nothing.
}
@Override
public void writeEndWaypoints() {
// Do nothing.
}
@Override
public void writeWaypoint(Waypoint waypoint) {
// Do nothing.
}
/** /**
* Writes the TCX Version. * Writes the TCX Version.
*/ */
@@ -23,58 +23,57 @@ import android.location.Location;
import java.io.OutputStream; import java.io.OutputStream;
/** /**
* Interface for writing tracks to a file. * Interface for writing tracks to a file. The expected sequence of calls is:
* *
* The expected sequence of calls is: * <pre>
* <ul> * {@link #prepare(OutputStream)}
* <li>{@link #prepare}</li> * {@link #writeHeader(Track[])}
* <li>{@link #writeHeader}</li> * For each track:
* <li>For each track:</li> * {@link #writeBeginWaypoints(Track)}
* <ul> * For each waypoint:
* <li>{@link #writeBeginWaypoints} * {@link #writeWaypoint(Waypoint)}
* <li>For each waypoint: {@link #writeWaypoint} * {@link #writeEndWaypoints()}
* <li>{@link #writeEndWaypoints} * {@link #writeBeginTracks()}
* <li>{@link #writeBeginTrack} * For each track:
* <li>For each segment: * {@link #writeBeginTrack(Track, Location)}
* <ul> * For each segment:
* <li>{@link #writeOpenSegment}</li> * {@link #writeOpenSegment()}
* <li>For each location in the segment: {@link #writeLocation}</li> * For each location in the segment:
* <li>{@link #writeCloseSegment}</li> * {@link #writeLocation(Location)}
* </ul> * {@link #writeCloseSegment()}
* </li> * {@link #writeEndTrack(Track, Location)}
* <li>{@link #writeEndTrack}</li> * {@link #writeEndTracks()}
* </ul> * {@link #writeFooter()}
* <li>{@link #writeFooter}</li> * {@link #close()}
* <li>{@link #close}</li> * </pre>
* </ul> *
*
* @author Rodrigo Damazio * @author Rodrigo Damazio
*/ */
public interface TrackWriter { public interface TrackWriter {
/** /**
* Gets the file extension (i.e. gpx, kml, ...) * Gets the file extension (e.g, gpx, kml, ...).
*/ */
public String getExtension(); public String getExtension();
/** /**
* Sets up the file handler. * Prepares the output stream.
* *
* @param outputStream the output stream for the file handler * @param outputStream the output stream
*/ */
public void prepare(OutputStream outputStream); public void prepare(OutputStream outputStream);
/** /**
* Closes the underlying file handler. * Closes the output stream.
*/ */
public void close(); public void close();
/** /**
* Writes the header for a file * Writes the header
* *
* @param track the track * @param tracks the tracks
*/ */
public void writeHeader(Track track); public void writeHeader(Track[] tracks);
/** /**
* Writes the footer. * Writes the footer.
@@ -83,50 +82,62 @@ public interface TrackWriter {
/** /**
* Writes the beginning of the waypoints. * Writes the beginning of the waypoints.
*
* @param track the track
*/ */
public void writeBeginWaypoints(); public void writeBeginWaypoints(Track track);
/** /**
* Writes the end of the waypoints. * Writes the end of the waypoints.
*/ */
public void writeEndWaypoints(); public void writeEndWaypoints();
/** /**
* Writes a waypoint. * Writes a waypoint.
* *
* @param waypoint the waypoint * @param waypoint the waypoint
*/ */
public void writeWaypoint(Waypoint waypoint); public void writeWaypoint(Waypoint waypoint);
/** /**
* Writes the beginning of the track. * Writes the beginning of the tracks.
*
* @param track the track
* @param firstLocation the first location
*/ */
public void writeBeginTrack(Track track, Location firstLocation); public void writeBeginTracks();
/** /**
* Writes the end of the track. * Writes the end of the tracks,
*
* @param track the track
* @param lastLocation the last location
*/ */
public void writeEndTrack(Track track, Location lastLocation); public void writeEndTracks();
/** /**
* Writes the statements necessary to open a new segment. * Writes the beginning of a track.
*
* @param track the track
* @param startLocation the start location
*/
public void writeBeginTrack(Track track, Location startLocation);
/**
* Writes the end of a track.
*
* @param track the track
* @param endLocation the end location
*/
public void writeEndTrack(Track track, Location endLocation);
/**
* Writes open segment.
*/ */
public void writeOpenSegment(); public void writeOpenSegment();
/** /**
* Writes the statements necessary to close a segment. * Writes close segment.
*/ */
public void writeCloseSegment(); public void writeCloseSegment();
/** /**
* Writes a location. * Writes a location.
* *
* @param location the location * @param location the location
*/ */
public void writeLocation(Location location); public void writeLocation(Location location);
@@ -441,8 +441,8 @@ public class SyncUtils {
java.io.File file = new java.io.File(directory, java.io.File file = new java.io.File(directory,
FileUtils.buildUniqueFileName(directory, track.getName(), trackFileFormat.getExtension())); FileUtils.buildUniqueFileName(directory, track.getName(), trackFileFormat.getExtension()));
FileTrackExporter fileTrackExporter = new FileTrackExporter( FileTrackExporter fileTrackExporter = new FileTrackExporter(myTracksProviderUtils,
myTracksProviderUtils, new Track[] { track }, trackFileFormat, context, false, null); new Track[] { track }, trackFileFormat.newTrackWriter(context, false), null);
FileOutputStream fileOutputStream = null; FileOutputStream fileOutputStream = null;
try { try {
@@ -13,6 +13,7 @@
* License for the specific language governing permissions and limitations under * License for the specific language governing permissions and limitations under
* the License. * the License.
*/ */
package com.google.android.apps.mytracks.content; package com.google.android.apps.mytracks.content;
import com.google.android.apps.mytracks.content.MyTracksProvider.DatabaseHelper; import com.google.android.apps.mytracks.content.MyTracksProvider.DatabaseHelper;
@@ -22,150 +23,202 @@ import android.net.Uri;
import android.test.AndroidTestCase; import android.test.AndroidTestCase;
/** /**
* A unit test for {@link MyTracksProvider}. * Tests {@link MyTracksProvider}.
* *
* @author Youtao Liu * @author Youtao Liu
*/ */
public class MyTracksProviderTest extends AndroidTestCase { public class MyTracksProviderTest extends AndroidTestCase {
private static final String DATABASE_NAME = "mytrackstest.db";
private SQLiteDatabase db; private SQLiteDatabase db;
private MyTracksProvider myTracksProvider; private MyTracksProvider myTracksProvider;
private String DATABASE_NAME = "mytrackstest.db";
@Override @Override
protected void setUp() throws Exception { protected void setUp() throws Exception {
super.setUp();
getContext().deleteDatabase(DATABASE_NAME); getContext().deleteDatabase(DATABASE_NAME);
db = (new DatabaseHelper(getContext(), DATABASE_NAME)).getWritableDatabase(); db = (new DatabaseHelper(getContext(), DATABASE_NAME)).getWritableDatabase();
myTracksProvider = new MyTracksProvider(); myTracksProvider = new MyTracksProvider();
super.setUp();
} }
/** /**
* Tests the method {@link MyTracksProvider.DatabaseHelper#onCreate()}. * Tests {@link MyTracksProvider.DatabaseHelper#onCreate(SQLiteDatabase)}.
*/ */
public void testDatabaseHelper_OnCreate() { public void testDatabaseHelper_OnCreate() {
assertTrue(checkTable(TrackPointsColumns.TABLE_NAME)); assertTrue(hasTable(TracksColumns.TABLE_NAME));
assertTrue(checkTable(TracksColumns.TABLE_NAME)); assertTrue(hasTable(TrackPointsColumns.TABLE_NAME));
assertTrue(checkTable(WaypointsColumns.TABLE_NAME)); assertTrue(hasTable(WaypointsColumns.TABLE_NAME));
} }
/** /**
* Tests the method * Tests {@link MyTracksProvider.DatabaseHelper#onUpgrade(SQLiteDatabase, int,
* {@link MyTracksProvider.DatabaseHelper#onUpgrade(SQLiteDatabase, int, int)} * int)} when version is less than 17.
* when version is less than 17.
*/ */
public void testDatabaseHelper_onUpgrade_Version16() { public void testDatabaseHelper_onUpgrade_Version16() {
DatabaseHelper databaseHelper = new DatabaseHelper(getContext());
dropTable(TrackPointsColumns.TABLE_NAME);
dropTable(TracksColumns.TABLE_NAME); dropTable(TracksColumns.TABLE_NAME);
dropTable(TrackPointsColumns.TABLE_NAME);
dropTable(WaypointsColumns.TABLE_NAME); dropTable(WaypointsColumns.TABLE_NAME);
databaseHelper.onUpgrade(db, 16, 20);
assertTrue(checkTable(TrackPointsColumns.TABLE_NAME)); int oldVersion = 16;
assertTrue(checkTable(TracksColumns.TABLE_NAME)); DatabaseHelper databaseHelper = new DatabaseHelper(getContext());
assertTrue(checkTable(WaypointsColumns.TABLE_NAME)); databaseHelper.onUpgrade(db, oldVersion, MyTracksProvider.DATABASE_VERSION);
assertTrue(hasTable(TracksColumns.TABLE_NAME));
assertTrue(hasTable(TrackPointsColumns.TABLE_NAME));
assertTrue(hasTable(WaypointsColumns.TABLE_NAME));
} }
/** /**
* Tests the method * Tests {@link MyTracksProvider.DatabaseHelper#onUpgrade(SQLiteDatabase, int,
* {@link MyTracksProvider.DatabaseHelper#onUpgrade(SQLiteDatabase, int, int)} * int)} when version is 17.
* when version is 17.
*/ */
public void testDatabaseHelper_onUpgrade_Version17() { public void testDatabaseHelper_onUpgrade_Version17() {
DatabaseHelper databaseHelper = new DatabaseHelper(getContext()); setupUpgrade(17);
// Make two table is only contains one normal integer column. assertTrue(hasColumn(TrackPointsColumns.TABLE_NAME, TrackPointsColumns.SENSOR));
dropTable(TrackPointsColumns.TABLE_NAME); assertTrue(hasColumn(TracksColumns.TABLE_NAME, TracksColumns.TABLEID));
dropTable(TracksColumns.TABLE_NAME); assertTrue(hasColumn(TracksColumns.TABLE_NAME, TracksColumns.ICON));
createEmptyTable(TrackPointsColumns.TABLE_NAME); assertTrue(hasColumn(TracksColumns.TABLE_NAME, TracksColumns.DRIVEID));
createEmptyTable(TracksColumns.TABLE_NAME); assertTrue(hasColumn(TracksColumns.TABLE_NAME, TracksColumns.MODIFIEDTIME));
databaseHelper.onUpgrade(db, 17, 20); assertTrue(hasColumn(TracksColumns.TABLE_NAME, TracksColumns.SHAREDWITHME));
assertTrue(isColumnExisted(TrackPointsColumns.TABLE_NAME, TrackPointsColumns.SENSOR)); assertTrue(hasColumn(TracksColumns.TABLE_NAME, TracksColumns.SHAREDOWNER));
assertTrue(isColumnExisted(TracksColumns.TABLE_NAME, TracksColumns.TABLEID)); assertTrue(hasColumn(WaypointsColumns.TABLE_NAME, WaypointsColumns.PHOTOURL));
assertTrue(isColumnExisted(TracksColumns.TABLE_NAME, TracksColumns.ICON)); assertTrue(hasColumn(TracksColumns.TABLE_NAME, TracksColumns.CALORIE));
} }
/** /**
* Tests the method * Tests {@link MyTracksProvider.DatabaseHelper#onUpgrade(SQLiteDatabase, int,
* {@link MyTracksProvider.DatabaseHelper#onUpgrade(SQLiteDatabase, int, int)} * int)} when version is 18.
* when version is 18.
*/ */
public void testDatabaseHelper_onUpgrade_Version18() { public void testDatabaseHelper_onUpgrade_Version18() {
DatabaseHelper databaseHelper = new DatabaseHelper(getContext()); setupUpgrade(18);
// Make two table is only contains one normal integer column. assertFalse(hasColumn(TrackPointsColumns.TABLE_NAME, TrackPointsColumns.SENSOR));
dropTable(TrackPointsColumns.TABLE_NAME); assertTrue(hasColumn(TracksColumns.TABLE_NAME, TracksColumns.TABLEID));
dropTable(TracksColumns.TABLE_NAME); assertTrue(hasColumn(TracksColumns.TABLE_NAME, TracksColumns.ICON));
createEmptyTable(TrackPointsColumns.TABLE_NAME); assertTrue(hasColumn(TracksColumns.TABLE_NAME, TracksColumns.DRIVEID));
createEmptyTable(TracksColumns.TABLE_NAME); assertTrue(hasColumn(TracksColumns.TABLE_NAME, TracksColumns.MODIFIEDTIME));
databaseHelper.onUpgrade(db, 18, 20); assertTrue(hasColumn(TracksColumns.TABLE_NAME, TracksColumns.SHAREDWITHME));
assertFalse(isColumnExisted(TrackPointsColumns.TABLE_NAME, TrackPointsColumns.SENSOR)); assertTrue(hasColumn(TracksColumns.TABLE_NAME, TracksColumns.SHAREDOWNER));
assertTrue(isColumnExisted(TracksColumns.TABLE_NAME, TracksColumns.TABLEID)); assertTrue(hasColumn(WaypointsColumns.TABLE_NAME, WaypointsColumns.PHOTOURL));
assertTrue(isColumnExisted(TracksColumns.TABLE_NAME, TracksColumns.ICON)); assertTrue(hasColumn(TracksColumns.TABLE_NAME, TracksColumns.CALORIE));
} }
/** /**
* Tests the method * Tests {@link MyTracksProvider.DatabaseHelper#onUpgrade(SQLiteDatabase, int,
* {@link MyTracksProvider.DatabaseHelper#onUpgrade(SQLiteDatabase, int, int)} * int)} when version is 19.
* when version is 19.
*/ */
public void testDatabaseHelper_onUpgrade_Version19() { public void testDatabaseHelper_onUpgrade_Version19() {
DatabaseHelper databaseHelper = new DatabaseHelper(getContext()); setupUpgrade(19);
// Make two table is only contains one normal integer column. assertFalse(hasColumn(TrackPointsColumns.TABLE_NAME, TrackPointsColumns.SENSOR));
dropTable(TrackPointsColumns.TABLE_NAME); assertFalse(hasColumn(TracksColumns.TABLE_NAME, TracksColumns.TABLEID));
dropTable(TracksColumns.TABLE_NAME); assertTrue(hasColumn(TracksColumns.TABLE_NAME, TracksColumns.ICON));
createEmptyTable(TrackPointsColumns.TABLE_NAME); assertTrue(hasColumn(TracksColumns.TABLE_NAME, TracksColumns.DRIVEID));
createEmptyTable(TracksColumns.TABLE_NAME); assertTrue(hasColumn(TracksColumns.TABLE_NAME, TracksColumns.MODIFIEDTIME));
databaseHelper.onUpgrade(db, 19, 20); assertTrue(hasColumn(TracksColumns.TABLE_NAME, TracksColumns.SHAREDWITHME));
assertFalse(isColumnExisted(TrackPointsColumns.TABLE_NAME, TrackPointsColumns.SENSOR)); assertTrue(hasColumn(TracksColumns.TABLE_NAME, TracksColumns.SHAREDOWNER));
assertFalse(isColumnExisted(TracksColumns.TABLE_NAME, TracksColumns.TABLEID)); assertTrue(hasColumn(WaypointsColumns.TABLE_NAME, WaypointsColumns.PHOTOURL));
assertTrue(isColumnExisted(TracksColumns.TABLE_NAME, TracksColumns.ICON)); assertTrue(hasColumn(TracksColumns.TABLE_NAME, TracksColumns.CALORIE));
} }
/** /**
* Tests the method {@link MyTracksProvider#onCreate()}. * Tests {@link MyTracksProvider.DatabaseHelper#onUpgrade(SQLiteDatabase, int,
* int)} when version is 20.
*/
public void testDatabaseHelper_onUpgrade_Version20() {
setupUpgrade(20);
assertFalse(hasColumn(TrackPointsColumns.TABLE_NAME, TrackPointsColumns.SENSOR));
assertFalse(hasColumn(TracksColumns.TABLE_NAME, TracksColumns.TABLEID));
assertFalse(hasColumn(TracksColumns.TABLE_NAME, TracksColumns.ICON));
assertTrue(hasColumn(TracksColumns.TABLE_NAME, TracksColumns.DRIVEID));
assertTrue(hasColumn(TracksColumns.TABLE_NAME, TracksColumns.MODIFIEDTIME));
assertTrue(hasColumn(TracksColumns.TABLE_NAME, TracksColumns.SHAREDWITHME));
assertTrue(hasColumn(TracksColumns.TABLE_NAME, TracksColumns.SHAREDOWNER));
assertTrue(hasColumn(WaypointsColumns.TABLE_NAME, WaypointsColumns.PHOTOURL));
assertTrue(hasColumn(TracksColumns.TABLE_NAME, TracksColumns.CALORIE));
}
/**
* Tests {@link MyTracksProvider.DatabaseHelper#onUpgrade(SQLiteDatabase, int,
* int)} when version is 21.
*/
public void testDatabaseHelper_onUpgrade_Version21() {
setupUpgrade(21);
assertFalse(hasColumn(TrackPointsColumns.TABLE_NAME, TrackPointsColumns.SENSOR));
assertFalse(hasColumn(TracksColumns.TABLE_NAME, TracksColumns.TABLEID));
assertFalse(hasColumn(TracksColumns.TABLE_NAME, TracksColumns.ICON));
assertFalse(hasColumn(TracksColumns.TABLE_NAME, TracksColumns.DRIVEID));
assertFalse(hasColumn(TracksColumns.TABLE_NAME, TracksColumns.MODIFIEDTIME));
assertFalse(hasColumn(TracksColumns.TABLE_NAME, TracksColumns.SHAREDWITHME));
assertFalse(hasColumn(TracksColumns.TABLE_NAME, TracksColumns.SHAREDOWNER));
assertTrue(hasColumn(WaypointsColumns.TABLE_NAME, WaypointsColumns.PHOTOURL));
assertTrue(hasColumn(TracksColumns.TABLE_NAME, TracksColumns.CALORIE));
}
/**
* Tests {@link MyTracksProvider.DatabaseHelper#onUpgrade(SQLiteDatabase, int,
* int)} when version is 22.
*/
public void testDatabaseHelper_onUpgrade_Version22() {
setupUpgrade(22);
assertFalse(hasColumn(TrackPointsColumns.TABLE_NAME, TrackPointsColumns.SENSOR));
assertFalse(hasColumn(TracksColumns.TABLE_NAME, TracksColumns.TABLEID));
assertFalse(hasColumn(TracksColumns.TABLE_NAME, TracksColumns.ICON));
assertFalse(hasColumn(TracksColumns.TABLE_NAME, TracksColumns.DRIVEID));
assertFalse(hasColumn(TracksColumns.TABLE_NAME, TracksColumns.MODIFIEDTIME));
assertFalse(hasColumn(TracksColumns.TABLE_NAME, TracksColumns.SHAREDWITHME));
assertFalse(hasColumn(TracksColumns.TABLE_NAME, TracksColumns.SHAREDOWNER));
assertFalse(hasColumn(WaypointsColumns.TABLE_NAME, WaypointsColumns.PHOTOURL));
assertFalse(hasColumn(TracksColumns.TABLE_NAME, TracksColumns.CALORIE));
}
/**
* Tests {@link MyTracksProvider#onCreate(android.content.Context)}.
*/ */
public void testOnCreate() { public void testOnCreate() {
assertTrue(myTracksProvider.onCreate(getContext())); assertTrue(myTracksProvider.onCreate(getContext()));
} }
/** /**
* Tests the method {@link MyTracksProvider#getType(Uri)}. * Tests {@link MyTracksProvider#getType(Uri)}.
*/ */
public void testGetType() { public void testGetType() {
assertEquals(TrackPointsColumns.CONTENT_TYPE,
myTracksProvider.getType(TrackPointsColumns.CONTENT_URI));
assertEquals(TracksColumns.CONTENT_TYPE, myTracksProvider.getType(TracksColumns.CONTENT_URI)); assertEquals(TracksColumns.CONTENT_TYPE, myTracksProvider.getType(TracksColumns.CONTENT_URI));
assertEquals(WaypointsColumns.CONTENT_TYPE, assertEquals(
myTracksProvider.getType(WaypointsColumns.CONTENT_URI)); TrackPointsColumns.CONTENT_TYPE, myTracksProvider.getType(TrackPointsColumns.CONTENT_URI));
assertEquals(
WaypointsColumns.CONTENT_TYPE, myTracksProvider.getType(WaypointsColumns.CONTENT_URI));
} }
/** /**
* Creates an table only contains one column. * Creates a table, containing one column.
* *
* @param table the name of table * @param table the table name
*/ */
private void createEmptyTable(String table) { private void createTable(String table) {
db.execSQL("CREATE TABLE " + table + " (test INTEGER)"); db.execSQL("CREATE TABLE " + table + " (test INTEGER)");
} }
/** /**
* Drops a table in database. * Drops a table in database.
* *
* @param table * @param table the table name
*/ */
private void dropTable(String table) { private void dropTable(String table) {
db.execSQL("Drop TABLE " + table); db.execSQL("Drop TABLE " + table);
} }
/** /**
* Checks whether a table is existed. * Returns true if the table exists.
* *
* @param table the name of table * @param table the table name
* @return true means the table has existed
*/ */
private boolean checkTable(String table) { private boolean hasTable(String table) {
try { try {
db.rawQuery("select count(*) from " + table, null); db.rawQuery("select count(*) from " + table, null);
return true; return true;
@@ -175,14 +228,12 @@ public class MyTracksProviderTest extends AndroidTestCase {
} }
/** /**
* Checks whether a column in a table is existed by whether can order by the * Returns true if the column in the table exists.
* column.
* *
* @param table the name of table * @param table the table name
* @param column the name of column * @param column the column name
* @return true means the column has existed
*/ */
private boolean isColumnExisted(String table, String column) { private boolean hasColumn(String table, String column) {
try { try {
db.execSQL("SElECT count(*) from " + table + " order by " + column); db.execSQL("SElECT count(*) from " + table + " order by " + column);
} catch (Exception e) { } catch (Exception e) {
@@ -193,4 +244,20 @@ public class MyTracksProviderTest extends AndroidTestCase {
return true; return true;
} }
/**
* Sets up upgrade.
*
* @param oldVersion thd old database version
*/
private void setupUpgrade(int oldVersion) {
dropTable(TracksColumns.TABLE_NAME);
dropTable(TrackPointsColumns.TABLE_NAME);
dropTable(WaypointsColumns.TABLE_NAME);
createTable(TracksColumns.TABLE_NAME);
createTable(TrackPointsColumns.TABLE_NAME);
createTable(WaypointsColumns.TABLE_NAME);
DatabaseHelper databaseHelper = new DatabaseHelper(getContext());
databaseHelper.onUpgrade(db, oldVersion, MyTracksProvider.DATABASE_VERSION);
}
} }
@@ -33,9 +33,9 @@ import android.test.AndroidTestCase;
*/ */
public class ChartFragmentTest extends AndroidTestCase { public class ChartFragmentTest extends AndroidTestCase {
private ChartFragment chartFragment; private static final double HOURS_PER_UNIT = 60.0;
private final double HOURS_PER_UNIT = 60.0; private ChartFragment chartFragment;
@Override @Override
protected void setUp() throws Exception { protected void setUp() throws Exception {
@@ -46,7 +46,7 @@ public class ChartFragmentTest extends AndroidTestCase {
/** /**
* Tests the logic to get the incorrect values of sensor in * Tests the logic to get the incorrect values of sensor in
* {@link ChartFragment#fillDataPoint(Location, double[])} * {@link ChartFragment#fillDataPoint(android.content.Context, Location, double[])}
*/ */
public void testFillDataPoint_sensorIncorrect() { public void testFillDataPoint_sensorIncorrect() {
MyTracksLocation myTracksLocation = TrackStubUtils.createMyTracksLocation(); MyTracksLocation myTracksLocation = TrackStubUtils.createMyTracksLocation();
@@ -83,7 +83,7 @@ public class ChartFragmentTest extends AndroidTestCase {
/** /**
* Tests the logic to get the correct values of sensor in * Tests the logic to get the correct values of sensor in
* {@link ChartFragment#fillDataPoint(Location, double[])}. * {@link ChartFragment#fillDataPoint(android.content.Context, Location, double[])}.
*/ */
public void testFillDataPoint_sensorCorrect() { public void testFillDataPoint_sensorCorrect() {
MyTracksLocation myTracksLocation = TrackStubUtils.createMyTracksLocation(); MyTracksLocation myTracksLocation = TrackStubUtils.createMyTracksLocation();
@@ -118,7 +118,7 @@ public class ChartFragmentTest extends AndroidTestCase {
/** /**
* Tests the logic to get the value of metric Distance in * Tests the logic to get the value of metric Distance in
* {@link ChartFragment#fillDataPoint(Location, double[])}. * {@link ChartFragment#fillDataPoint(android.content.Context, Location, double[])}.
*/ */
public void testFillDataPoint_distanceMetric() { public void testFillDataPoint_distanceMetric() {
// By distance. // By distance.
@@ -159,7 +159,7 @@ public class ChartFragmentTest extends AndroidTestCase {
/** /**
* Tests the logic to get the value of imperial Distance in * Tests the logic to get the value of imperial Distance in
* {@link ChartFragment#fillDataPoint(Location, double[])}. * {@link ChartFragment#fillDataPoint(android.content.Context, Location, double[])}.
*/ */
public void testFillDataPoint_distanceImperial() { public void testFillDataPoint_distanceImperial() {
// By distance. // By distance.
@@ -204,7 +204,7 @@ public class ChartFragmentTest extends AndroidTestCase {
/** /**
* Tests the logic to get the values of time in * Tests the logic to get the values of time in
* {@link ChartFragment#fillDataPoint(Location, double[])}. * {@link ChartFragment#fillDataPoint(android.content.Context, Location, double[])}.
*/ */
public void testFillDataPoint_time() { public void testFillDataPoint_time() {
// By time // By time
@@ -220,9 +220,9 @@ public class ChartFragmentTest extends AndroidTestCase {
} }
/** /**
* Tests the logic to get the value of elevation in * Tests the logic to get the value of elevation in
* {@link ChartFragment#fillDataPoint(Location, double[])} by one and two * {@link ChartFragment#fillDataPoint(android.content.Context,
* points. * Location, double[])} by one and two points.
*/ */
public void testFillDataPoint_elevation() { public void testFillDataPoint_elevation() {
MyTracksLocation myTracksLocation1 = TrackStubUtils.createMyTracksLocation(); MyTracksLocation myTracksLocation1 = TrackStubUtils.createMyTracksLocation();
@@ -247,9 +247,10 @@ public class ChartFragmentTest extends AndroidTestCase {
/** /**
* Tests the logic to get the value of speed in * Tests the logic to get the value of speed in
* {@link ChartFragment#fillDataPoint(Location, double[])}. In this test, * {@link ChartFragment#fillDataPoint(android.content.Context, Location, double[])}. In this test,
* firstly remove all points in memory, and then fill in two points one by * firstly remove all points in memory,
* one. The speed values of these points are 129, 130. * and then fill in two points one by one. The speed values of these points
* are 129, 130.
*/ */
public void testFillDataPoint_speed() { public void testFillDataPoint_speed() {
/* /*
@@ -358,7 +359,7 @@ public class ChartFragmentTest extends AndroidTestCase {
*/ */
private double[] fillDataPointTestHelper(Location location) { private double[] fillDataPointTestHelper(Location location) {
double[] point = new double[ChartView.NUM_SERIES + 1]; double[] point = new double[ChartView.NUM_SERIES + 1];
chartFragment.fillDataPoint(location, point); chartFragment.fillDataPoint(getContext(), location, point);
return point; return point;
} }
@@ -7,9 +7,6 @@ import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils.Factory; import com.google.android.apps.mytracks.content.MyTracksProviderUtils.Factory;
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.file.exporter.FileTrackExporter;
import com.google.android.apps.mytracks.io.file.exporter.TrackExporterListener;
import com.google.android.apps.mytracks.io.file.exporter.TrackWriter;
import com.google.android.apps.mytracks.services.TrackRecordingServiceTest.MockContext; import com.google.android.apps.mytracks.services.TrackRecordingServiceTest.MockContext;
import com.google.android.apps.mytracks.testing.TestingProviderUtilsFactory; import com.google.android.apps.mytracks.testing.TestingProviderUtilsFactory;
@@ -42,7 +39,7 @@ public class FileTrackExporterTest extends AndroidTestCase {
private IMocksControl mocksControl; private IMocksControl mocksControl;
private TrackWriter trackWriter; private TrackWriter trackWriter;
private Track track; private Track[] tracks;
private OutputStream outputStream; private OutputStream outputStream;
private FileTrackExporter fileTrackExporter; private FileTrackExporter fileTrackExporter;
@@ -65,10 +62,12 @@ public class FileTrackExporterTest extends AndroidTestCase {
mocksControl = EasyMock.createStrictControl(); mocksControl = EasyMock.createStrictControl();
trackWriter = mocksControl.createMock(TrackWriter.class); trackWriter = mocksControl.createMock(TrackWriter.class);
track = new Track(); Track track = new Track();
track.setName(TRACK_NAME); track.setName(TRACK_NAME);
track.setId(TRACK_ID); track.setId(TRACK_ID);
tracks = new Track[] {track};
outputStream = new ByteArrayOutputStream(); outputStream = new ByteArrayOutputStream();
TrackExporterListener trackExporterListener = new TrackExporterListener() { TrackExporterListener trackExporterListener = new TrackExporterListener() {
@@ -79,7 +78,7 @@ public class FileTrackExporterTest extends AndroidTestCase {
} }
}; };
fileTrackExporter = new FileTrackExporter( fileTrackExporter = new FileTrackExporter(
myTracksProviderUtils, new Track[] { track }, trackWriter, trackExporterListener); myTracksProviderUtils, tracks, trackWriter, trackExporterListener);
} }
@Override @Override
@@ -95,10 +94,13 @@ public class FileTrackExporterTest extends AndroidTestCase {
// Set expected mock behavior // Set expected mock behavior
trackWriter.prepare(outputStream); trackWriter.prepare(outputStream);
trackWriter.writeHeader(track); trackWriter.writeHeader(tracks);
trackWriter.writeBeginTrack(track, null); trackWriter.writeBeginTracks();
trackWriter.writeEndTrack(track, null); trackWriter.writeBeginTrack(tracks[0], null);
trackWriter.writeEndTrack(tracks[0], null);
trackWriter.writeEndTracks();
trackWriter.writeFooter(); trackWriter.writeFooter();
trackWriter.close();
mocksControl.replay(); mocksControl.replay();
assertTrue(fileTrackExporter.writeTrack(outputStream)); assertTrue(fileTrackExporter.writeTrack(outputStream));
@@ -124,11 +126,14 @@ public class FileTrackExporterTest extends AndroidTestCase {
// Set expected mock behavior // Set expected mock behavior
trackWriter.prepare(outputStream); trackWriter.prepare(outputStream);
trackWriter.writeHeader(track); trackWriter.writeHeader(tracks);
trackWriter.writeBeginTrack(track, null); trackWriter.writeBeginTracks();
trackWriter.writeEndTrack(track, null); trackWriter.writeBeginTrack(tracks[0], null);
trackWriter.writeEndTrack(tracks[0], null);
trackWriter.writeEndTracks();
trackWriter.writeFooter(); trackWriter.writeFooter();
trackWriter.close();
mocksControl.replay(); mocksControl.replay();
assertTrue(fileTrackExporter.writeTrack(outputStream)); assertTrue(fileTrackExporter.writeTrack(outputStream));
@@ -161,16 +166,17 @@ public class FileTrackExporterTest extends AndroidTestCase {
} }
trackWriter.prepare(outputStream); trackWriter.prepare(outputStream);
trackWriter.writeHeader(track); trackWriter.writeHeader(tracks);
// Expect reading/writing of the waypoints (except the first) // Expect reading/writing of the waypoints (except the first)
trackWriter.writeBeginWaypoints(); trackWriter.writeBeginWaypoints(tracks[0]);
trackWriter.writeWaypoint(waypointEq(waypoints[1])); trackWriter.writeWaypoint(waypointEq(waypoints[1]));
trackWriter.writeWaypoint(waypointEq(waypoints[2])); trackWriter.writeWaypoint(waypointEq(waypoints[2]));
trackWriter.writeEndWaypoints(); trackWriter.writeEndWaypoints();
// Begin the track // Begin the track
trackWriter.writeBeginTrack(trackEq(track), locationEq(locations[0])); trackWriter.writeBeginTracks();
trackWriter.writeBeginTrack(trackEq(tracks[0]), locationEq(locations[0]));
// Write locations 1-2 // Write locations 1-2
trackWriter.writeOpenSegment(); trackWriter.writeOpenSegment();
@@ -188,10 +194,12 @@ public class FileTrackExporterTest extends AndroidTestCase {
trackWriter.writeCloseSegment(); trackWriter.writeCloseSegment();
// End the track // End the track
trackWriter.writeEndTrack(trackEq(track), locationEq(locations[5])); trackWriter.writeEndTrack(trackEq(tracks[0]), locationEq(locations[5]));
trackWriter.writeEndTracks();
trackWriter.writeFooter(); trackWriter.writeFooter();
trackWriter.close();
mocksControl.replay(); mocksControl.replay();
assertTrue(fileTrackExporter.writeTrack(outputStream)); assertTrue(fileTrackExporter.writeTrack(outputStream));
@@ -17,7 +17,6 @@ package com.google.android.apps.mytracks.io.file.exporter;
import com.google.android.apps.mytracks.content.DescriptionGenerator; import com.google.android.apps.mytracks.content.DescriptionGenerator;
import com.google.android.apps.mytracks.content.Track; import com.google.android.apps.mytracks.content.Track;
import com.google.android.apps.mytracks.io.file.exporter.KmlTrackWriter;
import com.google.android.apps.mytracks.stats.TripStatistics; import com.google.android.apps.mytracks.stats.TripStatistics;
import android.location.Location; import android.location.Location;
@@ -5,7 +5,6 @@ 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.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.file.exporter.TrackWriter;
import android.test.AndroidTestCase; import android.test.AndroidTestCase;
@@ -117,11 +116,12 @@ public abstract class TrackWriterTest extends AndroidTestCase {
protected String writeTrack(TrackWriter trackWriter) throws Exception { protected String writeTrack(TrackWriter trackWriter) throws Exception {
OutputStream output = new ByteArrayOutputStream(BUFFER_SIZE); OutputStream output = new ByteArrayOutputStream(BUFFER_SIZE);
trackWriter.prepare(output); trackWriter.prepare(output);
trackWriter.writeHeader(track); trackWriter.writeHeader(new Track[] {track});
trackWriter.writeBeginWaypoints(); trackWriter.writeBeginWaypoints(track);
trackWriter.writeWaypoint(wp1); trackWriter.writeWaypoint(wp1);
trackWriter.writeWaypoint(wp2); trackWriter.writeWaypoint(wp2);
trackWriter.writeEndWaypoints(); trackWriter.writeEndWaypoints();
trackWriter.writeBeginTracks();
trackWriter.writeBeginTrack(track, location1); trackWriter.writeBeginTrack(track, location1);
trackWriter.writeOpenSegment(); trackWriter.writeOpenSegment();
trackWriter.writeLocation(location1); trackWriter.writeLocation(location1);
@@ -132,7 +132,9 @@ public abstract class TrackWriterTest extends AndroidTestCase {
trackWriter.writeLocation(location4); trackWriter.writeLocation(location4);
trackWriter.writeCloseSegment(); trackWriter.writeCloseSegment();
trackWriter.writeEndTrack(track, location4); trackWriter.writeEndTrack(track, location4);
trackWriter.writeEndTracks();
trackWriter.writeFooter(); trackWriter.writeFooter();
trackWriter.close();
return output.toString(); return output.toString();
} }