Merge heads

This commit is contained in:
youtaol
2013-05-09 11:27:28 +08:00
44 changed files with 903 additions and 803 deletions
+2 -9
View File
@@ -15,7 +15,7 @@ See the License for the specific language governing permissions and
limitations under the License.
-->
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
style="@style/ScrollView" >
style="@style/StatsScrollView" >
<LinearLayout
android:layout_height="wrap_content"
android:layout_width="match_parent"
@@ -44,14 +44,7 @@ limitations under the License.
<TextView
android:text="@string/marker_detail_statistics_title"
style="@style/TextLarge.WithTopMargin" />
<TableLayout
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:paddingTop="8dp"
android:shrinkColumns="0,2"
android:stretchColumns="0,2" >
<include layout="@layout/stats_core" />
</TableLayout>
<include layout="@layout/stats_content" />
</LinearLayout>
</LinearLayout>
</ScrollView>
+7 -36
View File
@@ -15,42 +15,13 @@ See the License for the specific language governing permissions and
limitations under the License.
-->
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
style="@style/ScrollView" >
<TableLayout
style="@style/StatsScrollView" >
<LinearLayout
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:padding="8dp"
android:shrinkColumns="0,2"
android:stretchColumns="0,2" >
<!-- Speed on one line -->
<TableRow>
<TextView
android:id="@+id/stats_speed_label"
style="@style/StatsLabel" />
</TableRow>
<TableRow>
<TextView
android:id="@+id/stats_speed_value"
style="@style/StatsValue" />
</TableRow>
<include layout="@layout/stats_core" />
<TableRow android:id="@+id/stats_coordinate_label_table_row" >
<TextView
android:text="@string/stats_latitude"
style="@style/StatsLabel" />
<TextView
android:layout_column="2"
android:text="@string/stats_longitude"
style="@style/StatsLabel" />
</TableRow>
<TableRow android:id="@+id/stats_coordinate_value_table_row" >
<TextView
android:id="@+id/stats_latitude_value"
style="@style/StatsValue" />
<TextView style="@style/StatsSpacer" />
<TextView
android:id="@+id/stats_longitude_value"
style="@style/StatsValue" />
</TableRow>
</TableLayout>
android:orientation="vertical"
android:paddingLeft="8dp"
android:paddingRight="8dp" >
<include layout="@layout/stats_content" />
</LinearLayout>
</ScrollView>
+132
View File
@@ -0,0 +1,132 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2013 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.
-->
<merge xmlns:android="http://schemas.android.com/apk/res/android" >
<!-- Row 1: distance and speed -->
<LinearLayout
android:layout_height="wrap_content"
android:layout_width="match_parent" >
<include
android:id="@+id/stats_distance"
layout="@layout/stats_large_item" />
<View style="@style/StatsVerticalSpacer" />
<include
android:id="@+id/stats_speed"
layout="@layout/stats_large_item" />
</LinearLayout>
<!-- Row 2: total time and average speed -->
<LinearLayout
android:layout_height="wrap_content"
android:layout_width="match_parent" >
<include
android:id="@+id/stats_total_time"
layout="@layout/stats_large_item" />
<View style="@style/StatsVerticalSpacer" />
<include
android:id="@+id/stats_average_speed"
layout="@layout/stats_large_item" />
</LinearLayout>
<!-- Row 3: horizontal line -->
<View style="@style/StatsHorizontalLine" />
<!-- Row 3: moving time and average moving speed -->
<LinearLayout
android:layout_height="wrap_content"
android:layout_width="match_parent" >
<include
android:id="@+id/stats_moving_time"
layout="@layout/stats_small_item" />
<View style="@style/StatsVerticalSpacer" />
<include
android:id="@+id/stats_average_moving_time"
layout="@layout/stats_small_item" />
</LinearLayout>
<!-- Row 4: empty and max speed -->
<LinearLayout
android:layout_height="wrap_content"
android:layout_width="match_parent" >
<LinearLayout style="@style/StatsSmallItemContainer" />
<View style="@style/StatsVerticalSpacer" />
<include
android:id="@+id/stats_max_speed"
layout="@layout/stats_small_item" />
</LinearLayout>
<!-- Row 5: horizontal line -->
<View
android:id="@+id/stats_grade_elevation_horizontal_line"
style="@style/StatsHorizontalLine" />
<!-- Row 5: grade and elevation -->
<LinearLayout
android:id="@+id/stats_grade_elevation_container"
android:layout_height="wrap_content"
android:layout_width="match_parent" >
<!-- Grade -->
<LinearLayout style="@style/StatsSmallItemContainer" >
<!-- Grade label -->
<TextView
android:text="@string/stats_grade"
style="@style/StatsSmallLabel" />
<!-- Grade min -->
<include
android:id="@+id/stats_grade_min"
layout="@layout/stats_small_item_1line" />
<!-- Grade max -->
<include
android:id="@+id/stats_grade_max"
layout="@layout/stats_small_item_1line" />
</LinearLayout>
<View style="@style/StatsVerticalSpacer" />
<!-- Elevation -->
<LinearLayout style="@style/StatsSmallItemContainer" >
<!-- Elevation label -->
<TextView
android:text="@string/stats_elevation"
style="@style/StatsSmallLabel" />
<!-- Elevation -->
<include
android:id="@+id/stats_elevation"
layout="@layout/stats_small_item_1line" />
<!-- Elevation gain -->
<include
android:id="@+id/stats_elevation_gain"
layout="@layout/stats_small_item_1line" />
<!-- Elevation min -->
<include
android:id="@+id/stats_elevation_min"
layout="@layout/stats_small_item_1line" />
<!-- Elevation max -->
<include
android:id="@+id/stats_elevation_max"
layout="@layout/stats_small_item_1line" />
</LinearLayout>
</LinearLayout>
<!-- Row 6: horizontal line -->
<View
android:id="@+id/stats_coordinate_horizontal_line"
style="@style/StatsHorizontalLine" />
<!-- Row 6: latitude and longitude -->
<LinearLayout
android:id="@+id/stats_coordinate_container"
android:layout_height="wrap_content"
android:layout_width="match_parent" >
<include
android:id="@+id/stats_latitude"
layout="@layout/stats_small_item" />
<View style="@style/StatsVerticalSpacer" />
<include
android:id="@+id/stats_longitude"
layout="@layout/stats_small_item" />
</LinearLayout>
</merge>
-140
View File
@@ -1,140 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2012 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.
-->
<merge xmlns:android="http://schemas.android.com/apk/res/android" >
<!-- Total distance -->
<TableRow>
<TextView
android:text="@string/stats_distance"
style="@style/StatsLabel" />
</TableRow>
<TableRow>
<TextView
android:id="@+id/stats_distance_value"
style="@style/StatsValue" />
</TableRow>
<!-- Total time/moving time -->
<TableRow>
<TextView
android:text="@string/stats_total_time"
style="@style/StatsLabel" />
<TextView
android:id="@+id/stats_moving_time_label"
android:layout_column="2"
android:text="@string/stats_moving_time"
style="@style/StatsLabel" />
</TableRow>
<TableRow>
<TextView
android:id="@+id/stats_total_time_value"
style="@style/StatsValue" />
<TextView
android:id="@+id/stats_moving_time_spacer"
style="@style/StatsSpacer" />
<TextView
android:id="@+id/stats_moving_time_value"
style="@style/StatsValue" />
</TableRow>
<!-- Average speed/average moving speed (average pace/average moving pace) -->
<TableRow>
<TextView
android:id="@+id/stats_average_speed_label"
style="@style/StatsLabel" />
<TextView
android:id="@+id/stats_average_moving_speed_label"
android:layout_column="2"
style="@style/StatsLabel" />
</TableRow>
<TableRow>
<TextView
android:id="@+id/stats_average_speed_value"
style="@style/StatsValue" />
<TextView
android:id="@+id/stats_average_moving_speed_spacer"
style="@style/StatsSpacer" />
<TextView
android:id="@+id/stats_average_moving_speed_value"
style="@style/StatsValue" />
</TableRow>
<!-- Max speed (fastest pace) -->
<TableRow>
<TextView
android:id="@+id/stats_max_speed_label"
style="@style/StatsLabel" />
</TableRow>
<TableRow>
<TextView
android:id="@+id/stats_max_speed_value"
style="@style/StatsValue" />
</TableRow>
<!-- Elevation and elevation gain -->
<TableRow android:id="@+id/stats_elevation_label_table_row1" >
<TextView
android:text="@string/stats_elevation"
style="@style/StatsLabel" />
<TextView
android:layout_column="2"
android:text="@string/stats_elevation_gain"
style="@style/StatsLabel" />
</TableRow>
<TableRow android:id="@+id/stats_elevation_value_table_row1" >
<TextView
android:id="@+id/stats_elevation_value"
style="@style/StatsValue" />
<TextView style="@style/StatsSpacer" />
<TextView
android:id="@+id/stats_elevation_gain_value"
style="@style/StatsValue" />
</TableRow>
<!-- Min and max elevation -->
<TableRow android:id="@+id/stats_elevation_label_table_row2" >
<TextView
android:text="@string/stats_min_elevation"
style="@style/StatsLabel" />
<TextView
android:layout_column="2"
android:text="@string/stats_max_elevation"
style="@style/StatsLabel" />
</TableRow>
<TableRow android:id="@+id/stats_elevation_value_table_row2" >
<TextView
android:id="@+id/stats_min_elevation_value"
style="@style/StatsValue" />
<TextView style="@style/StatsSpacer" />
<TextView
android:id="@+id/stats_max_elevation_value"
style="@style/StatsValue" />
</TableRow>
<!-- Min and max grade -->
<TableRow android:id="@+id/stats_grade_label_table_row" >
<TextView
android:text="@string/stats_min_grade"
style="@style/StatsLabel" />
<TextView
android:layout_column="2"
android:text="@string/stats_max_grade"
style="@style/StatsLabel" />
</TableRow>
<TableRow android:id="@+id/stats_grade_value_table_row" >
<TextView
android:id="@+id/stats_min_grade_value"
style="@style/StatsValue" />
<TextView style="@style/StatsSpacer" />
<TextView
android:id="@+id/stats_max_grade_value"
style="@style/StatsValue" />
</TableRow>
</merge>
+33
View File
@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2013 Google Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/stats_large_item_id"
style="@style/StatsLargeItemContainer" >
<!-- Distance label -->
<TextView
android:id="@+id/stats_label"
style="@style/StatsLargeLabel" />
<!-- Distance value -->
<LinearLayout style="@style/StatsLargeValueContainer" >
<TextView
android:id="@+id/stats_value"
style="@style/StatsLargeValue" />
<TextView
android:id="@+id/stats_unit"
style="@style/StatsUnit" />
</LinearLayout>
</LinearLayout>
+32
View File
@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2013 Google Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/stats_small_item_id"
style="@style/StatsSmallItemContainer" >
<TextView
android:id="@+id/stats_label"
style="@style/StatsSmallLabel" />
<!-- Distance value -->
<LinearLayout style="@style/StatsSmallValueContainer" >
<TextView
android:id="@+id/stats_value"
style="@style/StatsSmallValue" />
<TextView
android:id="@+id/stats_unit"
style="@style/StatsUnit" />
</LinearLayout>
</LinearLayout>
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2012 Google Inc.
Copyright 2013 Google Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -14,14 +14,18 @@ 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.
-->
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
style="@style/ScrollView">
<TableLayout
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:padding="8dp"
android:shrinkColumns="0,2"
android:stretchColumns="0,2" >
<include layout="@layout/stats_core" />
</TableLayout>
</ScrollView>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/stats_small_1line_id"
style="@style/StatsSmallValueContainer" >
<TextView
android:id="@+id/stats_value"
style="@style/StatsSmallValue" />
<TextView
android:id="@+id/stats_unit"
style="@style/StatsUnit" />
<TextView
android:id="@+id/stats_label"
android:layout_gravity="bottom"
android:paddingLeft="8dp"
style="@style/StatsSmallLabel" />
</LinearLayout>
+5
View File
@@ -15,6 +15,11 @@ See the License for the specific language governing permissions and
limitations under the License.
-->
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:icon="@drawable/menu_play"
android:id="@+id/list_context_menu_play"
android:showAsAction="ifRoom"
android:title="@string/menu_play"/>
<item
android:icon="@drawable/menu_share"
android:id="@+id/list_context_menu_share"
+1 -1
View File
@@ -31,7 +31,7 @@ limitations under the License.
</style>
<style name="ListItem">
<item name="android:background">?android:attr/activatedBackgroundIndicator</item>
</style>
</style>
<style name="MyTracksActionBar" parent="@android:style/Widget.Holo.ActionBar">
<!-- Same image as the source except using a grey line instead of a blue line -->
<item name="android:background">@drawable/ab_transparent_dark_holo</item>
+18 -1
View File
@@ -30,6 +30,23 @@ limitations under the License.
<item name="android:orientation">horizontal</item>
<item name="android:measureWithLargestChild">true</item>
</style>
<style name="StatsSmallLabel" parent="@style/TextSmall">
<!-- same as StatsSmallLabel in values/styles.xml except adding textAllCaps -->
<item name="android:gravity">right</item>
<item name="android:layout_gravity">right</item>
<item name="android:singleLine">false</item>
<item name="android:textAllCaps">true</item>
<item name="android:textStyle">bold</item>
</style>
<style name="StatsLargeLabel" parent="@style/TextSmall">
<!-- same as StatsLargeLabel in values/styles.xml except adding textAllCaps -->
<item name="android:gravity">right</item>
<item name="android:layout_gravity">right</item>
<item name="android:singleLine">false</item>
<item name="android:textAllCaps">true</item>
<item name="android:textColor">@color/stats_large_label</item>
<item name="android:textStyle">bold</item>
</style>
<style name="TextChooseActivity">
<!-- Same as TextChooseActivity in values/styles.xml except removing textSize and using textAppearance -->
<item name="android:textAppearance">?android:attr/textAppearanceListItemSmall</item>
@@ -58,7 +75,7 @@ limitations under the License.
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_width">wrap_content</item>
<item name="android:singleLine">true</item>
<item name="android:textColor">@color/track_widget_label</item>
<item name="android:textColor">@color/stats_large_label</item>
<item name="android:textSize">10dp</item>
<item name="android:textStyle">bold</item>
<item name="android:textAllCaps">true</item>
+2 -2
View File
@@ -28,11 +28,11 @@ limitations under the License.
<color name="chart_speed_border">#FF0066FF</color> <!-- blue -->
<color name="chart_speed_fill">#40C8E0FF</color> <!-- transparent blue -->
<color name="recording_text">#FFBE161B</color> <!-- red -->
<color name="stats_large_label">#FFFAAD2C</color> <!-- orange -->
<color name="stats_separator">#99999999</color> <!-- light gray -->
<color name="track_color_fast">#F7DF0101</color> <!-- red color -->
<color name="track_color_normal">#F75858FA</color> <!-- blue color -->
<color name="track_color_slow">#F774DF00</color> <!-- green color -->
<color name="track_controller_background">#FF272727</color> <!-- dark gray -->
<color name="track_widget_label">#FFFAAD2C</color> <!-- orange -->
<color name="track_widget_line">#99999999</color> <!-- light gray -->
<color name="warning_background">#FFFF8800</color> <!-- orange dark -->
</resources>
+1 -3
View File
@@ -53,9 +53,7 @@ limitations under the License.
<string name="share_track_key">shareTrack</string>
<string name="split_frequency_key">splitFrequency</string>
<string name="stats_show_coordinate_key">statsShowCoordinate</string>
<string name="stats_show_elevation_key">statsShowElevation</string>
<string name="stats_show_grade_key">statsShowGrade</string>
<string name="stats_show_moving_time_key">statsShowMovingTime</string>
<string name="stats_show_grade_elevation_key">statsShowGradeElevation</string>
<string name="track_color_mode_medium_key">trackColorModeMedium</string>
<string name="track_color_mode_percentage_key">trackColorModePercentage</string>
<string name="track_color_mode_slow_key">trackColorModeSlow</string>
+19 -53
View File
@@ -2089,12 +2089,12 @@ limitations under the License.
Character limit: ~23 (1 line)">
Latitude/Longitude
</string>
<string name="settings_stats_grade"
translation_description="In the 'Stats settings, the option to show grade. Grade is the amount
of inclination to the horizontal, also known as slope or incline.
<string name="settings_stats_grade_elevation"
translation_description="In the 'Stats settings, the option to show grade and elevation. Grade
is the amount of inclination to the horizontal, also known as slope or incline.
Character limit: ~23 (1 line)">
Grade
Grade/Elevation
</string>
<string name="settings_stats_rate_title"
translation_description="In the 'Stats' settings, the option to change the preferred rate,
@@ -2209,14 +2209,19 @@ limitations under the License.
Character limit: ~23 (1 line)">
Elevation
</string>
<string name="stats_elevation_gain"
translation_description="In the 'Stats' page, the elevation gain.">
Elevation gain
</string>
<string name="stats_fastest_pace"
translation_description="In the 'Stats' page, the fastest pace.">
Fastest pace
</string>
<string name="stats_gain"
translation_description="In the 'Stats' page, the gain of a value. E.g, gain in elevation.">
Gain
</string>
<string name="stats_grade"
translation_description="In the 'Stats' page, the grade. Grade is the amount of inclination to
the horizontal, also known as slope or incline.">
Grade
</string>
<string name="stats_latitude"
translation_description="In the 'Stats' page, the latitude.">
Latitude
@@ -2225,25 +2230,17 @@ limitations under the License.
translation_description="In the 'Stats' page, the longitude.">
Longitude
</string>
<string name="stats_max_elevation"
translation_description="In the 'Stats' page, the maximum elevation.">
Max elevation
</string>
<string name="stats_max_grade"
translation_description="In the 'Stats' page, the maximum grade.">
Max grade
<string name="stats_max"
translation_description="In the 'Stats' page, the maximum of a value.">
Max
</string>
<string name="stats_max_speed"
translation_description="In the 'Stats' page, the maximum speed.">
Max speed
</string>
<string name="stats_min_elevation"
translation_description="In the 'Stats' page, the minimum elevation.">
Min elevation
</string>
<string name="stats_min_grade"
translation_description="In the 'Stats' page, the minimum grade.">
Min grade
<string name="stats_min"
translation_description="In the 'Stats' page, the minimum of a value.">
Min
</string>
<string name="stats_moving_time"
translation_description="In the 'Stats' page, the moving time.">
@@ -2464,13 +2461,6 @@ limitations under the License.
translation_description="In a setting picker, the value to always enable the option.">
Always
</string>
<string name="value_coordinate_degree"
translation_description="To display a latitude or longitude coordinate in degree. E.g.,
'2.2 \u00B0'. \u00B0 is the unicode value for the degree symbol.
%1$s: a string value of the coordinate. E.g., '2.2'.">
%1$s \u00B0
</string>
<string name="value_float_feet"
translation_description="Display a float value in feet (ft).
@@ -2483,12 +2473,6 @@ limitations under the License.
%1$.2f: a float number. E.g., '2.22'.">
%1$.2f km
</string>
<string name="value_float_kilometer_hour"
translation_description="Display a float value in kilometers per hour (km/h).
%1$.2f: a float number. E.g., '2.22'.">
%1$.2f km/h
</string>
<string name="value_float_meter"
translation_description="Display a float value in meters (m).
@@ -2501,12 +2485,6 @@ limitations under the License.
%1$.2f: a float number. E.g., '2.22'.">
%1$.2f mi
</string>
<string name="value_float_mile_hour"
translation_description="Display a float value in miles per hour (mi/h).
%1$.2f: a float number. E.g., '2.22'.">
%1$.2f mi/h
</string>
<string name="value_float_mile_poor_gps"
translation_description="In a setting picker, the string format to display a float value in
miles (mi), recommended when having poor GPS signal.
@@ -2514,18 +2492,6 @@ limitations under the License.
%1$.1f: a float number. E.g., '2.2'.">
%1$.1f mi (poor GPS)
</string>
<string name="value_float_minute_kilometer"
translation_description="Display a float value in minutes per kilometer (min/km).
%1$.2f: a float number. E.g., '2.22'.">
%1$.2f min/km
</string>
<string name="value_float_minute_mile"
translation_description="Display a float value in minutes per mile (min/mi).
%1$.2f: a float number. E.g., '2.22'.">
%1$.2f min/mi
</string>
<string name="value_integer_feet"
translation_description="In a setting picker, the string format to display an integer value in
feet (ft).
+77 -19
View File
@@ -130,24 +130,82 @@ limitations under the License.
<item name="android:paddingRight">8dp</item>
<item name="android:textColor">@android:color/primary_text_light</item>
</style>
<!-- stats label -->
<style name="StatsLabel" parent="@style/TextMedium">
<item name="android:layout_weight">1</item>
<item name="android:layout_width">0dp</item>
<!-- stats horizontal line -->
<style name="StatsHorizontalLine">
<item name="android:background">@color/stats_separator</item>
<item name="android:layout_height">1dp</item>
<item name="android:layout_width">match_parent</item>
</style>
<!-- stats spacer -->
<style name="StatsSpacer">
<item name="android:layout_height">match_parent</item>
<item name="android:layout_width">8dp</item>
</style>
<!-- stats value -->
<style name="StatsValue" parent="@style/TextLarge">
<item name="android:background">@android:color/background_light</item>
<item name="android:gravity">right</item>
<item name="android:layout_weight">1</item>
<!-- stats large item container -->
<style name="StatsLargeItemContainer">
<item name="android:layout_gravity">top</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_weight">10</item>
<item name="android:layout_width">0dp</item>
<item name="android:orientation">vertical</item>
<item name="android:paddingBottom">6dp</item>
<item name="android:paddingLeft">8dp</item>
<item name="android:paddingRight">8dp</item>
<item name="android:textColor">@android:color/primary_text_light</item>
<item name="android:paddingTop">6dp</item>
</style>
<!-- stats large label -->
<style name="StatsLargeLabel" parent="@style/TextSmall">
<item name="android:gravity">right</item>
<item name="android:layout_gravity">right</item>
<item name="android:singleLine">false</item>
<item name="android:textColor">@color/stats_large_label</item>
<item name="android:textStyle">bold</item>
</style>
<!-- stats large value -->
<style name="StatsLargeValue">
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_width">wrap_content</item>
<item name="android:singleLine">true</item>
<item name="android:textColor">@android:color/white</item>
<item name="android:textSize">32sp</item>
<item name="android:textStyle">bold</item>
</style>
<!-- stats large value container -->
<style name="StatsLargeValueContainer">
<item name="android:layout_gravity">right</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_marginTop">-4dp</item>
<item name="android:layout_width">wrap_content</item>
</style>
<!-- stats scroll view -->
<style name="StatsScrollView" parent="@style/ScrollView">
<item name="android:scrollbarStyle">outsideOverlay</item>
</style>
<!-- stats small item container -->
<style name="StatsSmallItemContainer" parent="@style/StatsLargeItemContainer">
<item name="android:paddingTop">12dp</item>
</style>
<!-- stats small label -->
<style name="StatsSmallLabel" parent="@style/TextSmall">
<item name="android:gravity">right</item>
<item name="android:layout_gravity">right</item>
<item name="android:singleLine">false</item>
<item name="android:textStyle">bold</item>
</style>
<!-- stats small value -->
<style name="StatsSmallValue" parent="@style/TextLarge">
<item name="android:singleLine">true</item>
<item name="android:textColor">@android:color/white</item>
</style>
<!-- stats small value container -->
<style name="StatsSmallValueContainer" parent="@style/StatsLargeValueContainer">
<item name="android:layout_marginTop">-2dp</item>
</style>
<!-- stats unit -->
<style name="StatsUnit" parent="@style/TextSmall">
<item name="android:paddingLeft">4dp</item>
<item name="android:singleLine">true</item>
</style>
<!-- stats vertical spacer -->
<style name="StatsVerticalSpacer">
<item name="android:layout_height">match_parent</item>
<item name="android:layout_weight">1</item>
<item name="android:layout_width">0dp</item>
</style>
<!-- text choose activity -->
<style name="TextChooseActivity">
@@ -239,7 +297,7 @@ limitations under the License.
</style>
<!-- track widget horizontal line -->
<style name="TrackWidgetHorizontalLine">
<item name="android:background">@color/track_widget_line</item>
<item name="android:background">@color/stats_separator</item>
<item name="android:layout_height">1dp</item>
<item name="android:layout_width">0dp</item>
</style>
@@ -285,7 +343,7 @@ limitations under the License.
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_width">wrap_content</item>
<item name="android:singleLine">true</item>
<item name="android:textColor">@color/track_widget_label</item>
<item name="android:textColor">@color/stats_large_label</item>
<item name="android:textSize">10dp</item>
<item name="android:textStyle">bold</item>
</style>
@@ -342,7 +400,7 @@ limitations under the License.
<item name="android:textSize">18dp</item>
</style>
<!-- track widget value -->
<style name="TrackWidgetValue">
<style name="TrackWidgetValue">
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_weight">2</item>
<item name="android:layout_width">0dp</item>
@@ -373,7 +431,7 @@ limitations under the License.
</style>
<!-- track widget vertical line -->
<style name="TrackWidgetVerticalLine">
<item name="android:background">@color/track_widget_line</item>
<item name="android:background">@color/stats_separator</item>
<item name="android:layout_height">0dp</item>
<item name="android:layout_width">1dp</item>
</style>
+2 -10
View File
@@ -29,16 +29,8 @@ limitations under the License.
<PreferenceCategory android:title="@string/settings_show" >
<CheckBoxPreference
android:defaultValue="false"
android:key="@string/stats_show_moving_time_key"
android:title="@string/stats_moving_time" />
<CheckBoxPreference
android:defaultValue="false"
android:key="@string/stats_show_elevation_key"
android:title="@string/stats_elevation" />
<CheckBoxPreference
android:defaultValue="false"
android:key="@string/stats_show_grade_key"
android:title="@string/settings_stats_grade" />
android:key="@string/stats_show_grade_elevation_key"
android:title="@string/settings_stats_grade_elevation" />
<CheckBoxPreference
android:defaultValue="false"
android:key="@string/stats_show_coordinate_key"
@@ -26,6 +26,7 @@ import com.google.android.apps.mytracks.fragments.ChooseActivityDialogFragment;
import com.google.android.apps.mytracks.fragments.ChooseActivityDialogFragment.ChooseActivityCaller;
import com.google.android.apps.mytracks.fragments.ConfirmDialogFragment;
import com.google.android.apps.mytracks.fragments.ConfirmDialogFragment.ConfirmCaller;
import com.google.android.apps.mytracks.fragments.InstallEarthDialogFragment;
import com.google.android.apps.mytracks.io.drive.SendDriveActivity;
import com.google.android.apps.mytracks.io.file.SaveActivity;
import com.google.android.apps.mytracks.io.file.TrackFileFormat;
@@ -39,6 +40,7 @@ import com.google.android.apps.mytracks.io.sendtogoogle.UploadResultActivity;
import com.google.android.apps.mytracks.io.spreadsheets.SendSpreadsheetsActivity;
import com.google.android.apps.mytracks.io.sync.SyncUtils;
import com.google.android.apps.mytracks.util.AnalyticsUtils;
import com.google.android.apps.mytracks.util.GoogleEarthUtils;
import com.google.android.apps.mytracks.util.IntentUtils;
import com.google.android.apps.mytracks.util.PreferencesUtils;
import com.google.android.apps.mytracks.util.StringUtils;
@@ -338,6 +340,28 @@ public abstract class AbstractSendToGoogleActivity extends AbstractMyTracksActiv
Toast.makeText(this, R.string.send_google_no_account_permission, Toast.LENGTH_LONG).show();
}
/**
* Confirm playing tracks in Google Earth.
*
* @param trackIds the track ids
*/
protected void confirmPlay(long[] trackIds) {
if (GoogleEarthUtils.isEarthInstalled(this)) {
ConfirmDialogFragment.newInstance(R.string.confirm_play_earth_key,
PreferencesUtils.CONFIRM_PLAY_EARTH_DEFAULT,
getString(R.string.track_detail_play_confirm_message), trackIds)
.show(getSupportFragmentManager(), ConfirmDialogFragment.CONFIRM_DIALOG_TAG);
} else {
new InstallEarthDialogFragment().show(
getSupportFragmentManager(), InstallEarthDialogFragment.INSTALL_EARTH_DIALOG_TAG);
}
}
/**
* Confirm sharing a track.
*
* @param trackId the track id
*/
protected void confirmShare(long trackId) {
String shareTrack = PreferencesUtils.getString(
this, R.string.share_track_key, PreferencesUtils.SHARE_TRACK_DEFAULT);
@@ -346,35 +370,46 @@ public abstract class AbstractSendToGoogleActivity extends AbstractMyTracksActiv
if (shareTrack.equals(driveValue)) {
ConfirmDialogFragment.newInstance(R.string.confirm_share_drive_key,
PreferencesUtils.CONFIRM_SHARE_DRIVE_DEFAULT,
getString(R.string.share_track_drive_confirm_message), trackId)
getString(R.string.share_track_drive_confirm_message), new long[] { trackId })
.show(getSupportFragmentManager(), ConfirmDialogFragment.CONFIRM_DIALOG_TAG);
} else if (shareTrack.equals(mapsValue)) {
ConfirmDialogFragment.newInstance(R.string.confirm_share_maps_key,
PreferencesUtils.CONFIRM_SHARE_MAPS_DEFAULT, StringUtils.getHtml(
this, R.string.share_track_maps_confirm_message, R.string.maps_public_unlisted_url),
trackId).show(getSupportFragmentManager(), ConfirmDialogFragment.CONFIRM_DIALOG_TAG);
new long[] { trackId })
.show(getSupportFragmentManager(), ConfirmDialogFragment.CONFIRM_DIALOG_TAG);
} else {
ConfirmDialogFragment.newInstance(R.string.confirm_share_file_key,
PreferencesUtils.CONFIRM_SHARE_FILE_DEFAULT,
getString(R.string.share_track_file_confirm_message), trackId)
getString(R.string.share_track_file_confirm_message), new long[] { trackId })
.show(getSupportFragmentManager(), ConfirmDialogFragment.CONFIRM_DIALOG_TAG);
}
}
@Override
public void onConfirmDone(int confirmId, long trackId) {
public void onConfirmDone(int confirmId, long[] trackIds) {
Intent intent;
SendRequest newRequest;
switch (confirmId) {
case R.string.confirm_play_earth_key:
AnalyticsUtils.sendPageViews(this, "/action/play");
intent = IntentUtils.newIntent(this, SaveActivity.class)
.putExtra(SaveActivity.EXTRA_TRACK_IDS, trackIds)
.putExtra(SaveActivity.EXTRA_TRACK_FILE_FORMAT, (Parcelable) TrackFileFormat.KML)
.putExtra(SaveActivity.EXTRA_PLAY_TRACK, true);
startActivity(intent);
break;
case R.string.confirm_share_drive_key:
AnalyticsUtils.sendPageViews(this, "/action/share_drive");
newRequest = new SendRequest(trackId);
newRequest = new SendRequest(trackIds[0]);
newRequest.setSendDrive(true);
newRequest.setDriveShare(true);
sendToGoogle(newRequest);
break;
case R.string.confirm_share_maps_key:
AnalyticsUtils.sendPageViews(this, "/action/share_maps");
newRequest = new SendRequest(trackId);
newRequest = new SendRequest(trackIds[0]);
newRequest.setSendMaps(true);
newRequest.setMapsShare(true);
sendToGoogle(newRequest);
@@ -392,8 +427,8 @@ public abstract class AbstractSendToGoogleActivity extends AbstractMyTracksActiv
} else {
trackFileFormat = TrackFileFormat.TCX;
}
Intent intent = IntentUtils.newIntent(this, SaveActivity.class)
.putExtra(SaveActivity.EXTRA_TRACK_ID, trackId)
intent = IntentUtils.newIntent(this, SaveActivity.class)
.putExtra(SaveActivity.EXTRA_TRACK_IDS, trackIds)
.putExtra(SaveActivity.EXTRA_TRACK_FILE_FORMAT, (Parcelable) trackFileFormat)
.putExtra(SaveActivity.EXTRA_SHARE_TRACK, true);
startActivity(intent);
@@ -42,7 +42,7 @@ public class AggregatedStatsActivity extends AbstractMyTracksActivity {
@Override
protected int getLayoutResId() {
return R.layout.aggregated_stats;
return R.layout.stats;
}
/**
@@ -70,6 +70,7 @@ public class MarkerListActivity extends AbstractMyTracksActivity implements Dele
contextualActionModeCallback = new ContextualActionModeCallback() {
@Override
public void onPrepare(Menu menu, int[] positions, long[] ids) {
menu.findItem(R.id.list_context_menu_play).setVisible(false);
menu.findItem(R.id.list_context_menu_share).setVisible(false);
menu.findItem(R.id.list_context_menu_show_on_map).setVisible(ids.length == 1);
menu.findItem(R.id.list_context_menu_edit)
@@ -142,6 +142,9 @@ public class SearchListActivity extends AbstractSendToGoogleActivity
shareWithMe = track.isSharedWithMe();
markerId = (Long) item.get(MARKER_ID_FIELD);
}
// Only one item, the item is a track
menu.findItem(R.id.list_context_menu_play)
.setVisible(positions.length == 1 && markerId == null);
// Only one item, the item is a track, and the item is not a sharedWithMe track
menu.findItem(R.id.list_context_menu_share)
.setVisible(positions.length == 1 && markerId == null && !shareWithMe);
@@ -338,6 +341,9 @@ public class SearchListActivity extends AbstractSendToGoogleActivity
Long markerId = (Long) item.get(MARKER_ID_FIELD);
Intent intent;
switch (itemId) {
case R.id.list_context_menu_play:
confirmPlay(new long[] {trackId});
return true;
case R.id.list_context_menu_share:
confirmShare(trackId);
return true;
@@ -24,13 +24,11 @@ import com.google.android.apps.mytracks.content.WaypointCreationRequest;
import com.google.android.apps.mytracks.fragments.ChartFragment;
import com.google.android.apps.mytracks.fragments.ChooseUploadServiceDialogFragment;
import com.google.android.apps.mytracks.fragments.ChooseUploadServiceDialogFragment.ChooseUploadServiceCaller;
import com.google.android.apps.mytracks.fragments.ConfirmDialogFragment;
import com.google.android.apps.mytracks.fragments.DeleteTrackDialogFragment;
import com.google.android.apps.mytracks.fragments.DeleteTrackDialogFragment.DeleteTrackCaller;
import com.google.android.apps.mytracks.fragments.FileTypeDialogFragment;
import com.google.android.apps.mytracks.fragments.FileTypeDialogFragment.FileTypeCaller;
import com.google.android.apps.mytracks.fragments.FrequencyDialogFragment;
import com.google.android.apps.mytracks.fragments.InstallEarthDialogFragment;
import com.google.android.apps.mytracks.fragments.MyTracksMapFragment;
import com.google.android.apps.mytracks.fragments.StatsFragment;
import com.google.android.apps.mytracks.io.file.SaveActivity;
@@ -49,8 +47,6 @@ import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.Bundle;
import android.os.Parcelable;
import android.support.v4.app.TaskStackBuilder;
@@ -64,7 +60,6 @@ import android.view.View.OnClickListener;
import android.widget.TabHost;
import android.widget.TabHost.TabSpec;
import java.util.List;
import java.util.Locale;
/**
@@ -319,7 +314,7 @@ public class TrackDetailActivity extends AbstractSendToGoogleActivity
splitFrequencyMenuItem = menu.findItem(R.id.track_detail_split_frequency);
feedbackMenuItem = menu.findItem(R.id.track_detail_split_frequency);
feedbackMenuItem.setVisible(GoogleFeedbackUtils.isAvailable(this));
updateMenuItems(trackId == recordingTrackId, recordingTrackPaused);
return true;
}
@@ -344,18 +339,10 @@ public class TrackDetailActivity extends AbstractSendToGoogleActivity
startActivity(intent);
return true;
case R.id.track_detail_play:
if (isEarthInstalled()) {
ConfirmDialogFragment.newInstance(R.string.confirm_play_earth_key,
PreferencesUtils.CONFIRM_PLAY_EARTH_DEFAULT,
getString(R.string.track_detail_play_confirm_message), trackId)
.show(getSupportFragmentManager(), ConfirmDialogFragment.CONFIRM_DIALOG_TAG);
} else {
new InstallEarthDialogFragment().show(
getSupportFragmentManager(), InstallEarthDialogFragment.INSTALL_EARTH_DIALOG_TAG);
}
confirmPlay(new long[] {trackId});
return true;
case R.id.track_detail_share:
confirmShare(trackId);
confirmShare(trackId);
return true;
case R.id.track_detail_markers:
intent = IntentUtils.newIntent(this, MarkerListActivity.class)
@@ -384,7 +371,7 @@ public class TrackDetailActivity extends AbstractSendToGoogleActivity
FileTypeDialogFragment.newInstance(R.id.track_detail_save, R.string.save_selection_title,
R.string.save_selection_option, 4)
.show(getSupportFragmentManager(), FileTypeDialogFragment.FILE_TYPE_DIALOG_TAG);
return true;
return true;
case R.id.track_detail_edit:
intent = IntentUtils.newIntent(this, TrackEditActivity.class)
.putExtra(TrackEditActivity.EXTRA_TRACK_ID, trackId);
@@ -426,22 +413,6 @@ public class TrackDetailActivity extends AbstractSendToGoogleActivity
return super.onTrackballEvent(event);
}
@Override
public void onConfirmDone(int confirmId, long confirmTrackId) {
switch (confirmId) {
case R.string.confirm_play_earth_key:
AnalyticsUtils.sendPageViews(this, "/action/play");
Intent intent = IntentUtils.newIntent(this, SaveActivity.class)
.putExtra(SaveActivity.EXTRA_TRACK_ID, confirmTrackId)
.putExtra(SaveActivity.EXTRA_TRACK_FILE_FORMAT, (Parcelable) TrackFileFormat.KML)
.putExtra(SaveActivity.EXTRA_PLAY_TRACK, true);
startActivity(intent);
break;
default:
super.onConfirmDone(confirmId, confirmTrackId);
}
}
@Override
public void onChooseUploadServiceDone(boolean sendDrive, boolean sendMaps,
boolean sendFusionTables, boolean sendSpreadsheets, boolean mapsExistingMap) {
@@ -480,7 +451,7 @@ public class TrackDetailActivity extends AbstractSendToGoogleActivity
}
});
}
@Override
public void onFileTypeDone(int menuId, TrackFileFormat trackFileFormat) {
switch (menuId) {
@@ -488,7 +459,7 @@ public class TrackDetailActivity extends AbstractSendToGoogleActivity
AnalyticsUtils.sendPageViews(
this, "/action/save_" + trackFileFormat.name().toLowerCase(Locale.US));
Intent intent = IntentUtils.newIntent(this, SaveActivity.class)
.putExtra(SaveActivity.EXTRA_TRACK_ID, trackId)
.putExtra(SaveActivity.EXTRA_TRACK_IDS, new long[] {trackId})
.putExtra(SaveActivity.EXTRA_TRACK_FILE_FORMAT, (Parcelable) trackFileFormat);
startActivity(intent);
break;
@@ -590,20 +561,4 @@ public class TrackDetailActivity extends AbstractSendToGoogleActivity
}
setTitle(title);
}
/**
* Returns true if Google Earth app is installed.
*/
private boolean isEarthInstalled() {
List<ResolveInfo> infos = getPackageManager().queryIntentActivities(
new Intent().setType(SaveActivity.GOOGLE_EARTH_KML_MIME_TYPE),
PackageManager.MATCH_DEFAULT_ONLY);
for (ResolveInfo info : infos) {
if (info.activityInfo != null && info.activityInfo.packageName != null
&& info.activityInfo.packageName.equals(SaveActivity.GOOGLE_EARTH_PACKAGE)) {
return true;
}
}
return false;
}
}
@@ -366,13 +366,13 @@ public class TrackListActivity extends AbstractSendToGoogleActivity
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (BuildConfig.DEBUG) {
ApiAdapterFactory.getApiAdapter().enableStrictMode();
}
Intent intent = new Intent(this, RemoveTempFilesService.class);
startService(intent);
startService(intent);
myTracksProviderUtils = MyTracksProviderUtils.Factory.get(this);
sharedPreferences = getSharedPreferences(Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
@@ -385,13 +385,13 @@ public class TrackListActivity extends AbstractSendToGoogleActivity
setDefaultKeyMode(DEFAULT_KEYS_SEARCH_LOCAL);
// Show trackController when search dialog is dismissed
SearchManager searchManager = (SearchManager) getSystemService(SEARCH_SERVICE);
searchManager.setOnDismissListener(new SearchManager.OnDismissListener() {
searchManager.setOnDismissListener(new SearchManager.OnDismissListener() {
@Override
public void onDismiss() {
trackController.show();
trackController.show();
}
});
listView = (ListView) findViewById(R.id.track_list);
listView.setEmptyView(findViewById(R.id.track_list_empty_view));
listView.setOnItemClickListener(new OnItemClickListener() {
@@ -415,7 +415,7 @@ public class TrackListActivity extends AbstractSendToGoogleActivity
int startTimeIndex = cursor.getColumnIndexOrThrow(TracksColumns.STARTTIME);
int descriptionIndex = cursor.getColumnIndex(TracksColumns.DESCRIPTION);
int sharedOwnerIndex = cursor.getColumnIndex(TracksColumns.SHAREDOWNER);
boolean isRecording = cursor.getLong(idIndex) == recordingTrackId;
String icon = cursor.getString(iconIndex);
int iconId = TrackIconUtils.getIconDrawable(icon);
@@ -540,13 +540,13 @@ public class TrackListActivity extends AbstractSendToGoogleActivity
@Override
protected boolean configureActionBarHomeAsUp() {
return false;
return false;
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.track_list, menu);
searchMenuItem = menu.findItem(R.id.track_list_search);
startGpsMenuItem = menu.findItem(R.id.track_list_start_gps);
importAllMenuItem = menu.findItem(R.id.track_list_import_all);
@@ -620,7 +620,7 @@ public class TrackListActivity extends AbstractSendToGoogleActivity
return super.onOptionsItemSelected(item);
}
}
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
@@ -649,7 +649,7 @@ public class TrackListActivity extends AbstractSendToGoogleActivity
}
return super.onKeyUp(keyCode, event);
}
@Override
public boolean onSearchRequested() {
// Hide trackController when search dialog is shown
@@ -666,7 +666,7 @@ public class TrackListActivity extends AbstractSendToGoogleActivity
public void onDeleteTrackDone() {
// Do nothing
}
@Override
public void onFileTypeDone(int menuId, TrackFileFormat trackFileFormat) {
Intent intent;
@@ -675,6 +675,7 @@ public class TrackListActivity extends AbstractSendToGoogleActivity
AnalyticsUtils.sendPageViews(
this, "/action/save_all_" + trackFileFormat.name().toLowerCase(Locale.US));
intent = IntentUtils.newIntent(this, SaveActivity.class)
.putExtra(SaveActivity.EXTRA_TRACK_IDS, new long[] {-1L})
.putExtra(SaveActivity.EXTRA_TRACK_FILE_FORMAT, (Parcelable) trackFileFormat);
startActivity(intent);
break;
@@ -718,7 +719,7 @@ public class TrackListActivity extends AbstractSendToGoogleActivity
showStartupDialogs();
return;
}
finish();
finish();
}
private void checkGooglePlayServices() {
@@ -812,6 +813,9 @@ public class TrackListActivity extends AbstractSendToGoogleActivity
*/
private boolean handleContextItem(int itemId, long[] trackIds) {
switch (itemId) {
case R.id.list_context_menu_play:
confirmPlay(trackIds);
return true;
case R.id.list_context_menu_share:
confirmShare(trackIds[0]);
return true;
@@ -47,7 +47,7 @@ public class ConfirmDialogFragment extends DialogFragment {
/**
* Called when confirm is done.
*/
public void onConfirmDone(int confirmId, long trackId);
public void onConfirmDone(int confirmId, long[] trackIds);
}
public static final String CONFIRM_DIALOG_TAG = "confirmDialog";
@@ -55,17 +55,17 @@ public class ConfirmDialogFragment extends DialogFragment {
private static final String KEY_CONFIRM_ID = "confirmId";
private static final String KEY_DEFAULT_VALUE = "defaultValue";
private static final String KEY_MESSAGE = "message";
private static final String KEY_TRACK_ID = "trackId";
private static final String KEY_TRACK_IDS = "trackIds";
private CheckBox checkBox;
public static ConfirmDialogFragment newInstance(
int confirmId, boolean defaultValue, CharSequence message, long trackId) {
int confirmId, boolean defaultValue, CharSequence message, long[] trackIds) {
Bundle bundle = new Bundle();
bundle.putInt(KEY_CONFIRM_ID, confirmId);
bundle.putBoolean(KEY_DEFAULT_VALUE, defaultValue);
bundle.putCharSequence(KEY_MESSAGE, message);
bundle.putLong(KEY_TRACK_ID, trackId);
bundle.putLongArray(KEY_TRACK_IDS, trackIds);
ConfirmDialogFragment confirmDialogFragment = new ConfirmDialogFragment();
confirmDialogFragment.setArguments(bundle);
@@ -93,9 +93,9 @@ public class ConfirmDialogFragment extends DialogFragment {
boolean defaultValue = getArguments().getBoolean(KEY_DEFAULT_VALUE);
fragmentActivity = getActivity();
if (!PreferencesUtils.getBoolean(fragmentActivity, confirmId, defaultValue)) {
long trackId = getArguments().getLong(KEY_TRACK_ID);
long[] trackIds = getArguments().getLongArray(KEY_TRACK_IDS);
dismiss();
caller.onConfirmDone(confirmId, trackId);
caller.onConfirmDone(confirmId, trackIds);
}
}
@@ -106,15 +106,14 @@ public class ConfirmDialogFragment extends DialogFragment {
textView.setText(getArguments().getCharSequence(KEY_MESSAGE));
checkBox = (CheckBox) view.findViewById(R.id.confirm_dialog_check_box);
return new AlertDialog.Builder(fragmentActivity).setNegativeButton(
R.string.generic_no, null)
return new AlertDialog.Builder(fragmentActivity).setNegativeButton(R.string.generic_no, null)
.setPositiveButton(R.string.generic_yes, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
int confirmId = getArguments().getInt(KEY_CONFIRM_ID);
long trackId = getArguments().getLong(KEY_TRACK_ID);
long[] trackIds = getArguments().getLongArray(KEY_TRACK_IDS);
PreferencesUtils.setBoolean(fragmentActivity, confirmId, !checkBox.isChecked());
caller.onConfirmDone(confirmId, trackId);
caller.onConfirmDone(confirmId, trackIds);
}
}).setTitle(R.string.generic_confirm_title).setView(view).create();
}
@@ -87,6 +87,13 @@ public class EnableSyncDialogFragment extends DialogFragment {
}).setPositiveButton(R.string.generic_yes, new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
/*
* google_account_key can be set from the android backup service. If
* the user wants to enable sync, make sure google_account_key is
* cleared so the user can choose an account.
*/
PreferencesUtils.setString(fragmentActivity, R.string.google_account_key,
PreferencesUtils.GOOGLE_ACCOUNT_DEFAULT);
caller.onEnableSyncDone(true);
}
}).setTitle(R.string.enable_sync_title).create();
@@ -16,7 +16,7 @@
package com.google.android.apps.mytracks.fragments;
import com.google.android.apps.mytracks.io.file.SaveActivity;
import com.google.android.apps.mytracks.util.GoogleEarthUtils;
import com.google.android.maps.mytracks.R;
import android.app.AlertDialog;
@@ -32,7 +32,7 @@ import android.widget.Toast;
/**
* A DialogFragment to install Google Earth.
*
*
* @author Jimmy Shih
*/
public class InstallEarthDialogFragment extends DialogFragment {
@@ -40,17 +40,17 @@ public class InstallEarthDialogFragment extends DialogFragment {
public static final String INSTALL_EARTH_DIALOG_TAG = "installEarthDialog";
private FragmentActivity fragmentActivity;
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
fragmentActivity = getActivity();
return new AlertDialog.Builder(fragmentActivity)
.setMessage(R.string.track_detail_install_earth_message)
.setNegativeButton(R.string.generic_no, null)
return new AlertDialog.Builder(fragmentActivity).setMessage(
R.string.track_detail_install_earth_message).setNegativeButton(R.string.generic_no, null)
.setPositiveButton(R.string.generic_yes, new DialogInterface.OnClickListener() {
@Override
@Override
public void onClick(DialogInterface dialog, int which) {
Intent intent = new Intent().setData(Uri.parse(SaveActivity.GOOGLE_EARTH_MARKET_URL));
Intent intent = new Intent().setData(
Uri.parse(GoogleEarthUtils.GOOGLE_EARTH_MARKET_URL));
try {
startActivity(intent);
} catch (ActivityNotFoundException e) {
@@ -59,8 +59,6 @@ public class InstallEarthDialogFragment extends DialogFragment {
.show();
}
}
})
.setTitle(R.string.generic_confirm_title)
.create();
}).setTitle(R.string.generic_confirm_title).create();
}
}
@@ -102,7 +102,7 @@ public class StatsFragment extends Fragment implements TrackDataListener {
public void run() {
if (isResumed()) {
lastLocation = null;
StatsUtils.setLocationValues(getActivity(), lastLocation, true);
StatsUtils.setLocationValues(getActivity(), lastLocation, isSelectedTrackRecording());
}
}
});
@@ -118,11 +118,12 @@ public class StatsFragment extends Fragment implements TrackDataListener {
if (isResumed()) {
if (isSelectedTrackRecording() && !isSelectedTrackPaused()) {
lastLocation = location;
StatsUtils.setLocationValues(getActivity(), location, true);
StatsUtils.setLocationValues(getActivity(), location, isSelectedTrackRecording());
} else {
if (lastLocation != null) {
lastLocation = null;
StatsUtils.setLocationValues(getActivity(), lastLocation, true);
StatsUtils.setLocationValues(
getActivity(), lastLocation, isSelectedTrackRecording());
}
}
}
@@ -277,6 +278,6 @@ public class StatsFragment extends Fragment implements TrackDataListener {
*/
private void updateUi(FragmentActivity activity) {
StatsUtils.setTripStatisticsValues(activity, lastTripStatistics);
StatsUtils.setLocationValues(activity, lastLocation, true);
StatsUtils.setLocationValues(activity, lastLocation, isSelectedTrackRecording());
}
}
@@ -58,7 +58,6 @@ public class CsvTrackWriter implements TrackFormatWriter {
private final Context context;
private PrintWriter printWriter;
private Track track;
private int segmentIndex;
private int pointIndex;
@@ -72,8 +71,7 @@ public class CsvTrackWriter implements TrackFormatWriter {
}
@Override
public void prepare(Track aTrack, OutputStream out) {
track = aTrack;
public void prepare(OutputStream out) {
printWriter = new PrintWriter(out);
segmentIndex = 0;
pointIndex = 0;
@@ -85,7 +83,7 @@ public class CsvTrackWriter implements TrackFormatWriter {
}
@Override
public void writeHeader() {
public void writeHeader(Track track) {
writeCommaSeparatedLine(context.getString(R.string.generic_name),
context.getString(R.string.track_edit_activity_type_hint),
context.getString(R.string.generic_description));
@@ -133,7 +131,7 @@ public class CsvTrackWriter implements TrackFormatWriter {
}
@Override
public void writeBeginTrack(Location firstPoint) {
public void writeBeginTrack(Track track, Location firstPoint) {
writeCommaSeparatedLine(context.getString(R.string.description_track_segment),
context.getString(R.string.description_track_point),
context.getString(R.string.description_location_latitude),
@@ -149,7 +147,7 @@ public class CsvTrackWriter implements TrackFormatWriter {
}
@Override
public void writeEndTrack(Location lastPoint) {
public void writeEndTrack(Track track, Location lastPoint) {
// Do nothing
}
@@ -52,7 +52,6 @@ public class GpxTrackWriter implements TrackFormatWriter {
}
private final Context context;
private Track track;
private PrintWriter printWriter;
public GpxTrackWriter(Context context) {
@@ -65,8 +64,7 @@ public class GpxTrackWriter implements TrackFormatWriter {
}
@Override
public void prepare(Track aTrack, OutputStream outputStream) {
this.track = aTrack;
public void prepare(OutputStream outputStream) {
this.printWriter = new PrintWriter(outputStream);
}
@@ -79,7 +77,7 @@ public class GpxTrackWriter implements TrackFormatWriter {
}
@Override
public void writeHeader() {
public void writeHeader(Track track) {
if (printWriter != null) {
printWriter.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
printWriter.println("<gpx");
@@ -109,7 +107,7 @@ public class GpxTrackWriter implements TrackFormatWriter {
}
@Override
public void writeBeginTrack(Location firstLocation) {
public void writeBeginTrack(Track track, Location firstLocation) {
if (printWriter != null) {
printWriter.println("<trk>");
printWriter.println("<name>" + StringUtils.formatCData(track.getName()) + "</name>");
@@ -120,7 +118,7 @@ public class GpxTrackWriter implements TrackFormatWriter {
}
@Override
public void writeEndTrack(Location lastLocation) {
public void writeEndTrack(Track track, Location lastLocation) {
if (printWriter != null) {
printWriter.println("</trk>");
}
@@ -24,6 +24,7 @@ import com.google.android.apps.mytracks.content.Sensor.SensorDataSet;
import com.google.android.apps.mytracks.content.Track;
import com.google.android.apps.mytracks.content.Waypoint;
import com.google.android.apps.mytracks.content.Waypoint.WaypointType;
import com.google.android.apps.mytracks.util.GoogleEarthUtils;
import com.google.android.apps.mytracks.util.StringUtils;
import com.google.android.maps.mytracks.R;
import com.google.common.annotations.VisibleForTesting;
@@ -42,11 +43,6 @@ import java.util.ArrayList;
*/
public class KmlTrackWriter implements TrackFormatWriter {
/**
* ID of the KML feature to play a tour.
*/
public static final String TOUR_FEATURE_ID = "tour";
private static final String WAYPOINT_STYLE = "waypoint";
private static final String STATISTICS_STYLE = "statistics";
private static final String START_STYLE = "start";
@@ -70,7 +66,6 @@ public class KmlTrackWriter implements TrackFormatWriter {
private final Context context;
private final DescriptionGenerator descriptionGenerator;
private Track track;
private PrintWriter printWriter;
private ArrayList<Integer> powerList = new ArrayList<Integer>();
private ArrayList<Integer> cadenceList = new ArrayList<Integer>();
@@ -95,8 +90,7 @@ public class KmlTrackWriter implements TrackFormatWriter {
}
@Override
public void prepare(Track aTrack, OutputStream outputStream) {
this.track = aTrack;
public void prepare(OutputStream outputStream) {
this.printWriter = new PrintWriter(outputStream);
}
@@ -109,12 +103,12 @@ public class KmlTrackWriter implements TrackFormatWriter {
}
@Override
public void writeHeader() {
public void writeHeader(Track track) {
if (printWriter != null) {
printWriter.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
printWriter.println("<kml xmlns=\"http://www.opengis.net/kml/2.2\"");
printWriter.println("xmlns:gx=\"http://www.google.com/kml/ext/2.2\"");
printWriter.println("xmlns:atom=\"http://www.w3.org/2005/Atom\">");
printWriter.println("xmlns:atom=\"http://www.w3.org/2005/Atom\">");
printWriter.println("<Document>");
printWriter.println("<open>1</open>");
printWriter.println("<visibility>1</visibility>");
@@ -170,11 +164,11 @@ public class KmlTrackWriter implements TrackFormatWriter {
}
@Override
public void writeBeginTrack(Location firstLocation) {
public void writeBeginTrack(Track track, Location firstLocation) {
if (printWriter != null) {
String name = context.getString(R.string.marker_label_start, track.getName());
writePlacemark(name, "", "", START_STYLE, firstLocation);
printWriter.println("<Placemark id=\"" + TOUR_FEATURE_ID + "\">");
printWriter.println("<Placemark id=\"" + GoogleEarthUtils.TOUR_FEATURE_ID_VALUE + "\">");
printWriter.println("<name>" + StringUtils.formatCData(track.getName()) + "</name>");
printWriter.println(
"<description>" + StringUtils.formatCData(track.getDescription()) + "</description>");
@@ -187,7 +181,7 @@ public class KmlTrackWriter implements TrackFormatWriter {
}
@Override
public void writeEndTrack(Location lastLocation) {
public void writeEndTrack(Track track, Location lastLocation) {
if (printWriter != null) {
printWriter.println("</gx:MultiTrack>");
printWriter.println("</Placemark>");
@@ -18,6 +18,7 @@ package com.google.android.apps.mytracks.io.file;
import com.google.android.apps.mytracks.util.DialogUtils;
import com.google.android.apps.mytracks.util.FileUtils;
import com.google.android.apps.mytracks.util.GoogleEarthUtils;
import com.google.android.apps.mytracks.util.IntentUtils;
import com.google.android.maps.mytracks.R;
@@ -27,7 +28,6 @@ import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.widget.Toast;
@@ -42,23 +42,15 @@ import java.io.File;
public class SaveActivity extends Activity {
public static final String EXTRA_TRACK_FILE_FORMAT = "track_file_format";
public static final String EXTRA_TRACK_ID = "track_id";
public static final String EXTRA_TRACK_IDS = "track_ids";
public static final String EXTRA_PLAY_TRACK = "play_track";
public static final String EXTRA_SHARE_TRACK = "share_track";
public static final String GOOGLE_EARTH_KML_MIME_TYPE = "application/vnd.google-earth.kml+xml";
public static final String GOOGLE_EARTH_PACKAGE = "com.google.earth";
public static final String GOOGLE_EARTH_MARKET_URL = "market://details?id="
+ GOOGLE_EARTH_PACKAGE;
private static final String
GOOGLE_EARTH_TOUR_FEATURE_ID = "com.google.earth.EXTRA.tour_feature_id";
private static final String GOOGLE_EARTH_CLASS = "com.google.earth.EarthActivity";
private static final int DIALOG_PROGRESS_ID = 0;
private static final int DIALOG_RESULT_ID = 1;
private TrackFileFormat trackFileFormat;
private long trackId;
private long[] trackIds;
private boolean playTrack;
private boolean shareTrack;
private String directoryName;
@@ -78,7 +70,7 @@ public class SaveActivity extends Activity {
Intent intent = getIntent();
trackFileFormat = intent.getParcelableExtra(EXTRA_TRACK_FILE_FORMAT);
trackId = intent.getLongExtra(EXTRA_TRACK_ID, -1L);
trackIds = intent.getLongArrayExtra(EXTRA_TRACK_IDS);
playTrack = intent.getBooleanExtra(EXTRA_PLAY_TRACK, false);
shareTrack = intent.getBooleanExtra(EXTRA_SHARE_TRACK, false);
@@ -104,7 +96,7 @@ public class SaveActivity extends Activity {
saveAsyncTask = (SaveAsyncTask) retained;
saveAsyncTask.setActivity(this);
} else {
saveAsyncTask = new SaveAsyncTask(this, trackFileFormat, trackId, directory);
saveAsyncTask = new SaveAsyncTask(this, trackFileFormat, trackIds, directory);
saveAsyncTask.execute();
}
}
@@ -175,23 +167,17 @@ public class SaveActivity extends Activity {
removeDialog(DIALOG_PROGRESS_ID);
if (successCount == 1 && totalCount == 1 && savedPath != null) {
if (playTrack) {
Intent intent = new Intent().addFlags(
Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK)
.putExtra(GOOGLE_EARTH_TOUR_FEATURE_ID, KmlTrackWriter.TOUR_FEATURE_ID)
.setClassName(GOOGLE_EARTH_PACKAGE, GOOGLE_EARTH_CLASS)
.setDataAndType(Uri.fromFile(new File(savedPath)), GOOGLE_EARTH_KML_MIME_TYPE);
startActivity(intent);
startActivity(GoogleEarthUtils.getPlayInEarthIntent(savedPath));
finish();
return;
} else if (shareTrack) {
Intent intent = IntentUtils.newShareFileIntent(this, trackId, savedPath, trackFileFormat);
startActivity(
Intent.createChooser(intent, getString(R.string.share_track_picker_title)));
Intent intent = IntentUtils.newShareFileIntent(this, trackIds[0], savedPath, trackFileFormat);
startActivity(Intent.createChooser(intent, getString(R.string.share_track_picker_title)));
finish();
return;
}
}
}
showDialog(DIALOG_RESULT_ID);
showDialog(DIALOG_RESULT_ID);
}
/**
@@ -46,7 +46,7 @@ public class SaveAsyncTask extends AsyncTask<Void, Integer, Boolean> {
private SaveActivity saveActivity;
private final TrackFileFormat trackFileFormat;
private final long trackId;
private final long[] trackIds;
private final File directory;
private final Context context;
private final MyTracksProviderUtils myTracksProviderUtils;
@@ -75,10 +75,10 @@ public class SaveAsyncTask extends AsyncTask<Void, Integer, Boolean> {
* @param directory the directory to save to
*/
public SaveAsyncTask(
SaveActivity saveActivity, TrackFileFormat trackFileFormat, long trackId, File directory) {
SaveActivity saveActivity, TrackFileFormat trackFileFormat, long[] trackIds, File directory) {
this.saveActivity = saveActivity;
this.trackFileFormat = trackFileFormat;
this.trackId = trackId;
this.trackIds = trackIds;
this.directory = directory;
context = saveActivity.getApplicationContext();
myTracksProviderUtils = MyTracksProviderUtils.Factory.get(context);
@@ -118,16 +118,24 @@ public class SaveAsyncTask extends AsyncTask<Void, Integer, Boolean> {
@Override
protected Boolean doInBackground(Void... params) {
try {
if (trackId != -1L) {
if (trackIds.length == 1 && trackIds[0] == -1L) {
return saveAllTracks();
} else {
totalCount = 1;
if (saveOneTrack(trackId)) {
Track[] tracks = new Track[trackIds.length];
for (int i = 0; i < trackIds.length; i++) {
tracks[i] = myTracksProviderUtils.getTrack(trackIds[i]);
if (tracks[i] == null) {
Log.d(TAG, "No track for " + trackIds[i]);
return false;
}
}
if (saveTracks(tracks)) {
successCount = 1;
return true;
} else {
return false;
}
} else {
return saveAllTracks();
}
} finally {
// Release the wake lock if obtained
@@ -160,17 +168,15 @@ public class SaveAsyncTask extends AsyncTask<Void, Integer, Boolean> {
}
/**
* Saves one track.
* Saves tracks to one file.
*
* @param id the track id
* @param tracks the tracks
*/
private Boolean saveOneTrack(long id) {
Track track = myTracksProviderUtils.getTrack(id);
if (track == null) {
Log.d(TAG, "No track for " + id);
private Boolean saveTracks(Track[] tracks) {
if (tracks.length == 0) {
return false;
}
Track track = tracks[0];
// Make sure the file doesn't exist yet (possibly by changing the filename)
String fileName = FileUtils.buildUniqueFileName(
directory, track.getName(), trackFileFormat.getExtension());
@@ -178,21 +184,21 @@ public class SaveAsyncTask extends AsyncTask<Void, Integer, Boolean> {
Log.d(TAG, "Unable to get a unique filename for " + track.getName());
return false;
}
trackWriter = new TrackWriter(
context, myTracksProviderUtils, track, trackFileFormat, new TrackWriter.OnWriteListener() {
context, myTracksProviderUtils, tracks, trackFileFormat, new TrackWriter.OnWriteListener() {
@Override
public void onWrite(int number, int max) {
/*
* If only saving one track, update the progress dialog once every
* 500 points
*/
if (trackId != -1L && number % 500 == 0) {
if (trackIds.length == 1 && trackIds[0] != -1L && number % 500 == 0) {
publishProgress(number, max);
}
}
});
File file = null;
try {
file = new File(directory, fileName);
@@ -201,8 +207,8 @@ public class SaveAsyncTask extends AsyncTask<Void, Integer, Boolean> {
} catch (FileNotFoundException e) {
Log.d(TAG, "File not found " + fileName, e);
return false;
}
}
if (trackWriter.wasSuccess()) {
savedPath = file.getAbsolutePath();
} else {
@@ -224,14 +230,13 @@ public class SaveAsyncTask extends AsyncTask<Void, Integer, Boolean> {
return false;
}
totalCount = cursor.getCount();
int idIndex = cursor.getColumnIndexOrThrow(TracksColumns._ID);
for (int i = 0; i < totalCount; i++) {
if (isCancelled()) {
return false;
}
cursor.moveToPosition(i);
long id = cursor.getLong(idIndex);
if (saveOneTrack(id)) {
Track track = myTracksProviderUtils.createTrack(cursor);
if (track != null && saveTracks(new Track[] { track })) {
successCount++;
}
publishProgress(i + 1, totalCount);
@@ -84,7 +84,6 @@ public class TcxTrackWriter implements TrackFormatWriter {
R.string.activity_type_walking };
private final Context context;
private Track track;
private PrintWriter printWriter;
private SportType sportType;
@@ -93,10 +92,8 @@ public class TcxTrackWriter implements TrackFormatWriter {
}
@Override
public void prepare(Track aTrack, OutputStream out) {
this.track = aTrack;
public void prepare(OutputStream out) {
this.printWriter = new PrintWriter(out);
this.sportType = getSportType(track.getCategory());
}
@Override
@@ -113,7 +110,7 @@ public class TcxTrackWriter implements TrackFormatWriter {
}
@Override
public void writeHeader() {
public void writeHeader(Track track) {
if (printWriter != null) {
printWriter.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
printWriter.println("<TrainingCenterDatabase"
@@ -144,7 +141,8 @@ public class TcxTrackWriter implements TrackFormatWriter {
}
@Override
public void writeBeginTrack(Location firstPoint) {
public void writeBeginTrack(Track track, Location firstPoint) {
sportType = getSportType(track.getCategory());
if (printWriter != null) {
String startTime = StringUtils.formatDateTimeIso8601(
track.getTripStatistics().getStartTime());
@@ -165,7 +163,7 @@ public class TcxTrackWriter implements TrackFormatWriter {
}
@Override
public void writeEndTrack(Location lastPoint) {
public void writeEndTrack(Track track, Location lastPoint) {
if (printWriter != null) {
printWriter.println("</Lap>");
printWriter.println("<Notes>" + StringUtils.formatCData(track.getDescription()) + "</Notes>");
@@ -23,26 +23,30 @@ import android.location.Location;
import java.io.OutputStream;
/**
* Interface for writing a track to file.
* Interface for writing tracks to a file.
*
* The expected sequence of calls is:
* <ol>
* <li>{@link #prepare}
* <li>{@link #writeHeader}
* <li>{@link #writeBeginWaypoints}
* <li>For each waypoint: {@link #writeWaypoint}
* <li>{@link #writeEndWaypoints}
* <li>{@link #writeBeginTrack}
* <li>For each segment:
* <ol>
* <li>{@link #writeOpenSegment}
* <li>For each location in the segment: {@link #writeLocation}
* <li>{@link #writeCloseSegment}
* </ol>
* <li>{@link #writeEndTrack}
* <li>{@link #writeFooter}
* <li>{@link #close}
* </ol>
* <ul>
* <li>{@link #prepare}</li>
* <li>{@link #writeHeader}</li>
* <li>For each track:</li>
* <ul>
* <li>{@link #writeBeginWaypoints}
* <li>For each waypoint: {@link #writeWaypoint}
* <li>{@link #writeEndWaypoints}
* <li>{@link #writeBeginTrack}
* <li>For each segment:
* <ul>
* <li>{@link #writeOpenSegment}</li>
* <li>For each location in the segment: {@link #writeLocation}</li>
* <li>{@link #writeCloseSegment}</li>
* </ul>
* </li>
* <li>{@link #writeEndTrack}</li>
* </ul>
* <li>{@link #writeFooter}</li>
* <li>{@link #close}</li>
* </ul>
*
* @author Rodrigo Damazio
*/
@@ -54,12 +58,11 @@ public interface TrackFormatWriter {
public String getExtension();
/**
* Sets up the writer to write the given track.
* Sets up the file handler.
*
* @param track the track to write
* @param outputStream the output stream to write the track to
* @param outputStream the output stream for the file handler
*/
public void prepare(Track track, OutputStream outputStream);
public void prepare(OutputStream outputStream);
/**
* Closes the underlying file handler.
@@ -67,9 +70,11 @@ public interface TrackFormatWriter {
public void close();
/**
* Writes the header.
* Writes the header for a file
*
* @param track the track
*/
public void writeHeader();
public void writeHeader(Track track);
/**
* Writes the footer.
@@ -96,16 +101,18 @@ public interface TrackFormatWriter {
/**
* Writes the beginning of the track.
*
* @param track the track
* @param firstLocation the first location
*/
public void writeBeginTrack(Location firstLocation);
public void writeBeginTrack(Track track, Location firstLocation);
/**
* Writes the end of the track.
*
* @param track the track
* @param lastLocation the last location
*/
public void writeEndTrack(Location lastLocation);
public void writeEndTrack(Track track, Location lastLocation);
/**
* Writes the statements necessary to open a new segment.
@@ -33,7 +33,7 @@ import android.util.Log;
import java.io.OutputStream;
/**
* Track Writer for writing a track to an {@link OutputStream}.
* Track Writer for writing tracks to an {@link OutputStream}.
*
* @author Sandor Dornbush
* @author Rodrigo Damazio
@@ -49,7 +49,7 @@ public class TrackWriter {
* When a track location is written.
*
* @param number the location number
* @param max the maximum number of locations, for calculation of completion
* @param max the maximum number of locations in a track, for calculation of completion
* percentage
*/
public void onWrite(int number, int max);
@@ -58,7 +58,7 @@ public class TrackWriter {
private final static String TAG = TrackWriter.class.getSimpleName();
private final MyTracksProviderUtils myTracksProviderUtils;
private final Track track;
private final Track[] tracks;
private final TrackFormatWriter trackFormatWriter;
private final OnWriteListener onWriteListener;
@@ -70,20 +70,20 @@ public class TrackWriter {
*
* @param context the context
* @param myTracksProviderUtils the my tracks provider utils
* @param track the track
* @param tracks the tracks
* @param trackFileFormat the track file format
* @param onWriteListener the on write listener
*/
public TrackWriter(Context context, MyTracksProviderUtils myTracksProviderUtils, Track track,
public TrackWriter(Context context, MyTracksProviderUtils myTracksProviderUtils, Track[] tracks,
TrackFileFormat trackFileFormat, OnWriteListener onWriteListener) {
this(myTracksProviderUtils, track, trackFileFormat.newFormatWriter(context), onWriteListener);
this(myTracksProviderUtils, tracks, trackFileFormat.newFormatWriter(context), onWriteListener);
}
@VisibleForTesting
public TrackWriter(MyTracksProviderUtils myTracksProviderUtils, Track track,
public TrackWriter(MyTracksProviderUtils myTracksProviderUtils, Track[] tracks,
TrackFormatWriter trackFormatWriter, OnWriteListener onWriteListener) {
this.myTracksProviderUtils = myTracksProviderUtils;
this.track = track;
this.tracks = tracks;
this.trackFormatWriter = trackFormatWriter;
this.onWriteListener = onWriteListener;
}
@@ -105,10 +105,14 @@ public class TrackWriter {
@Override
public void run() {
try {
trackFormatWriter.prepare(track, outputStream);
trackFormatWriter.writeHeader();
writeWaypoints();
writeLocations();
trackFormatWriter.prepare(outputStream);
trackFormatWriter.writeHeader(tracks[0]);
long startTime = tracks[0].getTripStatistics().getStartTime();
for (int i = 0; i < tracks.length; i++) {
writeWaypoints(tracks[i]);
long offset = tracks[i].getTripStatistics().getStartTime() - startTime;
writeLocations(tracks[i], offset);
}
trackFormatWriter.writeFooter();
trackFormatWriter.close();
success = true;
@@ -147,7 +151,7 @@ public class TrackWriter {
/**
* Writes the waypoints.
*/
private void writeWaypoints() {
private void writeWaypoints(Track track) {
/*
* TODO: 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
@@ -185,7 +189,7 @@ public class TrackWriter {
/**
* Writes the locations.
*/
private void writeLocations() throws InterruptedException {
private void writeLocations(Track track, long offset) throws InterruptedException {
boolean wroteTrack = false;
boolean wroteSegment = false;
boolean isLastLocationValid = false;
@@ -197,6 +201,7 @@ public class TrackWriter {
int locationNumber = 0;
while (iterator.hasNext()) {
Location location = iterator.next();
setLocationTime(location, offset);
if (Thread.interrupted()) {
throw new InterruptedException();
}
@@ -205,8 +210,8 @@ public class TrackWriter {
boolean isLocationValid = LocationUtils.isValidLocation(location);
boolean isSegmentValid = isLocationValid && isLastLocationValid;
if (!wroteTrack && isSegmentValid) {
// Found the first two consecutive locations that are valid
trackFormatWriter.writeBeginTrack(locationFactory.lastLocation);
// Found the first two consecutive locations that are valid
trackFormatWriter.writeBeginTrack(track, locationFactory.lastLocation);
wroteTrack = true;
}
@@ -241,17 +246,30 @@ public class TrackWriter {
}
if (wroteTrack) {
Location lastValidTrackPoint = myTracksProviderUtils.getLastValidTrackPoint(track.getId());
trackFormatWriter.writeEndTrack(lastValidTrackPoint);
setLocationTime(lastValidTrackPoint, offset);
trackFormatWriter.writeEndTrack(track, lastValidTrackPoint);
} else {
// Write an empty track
trackFormatWriter.writeBeginTrack(null);
trackFormatWriter.writeEndTrack(null);
trackFormatWriter.writeBeginTrack(track, null);
trackFormatWriter.writeEndTrack(track, null);
}
} finally {
iterator.close();
}
}
/**
* Sets a location time.
*
* @param location the location
* @param offset the time offset
*/
private void setLocationTime(Location location, long offset) {
if (location != null) {
location.setTime(location.getTime() - offset);
}
}
/**
* Track writer location factory. Keeping the last two locations.
*
@@ -427,7 +427,7 @@ public class SyncUtils {
java.io.File file = new java.io.File(directory,
FileUtils.buildUniqueFileName(directory, track.getName(), trackFileFormat.getExtension()));
TrackWriter trackWriter = new TrackWriter(
context, myTracksProviderUtils, track, trackFileFormat, null);
context, myTracksProviderUtils, new Track[] {track}, trackFileFormat, null);
trackWriter.writeTrack(new FileOutputStream(file));
if (trackWriter.wasSuccess()) {
@@ -0,0 +1,75 @@
/*
* Copyright 2013 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks.util;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.net.Uri;
import java.io.File;
import java.util.List;
/**
* Utilities for Google Earth.
*
* @author Jimmy Shih
*/
public class GoogleEarthUtils {
private static final String GOOGLE_EARTH_CLASS = "com.google.earth.EarthActivity";
private static final String GOOGLE_EARTH_KML_MIME_TYPE = "application/vnd.google-earth.kml+xml";
private static final String GOOGLE_EARTH_PACKAGE = "com.google.earth";
private static final String
GOOGLE_EARTH_TOUR_FEATURE_ID = "com.google.earth.EXTRA.tour_feature_id";
public static final String GOOGLE_EARTH_MARKET_URL = "market://details?id="
+ GOOGLE_EARTH_PACKAGE;
public static final String TOUR_FEATURE_ID_VALUE = "tour";
private GoogleEarthUtils() {}
/**
* Returns true if Google Earth is installed.
*
* @param context the context
*/
public static boolean isEarthInstalled(Context context) {
List<ResolveInfo> infos = context.getPackageManager().queryIntentActivities(
new Intent().setType(GOOGLE_EARTH_KML_MIME_TYPE), PackageManager.MATCH_DEFAULT_ONLY);
for (ResolveInfo info : infos) {
if (info.activityInfo != null && info.activityInfo.packageName != null
&& info.activityInfo.packageName.equals(GOOGLE_EARTH_PACKAGE)) {
return true;
}
}
return false;
}
/**
* Gets an intent to play a kml file in Google Earth.
*
* @param kmlFilePath the kml file path
*/
public static Intent getPlayInEarthIntent(String kmlFilePath) {
return new Intent().addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK)
.putExtra(GOOGLE_EARTH_TOUR_FEATURE_ID, TOUR_FEATURE_ID_VALUE)
.setClassName(GOOGLE_EARTH_PACKAGE, GOOGLE_EARTH_CLASS)
.setDataAndType(Uri.fromFile(new File(kmlFilePath)), GOOGLE_EARTH_KML_MIME_TYPE);
}
}
@@ -42,6 +42,8 @@ public class GoogleFeedbackUtils {
private static Boolean available = null;
private GoogleFeedbackUtils() {}
/**
* Returns true if the Google Feedback is available.
*
@@ -23,7 +23,7 @@ import android.content.pm.ResolveInfo;
/**
* Utilities for Google location settings
*
*
* @author Jimmy Shih
*/
public class GoogleLocationUtils {
@@ -32,7 +32,9 @@ public class GoogleLocationUtils {
ACTION_GOOGLE_LOCATION_SETTINGS = "com.google.android.gsf.GOOGLE_LOCATION_SETTINGS";
private static final String
ACTION_GOOGLE_APPS_LOCATION_SETTINGS = "com.google.android.gsf.GOOGLE_APPS_LOCATION_SETTINGS";
private GoogleLocationUtils() {}
/**
* Returns true if the Google location settings is available.
*/
@@ -98,9 +98,7 @@ public class PreferencesUtils {
public static final String SHARE_TRACK_DEFAULT = "DRIVE";
public static final int SPLIT_FREQUENCY_DEFAULT = 0;
public static final boolean STATS_SHOW_COORDINATE_DEFAULT = false;
public static final boolean STATS_SHOW_ELEVATION_DEFAULT = false;
public static final boolean STATS_SHOW_GRADE_DEFAULT = false;
public static final boolean STATS_SHOW_MOVING_TIME_DEFAULT = false;
public static final boolean STATS_SHOW_GRADE_ELEVATION_DEFAULT = false;
public static final String TRACK_COLOR_MODE_DEFAULT = "SINGLE";
public static final int TRACK_COLOR_MODE_MEDIUM_DEFAULT = 15;
public static final int TRACK_COLOR_MODE_PERCENTAGE_DEFAULT = 25;
@@ -24,78 +24,87 @@ import android.location.Location;
import android.view.View;
import android.widget.TextView;
import java.util.Locale;
/**
* Utilities for updating the statistics UI labels and values.
*
*
* @author Jimmy Shih
*/
public class StatsUtils {
private static final String COORDINATE_DEGREE = "\u00B0";
private static final String GRADE_PERCENTAGE = "%";
private static final String ELEVATION_FORMAT = "%1$.2f";
private static final String GRADE_FORMAT = "%1$d";
private StatsUtils() {}
/**
* Sets the location values.
*
*
* @param activity the activity
* @param location the location
* @param showAll true to show all the fields, false to show only the
* elevation field
* @param isRecording true if recording
*/
public static void setLocationValues(Activity activity, Location location, boolean showAll) {
public static void setLocationValues(Activity activity, Location location, boolean isRecording) {
boolean metricUnits = PreferencesUtils.getBoolean(
activity, R.string.metric_units_key, PreferencesUtils.METRIC_UNITS_DEFAULT);
boolean reportSpeed = PreferencesUtils.getBoolean(
activity, R.string.report_speed_key, PreferencesUtils.REPORT_SPEED_DEFAULT);
// Set elevation
boolean showElevation = PreferencesUtils.getBoolean(
activity, R.string.stats_show_elevation_key, PreferencesUtils.STATS_SHOW_ELEVATION_DEFAULT);
if (showElevation) {
double altitude = location == null ? Double.NaN : location.getAltitude();
setElevationValue(activity, R.id.stats_elevation_value, altitude, metricUnits);
}
if (!showAll) {
return;
}
// Set speed/pace
setSpeedLabel(
activity, R.id.stats_speed_label, R.string.stats_speed, R.string.stats_pace, reportSpeed);
double speed = location == null ? Double.NaN : location.getSpeed();
setSpeedValue(activity, R.id.stats_speed_value, speed, metricUnits, reportSpeed);
double speed = !isRecording || location == null ? Double.NaN : location.getSpeed();
setSpeed(activity, R.id.stats_speed, R.string.stats_speed, R.string.stats_pace, speed,
metricUnits, reportSpeed);
// Set elevation
boolean showGradeElevation = PreferencesUtils.getBoolean(activity,
R.string.stats_show_grade_elevation_key,
PreferencesUtils.STATS_SHOW_GRADE_ELEVATION_DEFAULT);
View elevation = activity.findViewById(R.id.stats_elevation);
if (showGradeElevation && isRecording) {
double altitude = location == null ? Double.NaN : location.getAltitude();
elevation.setVisibility(View.VISIBLE);
setElevationValue(activity, R.id.stats_elevation, -1, altitude, metricUnits);
} else {
elevation.setVisibility(View.GONE);
}
// Set coordinate
boolean showCoordinate = PreferencesUtils.getBoolean(activity,
R.string.stats_show_coordinate_key, PreferencesUtils.STATS_SHOW_COORDINATE_DEFAULT);
View coordinateLabelTableRow = activity.findViewById(R.id.stats_coordinate_label_table_row);
View coordinateValueTableRow = activity.findViewById(R.id.stats_coordinate_value_table_row);
if (coordinateLabelTableRow == null || coordinateValueTableRow == null) {
return;
}
coordinateLabelTableRow.setVisibility(showCoordinate ? View.VISIBLE : View.GONE);
coordinateValueTableRow.setVisibility(showCoordinate ? View.VISIBLE : View.GONE);
if (showCoordinate) {
View coordinateHorizontalLine = activity.findViewById(R.id.stats_coordinate_horizontal_line);
View coordinateContainer = activity.findViewById(R.id.stats_coordinate_container);
if (showCoordinate && isRecording) {
double latitude = location == null ? Double.NaN : location.getLatitude();
double longitude = location == null ? Double.NaN : location.getLongitude();
setCoordinateValue(activity, R.id.stats_latitude_value, latitude);
setCoordinateValue(activity, R.id.stats_longitude_value, longitude);
coordinateHorizontalLine.setVisibility(View.VISIBLE);
coordinateContainer.setVisibility(View.VISIBLE);
setCoordinateValue(activity, R.id.stats_latitude, R.string.stats_latitude, latitude);
setCoordinateValue(activity, R.id.stats_longitude, R.string.stats_longitude, longitude);
} else {
coordinateHorizontalLine.setVisibility(View.GONE);
coordinateContainer.setVisibility(View.GONE);
}
}
/**
* Sets the total time value.
*
*
* @param activity the activity
* @param totalTime the total time
*/
public static void setTotalTimeValue(Activity activity, long totalTime) {
setTimeValue(activity, R.id.stats_total_time_value, totalTime);
setTimeValue(activity, R.id.stats_total_time, R.string.stats_total_time, totalTime);
}
/**
* Sets the trip statistics values.
*
*
* @param activity the activity
* @param tripStatistics the trip statistics
*/
@@ -104,249 +113,206 @@ public class StatsUtils {
activity, R.string.metric_units_key, PreferencesUtils.METRIC_UNITS_DEFAULT);
boolean reportSpeed = PreferencesUtils.getBoolean(
activity, R.string.report_speed_key, PreferencesUtils.REPORT_SPEED_DEFAULT);
boolean showMovingTime = PreferencesUtils.getBoolean(activity,
R.string.stats_show_moving_time_key, PreferencesUtils.STATS_SHOW_MOVING_TIME_DEFAULT);
// Set total distance
double totalDistance = tripStatistics == null ? Double.NaN : tripStatistics.getTotalDistance();
setDistanceValue(activity, R.id.stats_distance_value, totalDistance, metricUnits);
setDistanceValue(activity, totalDistance, metricUnits);
// Set total time
setTimeValue(activity, R.id.stats_total_time_value,
setTimeValue(activity, R.id.stats_total_time, R.string.stats_total_time,
tripStatistics != null ? tripStatistics.getTotalTime() : -1L);
// Set moving time
setItemVisibility(activity, R.id.stats_moving_time_label, R.id.stats_moving_time_spacer,
R.id.stats_moving_time_value, showMovingTime);
if (showMovingTime) {
setTimeValue(activity, R.id.stats_moving_time_value,
tripStatistics != null ? tripStatistics.getMovingTime() : -1L);
}
// Set average speed
setSpeedLabel(activity, R.id.stats_average_speed_label, R.string.stats_average_speed,
R.string.stats_average_pace, reportSpeed);
// Set average speed/pace
double averageSpeed = tripStatistics != null ? tripStatistics.getAverageSpeed() : Double.NaN;
setSpeedValue(activity, R.id.stats_average_speed_value, averageSpeed, metricUnits, reportSpeed);
// Set average moving speed
setItemVisibility(activity, R.id.stats_average_moving_speed_label,
R.id.stats_average_moving_speed_spacer, R.id.stats_average_moving_speed_value,
showMovingTime);
if (showMovingTime) {
setSpeedLabel(activity, R.id.stats_average_moving_speed_label,
R.string.stats_average_moving_speed, R.string.stats_average_moving_pace, reportSpeed);
double averageMovingSpeed = tripStatistics != null ? tripStatistics.getAverageMovingSpeed()
: Double.NaN;
setSpeedValue(activity, R.id.stats_average_moving_speed_value, averageMovingSpeed,
metricUnits, reportSpeed);
}
setSpeed(activity, R.id.stats_average_speed, R.string.stats_average_speed,
R.string.stats_average_pace, averageSpeed, metricUnits, reportSpeed);
// Set max speed
setSpeedLabel(activity, R.id.stats_max_speed_label, R.string.stats_max_speed,
R.string.stats_fastest_pace, reportSpeed);
// Set moving time
setTimeValue(activity, R.id.stats_moving_time, R.string.stats_moving_time,
tripStatistics != null ? tripStatistics.getMovingTime() : -1L);
// Set average moving speed/pace
double averageMovingSpeed = tripStatistics != null ? tripStatistics.getAverageMovingSpeed()
: Double.NaN;
setSpeed(activity, R.id.stats_average_moving_time, R.string.stats_average_moving_speed,
R.string.stats_average_moving_pace, averageMovingSpeed, metricUnits, reportSpeed);
// Set max speed/pace
double maxSpeed = tripStatistics == null ? Double.NaN : tripStatistics.getMaxSpeed();
setSpeedValue(activity, R.id.stats_max_speed_value, maxSpeed, metricUnits, reportSpeed);
// Set elevation
boolean showElevation = PreferencesUtils.getBoolean(
activity, R.string.stats_show_elevation_key, PreferencesUtils.STATS_SHOW_ELEVATION_DEFAULT);
View elevationLabelTableRow1 = activity.findViewById(R.id.stats_elevation_label_table_row1);
View elevationValueTableRow1 = activity.findViewById(R.id.stats_elevation_value_table_row1);
View elevationLabelTableRow2 = activity.findViewById(R.id.stats_elevation_label_table_row2);
View elevationValueTableRow2 = activity.findViewById(R.id.stats_elevation_value_table_row2);
if (elevationLabelTableRow1 == null
|| elevationValueTableRow1 == null
|| elevationLabelTableRow2 == null
|| elevationValueTableRow2 == null) {
return;
}
elevationLabelTableRow1.setVisibility(showElevation ? View.VISIBLE : View.GONE);
elevationValueTableRow1.setVisibility(showElevation ? View.VISIBLE : View.GONE);
elevationLabelTableRow2.setVisibility(showElevation ? View.VISIBLE : View.GONE);
elevationValueTableRow2.setVisibility(showElevation ? View.VISIBLE : View.GONE);
if (showElevation) {
setSpeed(activity, R.id.stats_max_speed, R.string.stats_max_speed, R.string.stats_fastest_pace,
maxSpeed, metricUnits, reportSpeed);
// Set grade/elevation
boolean showGradeElevation = PreferencesUtils.getBoolean(activity,
R.string.stats_show_grade_elevation_key,
PreferencesUtils.STATS_SHOW_GRADE_ELEVATION_DEFAULT);
View gradeElevationHorizontalLine = activity.findViewById(
R.id.stats_grade_elevation_horizontal_line);
View gradeElevationContainer = activity.findViewById(R.id.stats_grade_elevation_container);
if (showGradeElevation) {
gradeElevationHorizontalLine.setVisibility(View.VISIBLE);
gradeElevationContainer.setVisibility(View.VISIBLE);
// Set grade
double minGrade = tripStatistics == null ? Double.NaN : tripStatistics.getMinGrade();
double maxGrade = tripStatistics == null ? Double.NaN : tripStatistics.getMaxGrade();
setGradeValue(activity, R.id.stats_grade_min, R.string.stats_min, minGrade);
setGradeValue(activity, R.id.stats_grade_max, R.string.stats_max, maxGrade);
// Set elevation
double elevationGain = tripStatistics == null ? Double.NaN
: tripStatistics.getTotalElevationGain();
double minElevation = tripStatistics == null ? Double.NaN : tripStatistics.getMinElevation();
double maxElevation = tripStatistics == null ? Double.NaN : tripStatistics.getMaxElevation();
setElevationValue(activity, R.id.stats_elevation_gain_value, elevationGain, metricUnits);
setElevationValue(activity, R.id.stats_min_elevation_value, minElevation, metricUnits);
setElevationValue(activity, R.id.stats_max_elevation_value, maxElevation, metricUnits);
}
// Set grade
boolean showGrade = PreferencesUtils.getBoolean(
activity, R.string.stats_show_grade_key, PreferencesUtils.STATS_SHOW_GRADE_DEFAULT);
View gradeLabelTableRow = activity.findViewById(R.id.stats_grade_label_table_row);
View gradeValueTableRow = activity.findViewById(R.id.stats_grade_value_table_row);
if (gradeLabelTableRow == null || gradeValueTableRow == null) {
return;
}
gradeLabelTableRow.setVisibility(showGrade ? View.VISIBLE : View.GONE);
gradeValueTableRow.setVisibility(showGrade ? View.VISIBLE : View.GONE);
if (showGrade) {
double minGrade = tripStatistics == null ? Double.NaN : tripStatistics.getMinGrade();
double maxGrade = tripStatistics == null ? Double.NaN : tripStatistics.getMaxGrade();
setGradeValue(activity, R.id.stats_min_grade_value, minGrade);
setGradeValue(activity, R.id.stats_max_grade_value, maxGrade);
}
}
private static void setItemVisibility(
Activity activity, int labelId, int spacerId, int valueId, boolean show) {
View label = activity.findViewById(labelId);
View spacer = activity.findViewById(spacerId);
View value = activity.findViewById(valueId);
if (label != null) {
label.setVisibility(show ? View.VISIBLE : View.GONE);
}
if (spacer != null) {
spacer.setVisibility(show ? View.VISIBLE : View.GONE);
}
if (value != null) {
value.setVisibility(show ? View.VISIBLE : View.GONE);
setElevationValue(
activity, R.id.stats_elevation_gain, R.string.stats_gain, elevationGain, metricUnits);
setElevationValue(
activity, R.id.stats_elevation_min, R.string.stats_min, minElevation, metricUnits);
setElevationValue(
activity, R.id.stats_elevation_max, R.string.stats_max, maxElevation, metricUnits);
} else {
gradeElevationHorizontalLine.setVisibility(View.GONE);
gradeElevationContainer.setVisibility(View.GONE);
}
}
/**
* Sets a speed label.
*
* Sets speed.
*
* @param activity the activity
* @param id the speed label resource id
* @param speedId the speed string id
* @param paceId the pace string id
* @param reportSpeed true to report speed
*/
private static void setSpeedLabel(
Activity activity, int id, int speedId, int paceId, boolean reportSpeed) {
TextView textView = (TextView) activity.findViewById(id);
if (textView == null) {
return;
}
textView.setText(reportSpeed ? speedId : paceId);
}
/**
* Sets a speed value.
*
* @param activity the activity
* @param id the speed value resource id
* @param itemId the item id
* @param speedLabelId the speed label id
* @param paceLabelId the pace label id
* @param speed the speed in meters per second
* @param metricUnits true to display in metric units
* @param reportSpeed true to report speed
* @param metricUnits true if metric units
* @param reportSpeed true if report speed
*/
private static void setSpeedValue(
Activity activity, int id, double speed, boolean metricUnits, boolean reportSpeed) {
TextView textView = (TextView) activity.findViewById(id);
if (textView == null) {
return;
}
textView.setText(StringUtils.formatSpeed(activity, speed, metricUnits, reportSpeed));
private static void setSpeed(Activity activity, int itemId, int speedLabelId, int paceLabelId,
double speed, boolean metricUnits, boolean reportSpeed) {
String parts[] = StringUtils.getSpeedParts(activity, speed, metricUnits, reportSpeed);
setItem(activity, itemId, reportSpeed ? speedLabelId : paceLabelId, parts[0], parts[1]);
}
/**
* Sets a distance value.
*
* Sets distance value.
*
* @param activity the activity
* @param id the distance value resource id
* @param distance the distance in meters
* @param metricUnits true to display in metric units
* @param metricUnits true if metric units
*/
private static void setDistanceValue(
Activity activity, int id, double distance, boolean metricUnits) {
TextView textView = (TextView) activity.findViewById(id);
if (textView == null) {
return;
}
textView.setText(StringUtils.formatDistance(activity, distance, metricUnits));
private static void setDistanceValue(Activity activity, double distance, boolean metricUnits) {
String parts[] = StringUtils.getDistanceParts(activity, distance, metricUnits);
setItem(activity, R.id.stats_distance, R.string.stats_distance, parts[0], parts[1]);
}
/**
* Sets a time value.
*
*
* @param activity the activity
* @param id the time value resource id
* @param itemId the item id
* @param labelId the label id
* @param time the time
*/
private static void setTimeValue(Activity activity, int id, long time) {
TextView textView = (TextView) activity.findViewById(id);
if (textView == null) {
return;
}
private static void setTimeValue(Activity activity, int itemId, int labelId, long time) {
String value = time == -1L ? activity.getString(R.string.value_unknown)
: StringUtils.formatElapsedTime(time);
textView.setText(value);
setItem(activity, itemId, labelId, value, null);
}
/**
* Sets an elevation value.
*
*
* @param activity the activity
* @param id the elevation value resource id
* @param itemId the item id
* @param labelId the label id
* @param elevation the elevation in meters
* @param metricUnits true to display in metric units
* @param metricUnits true if metric units
*/
private static void setElevationValue(
Activity activity, int id, double elevation, boolean metricUnits) {
TextView textView = (TextView) activity.findViewById(id);
if (textView == null) {
return;
}
Activity activity, int itemId, int labelId, double elevation, boolean metricUnits) {
String value;
String unit;
if (Double.isNaN(elevation) || Double.isInfinite(elevation)) {
value = activity.getString(R.string.value_unknown);
value = null;
unit = null;
} else {
if (metricUnits) {
value = activity.getString(R.string.value_float_meter, elevation);
value = String.format(Locale.getDefault(), ELEVATION_FORMAT, elevation);
unit = activity.getString(R.string.unit_meter);
} else {
elevation *= UnitConversions.M_TO_FT;
value = activity.getString(R.string.value_float_feet, elevation);
value = String.format(Locale.getDefault(), ELEVATION_FORMAT, elevation);
unit = activity.getString(R.string.unit_feet);
}
}
textView.setText(value);
setItem(activity, itemId, labelId, value, unit);
}
/**
* Sets a grade value.
*
*
* @param activity the activity
* @param id the grade value resource id
* @param itemId the item id
* @param labelId the label id
* @param grade the grade in fraction between 0 and 1
*/
private static void setGradeValue(Activity activity, int id, double grade) {
TextView textView = (TextView) activity.findViewById(id);
if (textView == null) {
return;
}
String value;
if (Double.isNaN(grade) || Double.isInfinite(grade)) {
value = activity.getString(R.string.value_unknown);
} else {
value = activity.getString(R.string.value_integer_percent, Math.round(grade * 100));
}
textView.setText(value);
private static void setGradeValue(Activity activity, int itemId, int labelId, double grade) {
String value = Double.isNaN(grade) || Double.isInfinite(grade) ? null
: String.format(Locale.getDefault(), GRADE_FORMAT, Math.round(grade * 100));
setItem(activity, itemId, labelId, value, GRADE_PERCENTAGE);
}
/**
* Sets a coordinate value.
*
*
* @param activity the activity
* @param id the coordinate value resource id
* @param itemId the item id
* @param labelId the label id
* @param coordinate the coordinate in degrees
*/
private static void setCoordinateValue(Activity activity, int id, double coordinate) {
TextView textView = (TextView) activity.findViewById(id);
if (textView == null) {
private static void setCoordinateValue(
Activity activity, int itemId, int labelId, double coordinate) {
String value = Double.isNaN(coordinate) || Double.isInfinite(coordinate) ? null
: Location.convert(coordinate, Location.FORMAT_DEGREES);
setItem(activity, itemId, labelId, value, COORDINATE_DEGREE);
}
/**
* Sets an item.
*
* @param activity the activity
* @param itemId the item id
* @param labelId the label id. -1 to hide the label
* @param value the value, can be null
* @param unit the unit. Null to hide the unit
*/
private static void setItem(
Activity activity, int itemId, int labelId, String value, String unit) {
View view = activity.findViewById(itemId);
TextView labelTextView = (TextView) view.findViewById(R.id.stats_label);
TextView valueTextView = (TextView) view.findViewById(R.id.stats_value);
TextView unitTextView = (TextView) view.findViewById(R.id.stats_unit);
if (labelTextView == null || valueTextView == null || unitTextView == null) {
return;
}
String value;
if (Double.isNaN(coordinate) || Double.isInfinite(coordinate)) {
value = activity.getString(R.string.value_unknown);
if (labelId == -1) {
labelTextView.setVisibility(View.GONE);
} else {
value = activity.getString(
R.string.value_coordinate_degree, Location.convert(coordinate, Location.FORMAT_DEGREES));
labelTextView.setVisibility(View.VISIBLE);
labelTextView.setText(labelId);
}
textView.setText(value);
if (value == null) {
value = activity.getString(R.string.value_unknown);
unitTextView.setVisibility(View.GONE);
} else {
if (unit == null) {
unitTextView.setVisibility(View.GONE);
} else {
unitTextView.setVisibility(View.VISIBLE);
unitTextView.setText(unit);
}
}
valueTextView.setText(value);
}
}
@@ -151,7 +151,8 @@ public class StringUtils {
/**
* Gets the distance in an array of two strings. The first string is the
* distance. The second string is the unit.
* distance. The second string is the unit. The first string is null if the
* distance is invalid.
*
* @param context the context
* @param distance the distance
@@ -160,7 +161,7 @@ public class StringUtils {
public static String[] getDistanceParts(Context context, double distance, boolean metricUnits) {
String[] result = new String[2];
if (Double.isNaN(distance) || Double.isInfinite(distance)) {
result[0] = context.getString(R.string.value_unknown);
result[0] = null;
result[1] = context.getString(metricUnits ? R.string.unit_meter : R.string.unit_feet);
return result;
}
@@ -188,42 +189,9 @@ public class StringUtils {
}
/**
* Formats the speed.
*
* @param context the context
* @param speed the speed in meters per second
* @param metricUnits true to use metric units. False to use imperial units
* @param reportSpeed true to report as speed. False to report as pace
*/
public static String formatSpeed(
Context context, double speed, boolean metricUnits, boolean reportSpeed) {
if (Double.isNaN(speed) || Double.isInfinite(speed)) {
return context.getString(R.string.value_unknown);
}
speed *= UnitConversions.MS_TO_KMH;
if (metricUnits) {
if (reportSpeed) {
return context.getString(R.string.value_float_kilometer_hour, speed);
} else {
// convert from hours to minutes
double pace = speed == 0 ? 0.0 : 60.0 / speed;
return context.getString(R.string.value_float_minute_kilometer, pace);
}
} else {
speed *= UnitConversions.KM_TO_MI;
if (reportSpeed) {
return context.getString(R.string.value_float_mile_hour, speed);
} else {
// convert from hours to minutes
double pace = speed == 0 ? 0.0 : 60.0 / speed;
return context.getString(R.string.value_float_minute_mile, pace);
}
}
}
/**
* Gets the speed in an array of two strings. The first string is the
* speed. The second string is the unit.
* Gets the speed in an array of two strings. The first string is the speed.
* The second string is the unit. The first string is null if speed is
* invalid.
*
* @param context the context
* @param speed the speed
@@ -241,7 +209,7 @@ public class StringUtils {
}
result[1] = context.getString(unitId);
if (Double.isNaN(speed) || Double.isInfinite(speed)) {
result[0] = context.getString(R.string.value_unknown);
result[0] = null;
return result;
}
speed *= UnitConversions.MS_TO_KMH;
@@ -314,6 +314,9 @@ public class TrackWidgetProvider extends AppWidgetProvider {
TripStatistics tripStatistics, boolean metricUnits) {
double totalDistance = tripStatistics == null ? Double.NaN : tripStatistics.getTotalDistance();
String[] totalDistanceParts = StringUtils.getDistanceParts(context, totalDistance, metricUnits);
if (totalDistanceParts[0] == null) {
totalDistanceParts[0] = context.getString(R.string.value_unknown);
}
remoteViews.setTextViewText(ids[0], context.getString(R.string.stats_distance));
remoteViews.setTextViewText(ids[1], totalDistanceParts[0]);
remoteViews.setTextViewText(ids[2], totalDistanceParts[1]);
@@ -367,6 +370,11 @@ public class TrackWidgetProvider extends AppWidgetProvider {
Double speed = tripStatistics == null ? Double.NaN : tripStatistics.getAverageSpeed();
String[] speedParts = StringUtils.getSpeedParts(context, speed, metricUnits, reportSpeed);
if (speedParts[0] == null) {
speedParts[0] = context.getString(R.string.value_unknown);
}
remoteViews.setTextViewText(ids[1], speedParts[0]);
remoteViews.setTextViewText(ids[2], speedParts[1]);
}
@@ -406,6 +414,11 @@ public class TrackWidgetProvider extends AppWidgetProvider {
Double speed = tripStatistics == null ? Double.NaN : tripStatistics.getAverageMovingSpeed();
String[] speedParts = StringUtils.getSpeedParts(context, speed, metricUnits, reportSpeed);
if (speedParts[0] == null) {
speedParts[0] = context.getString(R.string.value_unknown);
}
remoteViews.setTextViewText(ids[1], speedParts[0]);
remoteViews.setTextViewText(ids[2], speedParts[1]);
}
@@ -115,13 +115,13 @@ public abstract class TrackFormatWriterTest extends AndroidTestCase {
*/
protected String writeTrack(TrackFormatWriter writer) throws Exception {
OutputStream output = new ByteArrayOutputStream(BUFFER_SIZE);
writer.prepare(track, output);
writer.writeHeader();
writer.prepare(output);
writer.writeHeader(track);
writer.writeBeginWaypoints();
writer.writeWaypoint(wp1);
writer.writeWaypoint(wp2);
writer.writeEndWaypoints();
writer.writeBeginTrack(location1);
writer.writeBeginTrack(track, location1);
writer.writeOpenSegment();
writer.writeLocation(location1);
writer.writeLocation(location2);
@@ -130,7 +130,7 @@ public abstract class TrackFormatWriterTest extends AndroidTestCase {
writer.writeLocation(location3);
writer.writeLocation(location4);
writer.writeCloseSegment();
writer.writeEndTrack(location4);
writer.writeEndTrack(track, location4);
writer.writeFooter();
writer.close();
return output.toString();
@@ -76,7 +76,7 @@ public class TrackWriterTest extends AndroidTestCase {
}
};
trackWriter = new TrackWriter(myTracksProviderUtils, track, trackFormatWriter, onWriteListener);
trackWriter = new TrackWriter(myTracksProviderUtils, new Track[] {track}, trackFormatWriter, onWriteListener);
}
@Override
@@ -91,10 +91,10 @@ public class TrackWriterTest extends AndroidTestCase {
public void testWriteTrack_emptyTrack() throws Exception {
// Set expected mock behavior
trackFormatWriter.prepare(track, outputStream);
trackFormatWriter.writeHeader();
trackFormatWriter.writeBeginTrack(null);
trackFormatWriter.writeEndTrack(null);
trackFormatWriter.prepare(outputStream);
trackFormatWriter.writeHeader(track);
trackFormatWriter.writeBeginTrack(track, null);
trackFormatWriter.writeEndTrack(track, null);
trackFormatWriter.writeFooter();
trackFormatWriter.close();
@@ -123,10 +123,10 @@ public class TrackWriterTest extends AndroidTestCase {
myTracksProviderUtils.bulkInsertTrackPoint(locations, locations.length, TRACK_ID));
// Set expected mock behavior
trackFormatWriter.prepare(track, outputStream);
trackFormatWriter.writeHeader();
trackFormatWriter.writeBeginTrack(null);
trackFormatWriter.writeEndTrack(null);
trackFormatWriter.prepare(outputStream);
trackFormatWriter.writeHeader(track);
trackFormatWriter.writeBeginTrack(track, null);
trackFormatWriter.writeEndTrack(track, null);
trackFormatWriter.writeFooter();
trackFormatWriter.close();
@@ -162,8 +162,8 @@ public class TrackWriterTest extends AndroidTestCase {
waypoint.setId(i + 1);
}
trackFormatWriter.prepare(track, outputStream);
trackFormatWriter.writeHeader();
trackFormatWriter.prepare(outputStream);
trackFormatWriter.writeHeader(track);
// Expect reading/writing of the waypoints (except the first)
trackFormatWriter.writeBeginWaypoints();
@@ -172,7 +172,7 @@ public class TrackWriterTest extends AndroidTestCase {
trackFormatWriter.writeEndWaypoints();
// Begin the track
trackFormatWriter.writeBeginTrack(locationEq(locations[0]));
trackFormatWriter.writeBeginTrack(trackEq(track), locationEq(locations[0]));
// Write locations 1-2
trackFormatWriter.writeOpenSegment();
@@ -190,7 +190,7 @@ public class TrackWriterTest extends AndroidTestCase {
trackFormatWriter.writeCloseSegment();
// End the track
trackFormatWriter.writeEndTrack(locationEq(locations[5]));
trackFormatWriter.writeEndTrack(trackEq(track), locationEq(locations[5]));
trackFormatWriter.writeFooter();
trackFormatWriter.close();
@@ -266,6 +266,33 @@ public class TrackWriterTest extends AndroidTestCase {
return null;
}
/**
* Track equals.
*
* @param track1 the track
*/
private Track trackEq(final Track track1) {
EasyMock.reportMatcher(new IArgumentMatcher() {
@Override
public boolean matches(Object object) {
if (object == null || track1 == null) {
return track1 == object;
}
Track track2 = (Track) object;
return track1.getName().equals(track2.getName());
}
@Override
public void appendTo(StringBuffer buffer) {
buffer.append("trackEq(");
buffer.append(track1);
buffer.append(")");
}
});
return null;
}
/**
* Fills the locations.
*
@@ -90,28 +90,6 @@ public class StringUtilsTest extends AndroidTestCase {
assertEquals("328.08 ft", StringUtils.formatDistance(getContext(), 100, false));
}
/**
* Tests {@link StringUtils#formatSpeed(android.content.Context, double,
* boolean, boolean)}.
*/
public void testFormatSpeed() {
// Speed in metric
assertEquals("36.00 km/h", StringUtils.formatSpeed(getContext(), 10, true, true));
// Speed in imperial
assertEquals("22.37 mi/h", StringUtils.formatSpeed(getContext(), 10, false, true));
// Pace in metric
assertEquals("1.67 min/km", StringUtils.formatSpeed(getContext(), 10, true, false));
// Pace in imperial
assertEquals("2.68 min/mi", StringUtils.formatSpeed(getContext(), 10, false, false));
// zero pace
assertEquals("0.00 min/km", StringUtils.formatSpeed(getContext(), 0, true, false));
assertEquals("0.00 min/mi", StringUtils.formatSpeed(getContext(), 0, false, false));
// speed is NaN
assertEquals("-", StringUtils.formatSpeed(getContext(), Double.NaN, true, true));
// speed is infinite
assertEquals("-", StringUtils.formatSpeed(getContext(), Double.NEGATIVE_INFINITY, true, true));
}
/**
* Tests {@link StringUtils#formatCData(String)}.
*/