Use stats_core.xml layout for

- AggregatedStatsActivity
- StatsFragment
- MarkerDetailActivity
Remove StatsUtilities. Use StatsUtils to set all stats labels and values.
This commit is contained in:
Jimmy Shih
2012-04-20 12:50:22 -07:00
parent 8f7c44d1e7
commit aaef92b139
20 changed files with 630 additions and 1211 deletions
+27
View File
@@ -0,0 +1,27 @@
<?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.
-->
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
style="@style/ScrollView">
<TableLayout
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:padding="8dp"
android:shrinkColumns="0,2"
android:stretchColumns="0,2" >
<include layout="@layout/stats_core" />
</TableLayout>
</ScrollView>
+3 -3
View File
@@ -39,14 +39,14 @@ limitations under the License.
<TextView <TextView
android:id="@+id/list_item_total_time" android:id="@+id/list_item_total_time"
android:layout_marginRight="8dp" android:layout_marginRight="8dp"
style="@style/ListItemStat" /> style="@style/ListItemStats" />
<TextView <TextView
android:id="@+id/list_item_total_distance" android:id="@+id/list_item_total_distance"
android:layout_marginRight="8dp" android:layout_marginRight="8dp"
style="@style/ListItemStat" /> style="@style/ListItemStats" />
<TextView <TextView
android:id="@+id/list_item_start_time" android:id="@+id/list_item_start_time"
style="@style/ListItemStat" /> style="@style/ListItemStats" />
</LinearLayout> </LinearLayout>
<TextView <TextView
android:id="@+id/list_item_description" android:id="@+id/list_item_description"
+2 -116
View File
@@ -15,8 +15,7 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
--> -->
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android" <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="fill_parent" style="@style/ScrollView">
android:layout_width="fill_parent" >
<LinearLayout <LinearLayout
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_width="fill_parent" android:layout_width="fill_parent"
@@ -43,120 +42,7 @@ limitations under the License.
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:shrinkColumns="0,2" android:shrinkColumns="0,2"
android:stretchColumns="0,2" > android:stretchColumns="0,2" >
<!-- Total distance and max speed (fastest pace) --> <include layout="@layout/stats_core" />
<TableRow>
<TextView
android:text="@string/stat_total_distance"
style="@style/MarkerDetailStatisticsLabel" />
<TextView
android:id="@+id/marker_detail_max_speed_label"
android:layout_column="2"
style="@style/MarkerDetailStatisticsLabel" />
</TableRow>
<TableRow>
<TextView
android:id="@+id/marker_detail_total_distance_value"
style="@style/MarkerDetailStatisticsValue" />
<TextView style="@style/MarkerDetailStatisticsSpacer" />
<TextView
android:id="@+id/marker_detail_max_speed_value"
style="@style/MarkerDetailStatisticsValue" />
</TableRow>
<!-- Total time and average speed (average pace) -->
<TableRow>
<TextView
android:text="@string/stat_total_time"
style="@style/MarkerDetailStatisticsLabel" />
<TextView
android:id="@+id/marker_detail_average_speed_label"
android:layout_column="2"
style="@style/MarkerDetailStatisticsLabel" />
</TableRow>
<TableRow>
<TextView
android:id="@+id/marker_detail_total_time_value"
style="@style/MarkerDetailStatisticsValue" />
<TextView style="@style/MarkerDetailStatisticsSpacer" />
<TextView
android:id="@+id/marker_detail_average_speed_value"
style="@style/MarkerDetailStatisticsValue" />
</TableRow>
<!-- Moving time and average moving speed (average moving pace) -->
<TableRow>
<TextView
android:text="@string/stat_moving_time"
style="@style/MarkerDetailStatisticsLabel" />
<TextView
android:id="@+id/marker_detail_average_moving_speed_label"
android:layout_column="2"
style="@style/MarkerDetailStatisticsLabel" />
</TableRow>
<TableRow>
<TextView
android:id="@+id/marker_detail_moving_time_value"
style="@style/MarkerDetailStatisticsValue" />
<TextView style="@style/MarkerDetailStatisticsSpacer" />
<TextView
android:id="@+id/marker_detail_average_moving_speed_value"
style="@style/MarkerDetailStatisticsValue" />
</TableRow>
<!-- Elevation and elevation gain -->
<TableRow>
<TextView
android:text="@string/stat_elevation"
style="@style/MarkerDetailStatisticsLabel" />
<TextView
android:layout_column="2"
android:text="@string/stat_elevation_gain"
style="@style/MarkerDetailStatisticsLabel" />
</TableRow>
<TableRow>
<TextView
android:id="@+id/marker_detail_elevation_value"
style="@style/MarkerDetailStatisticsValue" />
<TextView style="@style/MarkerDetailStatisticsSpacer" />
<TextView
android:id="@+id/marker_detail_elevation_gain_value"
style="@style/MarkerDetailStatisticsValue" />
</TableRow>
<!-- Min and max elevation -->
<TableRow>
<TextView
android:text="@string/stat_min_elevation"
style="@style/MarkerDetailStatisticsLabel" />
<TextView
android:layout_column="2"
android:text="@string/stat_max_elevation"
style="@style/MarkerDetailStatisticsLabel" />
</TableRow>
<TableRow>
<TextView
android:id="@+id/marker_detail_min_elevation_value"
style="@style/MarkerDetailStatisticsValue" />
<TextView style="@style/MarkerDetailStatisticsSpacer" />
<TextView
android:id="@+id/marker_detail_max_elevation_value"
style="@style/MarkerDetailStatisticsValue" />
</TableRow>
<!-- Min and max grade -->
<TableRow>
<TextView
android:text="@string/stat_min_grade"
style="@style/MarkerDetailStatisticsLabel" />
<TextView
android:layout_column="2"
android:text="@string/stat_max_grade"
style="@style/MarkerDetailStatisticsLabel" />
</TableRow>
<TableRow>
<TextView
android:id="@+id/marker_detail_min_grade_value"
style="@style/MarkerDetailStatisticsValue" />
<TextView style="@style/MarkerDetailStatisticsSpacer" />
<TextView
android:id="@+id/marker_detail_max_grade_value"
style="@style/MarkerDetailStatisticsValue" />
</TableRow>
</TableLayout> </TableLayout>
</LinearLayout> </LinearLayout>
</ScrollView> </ScrollView>
+50 -64
View File
@@ -14,67 +14,53 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
--> -->
<LinearLayout <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:android="http://schemas.android.com/apk/res/android" style="@style/ScrollView" >
android:layout_height="fill_parent" <LinearLayout
android:layout_width="fill_parent" android:layout_height="wrap_content"
android:orientation="vertical"> android:layout_width="fill_parent"
<ScrollView android:orientation="vertical"
android:layout_height="0dp" android:padding="8dp" >
android:layout_weight="1" <TextView
android:layout_width="fill_parent"> android:text="@string/menu_sensor_state"
<LinearLayout style="@style/SensorStateLabel" />
android:layout_height="wrap_content" <TextView
android:layout_width="fill_parent" android:id="@+id/sensor_state"
android:orientation="vertical"> style="@style/SensorStateValue" />
<!-- Last sensor time -->
<!-- Sensor state --> <TextView
<TextView android:text="@string/sensor_state_last_sensor_time"
android:text="@string/menu_sensor_state" style="@style/SensorStateLabel" />
style="@style/SensorStateLabel"/> <TextView
<TextView android:id="@+id/sensor_state_last_sensor_time"
android:id="@+id/sensor_state" style="@style/SensorStateValue" />
style="@style/SensorStateValue"/> <!-- Power -->
<TextView
<!-- Last sensor time --> android:text="@string/sensor_state_power"
<TextView style="@style/SensorStateLabel" />
android:text="@string/sensor_state_last_sensor_time" <TextView
style="@style/SensorStateLabel"/> android:id="@+id/sensor_state_power"
<TextView style="@style/SensorStateValue" />
android:id="@+id/sensor_state_last_sensor_time" <!-- Cadence -->
style="@style/SensorStateValue"/> <TextView
android:text="@string/sensor_state_cadence"
<!-- Power --> style="@style/SensorStateLabel" />
<TextView <TextView
android:text="@string/sensor_state_power" android:id="@+id/sensor_state_cadence"
style="@style/SensorStateLabel"/> style="@style/SensorStateValue" />
<TextView <!-- Heart rate -->
android:id="@+id/sensor_state_power" <TextView
style="@style/SensorStateValue"/> android:text="@string/sensor_state_heart_rate"
style="@style/SensorStateLabel" />
<!-- Cadence --> <TextView
<TextView android:id="@+id/sensor_state_heart_rate"
android:text="@string/sensor_state_cadence" style="@style/SensorStateValue" />
style="@style/SensorStateLabel"/> <!-- Battery level -->
<TextView <TextView
android:id="@+id/sensor_state_cadence" android:text="@string/sensor_state_battery"
style="@style/SensorStateValue"/> style="@style/SensorStateLabel" />
<TextView
<!-- Heart rate --> android:id="@+id/sensor_state_battery"
<TextView style="@style/SensorStateValue" />
android:text="@string/sensor_state_heart_rate" </LinearLayout>
style="@style/SensorStateLabel"/> </ScrollView>
<TextView
android:id="@+id/sensor_state_heart_rate"
style="@style/SensorStateValue"/>
<!-- Battery level -->
<TextView
android:text="@string/sensor_state_battery"
style="@style/SensorStateLabel"/>
<TextView
android:id="@+id/sensor_state_battery"
style="@style/SensorStateValue"/>
</LinearLayout>
</ScrollView>
</LinearLayout>
+39 -344
View File
@@ -14,349 +14,44 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
--> -->
<RelativeLayout <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:android="http://schemas.android.com/apk/res/android" style="@style/ScrollView" >
android:id="@+id/stats_root" <TableLayout
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_width="fill_parent">
<ScrollView
android:id="@+id/scrolly"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_width="fill_parent">
<TableLayout
android:id="@+id/stats_table"
android:layout_height="wrap_content"
android:stretchColumns="1,4"
android:layout_width="fill_parent">
<!-- Layout the speed large on it's own line. -->
<TableRow>
<TextView
android:id="@+id/speed_label"
android:layout_span="5"
android:text="@string/stat_speed" />
</TableRow>
<TableRow
android:background="@color/stat_label_background">
<TextView
style="@style/StatsRegister.Big"
android:id="@+id/speed_register"
android:layout_column="1"
android:layout_span="4"/>
<LinearLayout
android:gravity="bottom"
android:layout_column="5"
android:layout_width="wrap_content"
android:lines="1"
android:orientation="vertical">
<TextView
android:layout_height="fill_parent"
android:layout_width="fill_parent" />
<TextView
android:id="@+id/speed_unit_label_top"
style="@style/StatsUnit" />
<TextView
style="@style/StatsDivider" />
<TextView
android:id="@+id/speed_unit_label_bottom"
style="@style/StatsUnit" />
</LinearLayout>
</TableRow>
<!-- Total distance and max speed -->
<TableRow
android:padding="1dp">
<TextView
android:id="@+id/total_distance_label"
android:layout_column="1"
android:layout_span="3"
android:text="@string/stat_total_distance" />
<TextView
android:id="@+id/max_speed_label"
android:layout_column="4"
android:layout_span="2"
android:text="@string/stat_max_speed" />
</TableRow>
<TableRow
android:background="@color/stat_label_background">
<TextView
style="@style/StatsRegister"
android:id="@+id/total_distance_register"
android:layout_column="1" />
<TextView
android:id="@+id/total_distance_unit_label"
android:layout_column="2"
style="@style/StatsUnitSolo" />
<!-- TODO 4/08/2009
The following is a bad hack to get a spacer the same size as the
text. Ideally this should just be a View, however I don't know how to
set the view height properly. fill_parent on this element causes as
NullPointerException. This same filler is repeated on each line.-->
<TextView
style="@style/StatsSpacer"
android:layout_column="3"/>
<TextView
android:id="@+id/max_speed_register"
style="@style/StatsRegister"
android:layout_column="4" />
<LinearLayout
android:gravity="bottom"
android:layout_column="5"
android:layout_width="wrap_content"
android:lines="1"
android:orientation="vertical">
<TextView
android:id="@+id/max_speed_unit_label_top"
style="@style/StatsUnit" />
<TextView
style="@style/StatsDivider" />
<TextView
android:id="@+id/max_speed_unit_label_bottom"
style="@style/StatsUnit" />
</LinearLayout>
</TableRow>
<!-- Total time and average speed -->
<TableRow>
<TextView
android:id="@+id/track_time_label"
android:layout_column="1"
android:layout_span="3"
android:text="@string/stat_total_time" />
<TextView
android:id="@+id/average_speed_label"
android:layout_column="4"
android:layout_span="2"
android:text="@string/stat_average_speed" />
</TableRow>
<TableRow
android:background="@color/stat_label_background">
<TextView
android:id="@+id/total_time_register"
android:layout_column="1"
android:layout_height="wrap_content"
android:layout_span="2"
android:layout_width="fill_parent"
style="@style/StatsRegister" />
<TextView
style="@style/StatsSpacer"
android:layout_column="3"/>
<TextView
android:id="@+id/average_speed_register"
android:layout_column="4"
style="@style/StatsRegister" />
<LinearLayout
android:gravity="bottom"
android:layout_column="5"
android:layout_width="wrap_content"
android:lines="1"
android:orientation="vertical">
<TextView
android:id="@+id/average_speed_unit_label_top"
style="@style/StatsUnit" />
<TextView
style="@style/StatsDivider" />
<TextView
android:id="@+id/average_speed_unit_label_bottom"
style="@style/StatsUnit" />
</LinearLayout>
</TableRow>
<!-- Moving time and average moving speed -->
<TableRow>
<TextView
android:id="@+id/moving_time_label"
android:layout_column="1"
android:layout_span="3"
android:text="@string/stat_moving_time" />
<TextView
android:id="@+id/average_moving_speed_label"
android:layout_column="4"
android:layout_span="2"
android:text="@string/stat_average_moving_speed" />
</TableRow>
<TableRow
android:background="@color/stat_label_background">
<TextView
android:id="@+id/moving_time_register"
android:layout_column="1"
android:layout_height="wrap_content"
android:layout_span="2"
android:layout_width="fill_parent"
style="@style/StatsRegister" />
<TextView
style="@style/StatsSpacer"
android:layout_column="3"/>
<TextView
android:id="@+id/average_moving_speed_register"
style="@style/StatsRegister" />
<LinearLayout
android:gravity="bottom"
android:layout_column="5"
android:layout_width="wrap_content"
android:lines="1"
android:orientation="vertical">
<TextView
android:id="@+id/average_moving_speed_unit_label_top"
style="@style/StatsUnit" />
<TextView
style="@style/StatsDivider" />
<TextView
android:id="@+id/average_moving_speed_unit_label_bottom"
style="@style/StatsUnit" />
</LinearLayout>
</TableRow>
<!-- Elevation and elevation gain -->
<TableRow>
<TextView
android:id="@+id/elevation_label"
android:layout_column="1"
android:layout_span="3"
android:text="@string/stat_elevation" />
<TextView
android:id="@+id/elevation_gain_label"
android:layout_column="4"
android:layout_span="2"
android:text="@string/stat_elevation_gain" />
</TableRow>
<TableRow
android:background="@color/stat_label_background">
<TextView
android:id="@+id/elevation_register"
android:layout_column="1"
style="@style/StatsRegister" />
<TextView
android:id="@+id/elevation_unit_label"
android:layout_column="2"
style="@style/StatsUnitSolo" />
<TextView
style="@style/StatsSpacer"
android:layout_column="3"/>
<TextView
android:id="@+id/elevation_gain_register"
android:layout_column="4"
style="@style/StatsRegister" />
<TextView
android:id="@+id/elevation_gain_unit_label"
android:layout_column="5"
style="@style/StatsUnitSolo" />
</TableRow>
<!-- Min and max elevation -->
<TableRow>
<TextView
android:id="@+id/min_elevation_label"
android:layout_column="1"
android:layout_span="3"
android:text="@string/stat_min_elevation" />
<TextView
android:id="@+id/max_elevation_label"
android:layout_column="4"
android:layout_span="3"
android:text="@string/stat_max_elevation" />
</TableRow>
<TableRow
android:background="@color/stat_label_background">
<TextView
android:id="@+id/min_elevation_register"
android:layout_column="1"
style="@style/StatsRegister" />
<TextView
android:id="@+id/min_elevation_unit_label"
android:layout_column="2"
style="@style/StatsUnitSolo" />
<TextView
style="@style/StatsSpacer"
android:layout_column="3"/>
<TextView
android:id="@+id/max_elevation_register"
android:layout_column="4"
style="@style/StatsRegister" />
<TextView
android:id="@+id/max_elevation_unit_label"
android:layout_column="5"
style="@style/StatsUnitSolo" />
</TableRow>
<!-- Min and max grade -->
<TableRow>
<TextView
android:id="@+id/min_grade_label"
android:layout_column="1"
android:layout_span="3"
android:text="@string/stat_min_grade" />
<TextView
android:id="@+id/max_grade_label"
android:layout_column="4"
android:layout_span="2"
android:text="@string/stat_max_grade" />
</TableRow>
<TableRow
android:background="@color/stat_label_background">
<TextView
android:id="@+id/min_grade_register"
android:layout_column="1"
android:layout_span="2"
style="@style/StatsRegister" />
<TextView
style="@style/StatsSpacer"
android:layout_column="3"/>
<TextView
android:id="@+id/max_grade_register"
android:layout_column="4"
android:layout_span="2"
style="@style/StatsRegister" />
</TableRow>
<!-- Latitude and Longitude -->
<TableRow>
<TextView
android:layout_column="1"
android:layout_span="3"
android:text="@string/stat_latitude" />
<TextView
android:layout_column="4"
android:layout_span="2"
android:text="@string/stat_longitude" />
</TableRow>
<TableRow
android:background="@color/stat_label_background">
<TextView
android:id="@+id/latitude_register"
android:layout_column="1"
android:layout_span="2"
style="@style/StatsRegister.Small" />
<TextView
style="@style/StatsSpacer"
android:layout_column="3"
android:textSize="25sp" />
<TextView
android:id="@+id/longitude_register"
android:layout_column="4"
android:layout_span="2"
style="@style/StatsRegister.Small" />
</TableRow>
</TableLayout>
</ScrollView>
<LinearLayout android:id="@+id/stats_busypane"
android:orientation="vertical"
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="fill_parent" android:padding="8dp"
android:padding="3dp" android:shrinkColumns="0,2"
android:visibility="gone"> android:stretchColumns="0,2" >
<ProgressBar <!-- Speed on one line -->
android:layout_weight="1" <TableRow>
android:layout_height="0dp" <TextView
android:layout_width="wrap_content" android:id="@+id/stats_speed_label"
android:maxWidth="80dp" style="@style/StatsLabel" />
android:maxHeight="80dp" </TableRow>
android:minWidth="80dp" <TableRow>
android:minHeight="80dp" <TextView
android:layout_gravity="center"/> android:id="@+id/stats_speed_value"
</LinearLayout> style="@style/StatsValue" />
</RelativeLayout> </TableRow>
<include layout="@layout/stats_core" />
<!-- Latitude and longitude -->
<TableRow>
<TextView
android:text="@string/stats_latitude"
style="@style/StatsLabel" />
<TextView
android:layout_column="2"
android:text="@string/stats_longitude"
style="@style/StatsLabel" />
</TableRow>
<TableRow>
<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>
</ScrollView>
+132
View File
@@ -0,0 +1,132 @@
<?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 and max speed (fastest pace) -->
<TableRow>
<TextView
android:text="@string/stats_total_distance"
style="@style/StatsLabel" />
<TextView
android:id="@+id/stats_max_speed_label"
android:layout_column="2"
style="@style/StatsLabel" />
</TableRow>
<TableRow>
<TextView
android:id="@+id/stats_total_distance_value"
style="@style/StatsValue" />
<TextView style="@style/StatsSpacer" />
<TextView
android:id="@+id/stats_max_speed_value"
style="@style/StatsValue" />
</TableRow>
<!-- Total time and average speed (average pace) -->
<TableRow>
<TextView
android:text="@string/stats_total_time"
style="@style/StatsLabel" />
<TextView
android:id="@+id/stats_average_speed_label"
android:layout_column="2"
style="@style/StatsLabel" />
</TableRow>
<TableRow>
<TextView
android:id="@+id/stats_total_time_value"
style="@style/StatsValue" />
<TextView style="@style/StatsSpacer" />
<TextView
android:id="@+id/stats_average_speed_value"
style="@style/StatsValue" />
</TableRow>
<!-- Moving time and average moving speed (average moving pace) -->
<TableRow>
<TextView
android:text="@string/stats_moving_time"
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_moving_time_value"
style="@style/StatsValue" />
<TextView style="@style/StatsSpacer" />
<TextView
android:id="@+id/stats_average_moving_speed_value"
style="@style/StatsValue" />
</TableRow>
<!-- Elevation and elevation gain -->
<TableRow>
<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>
<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>
<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>
<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>
<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>
<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>
+3 -3
View File
@@ -52,7 +52,7 @@ limitations under the License.
android:id="@+id/appwidget_distance_text" /> android:id="@+id/appwidget_distance_text" />
<TextView <TextView
style="@style/WidgetTextView" style="@style/WidgetTextView"
android:text="@string/stat_total_distance" /> android:text="@string/stats_total_distance" />
</LinearLayout> </LinearLayout>
<LinearLayout <LinearLayout
android:layout_width="fill_parent" android:layout_width="fill_parent"
@@ -68,7 +68,7 @@ limitations under the License.
android:id="@+id/appwidget_time_text" /> android:id="@+id/appwidget_time_text" />
<TextView <TextView
style="@style/WidgetTextView" style="@style/WidgetTextView"
android:text="@string/stat_moving_time" /> android:text="@string/stats_moving_time" />
</LinearLayout> </LinearLayout>
<LinearLayout <LinearLayout
android:layout_width="fill_parent" android:layout_width="fill_parent"
@@ -83,7 +83,7 @@ limitations under the License.
android:id="@+id/appwidget_speed_text" /> android:id="@+id/appwidget_speed_text" />
<TextView <TextView
style="@style/WidgetTextView" style="@style/WidgetTextView"
android:text="@string/stat_speed" /> android:text="@string/stats_speed" />
</LinearLayout> </LinearLayout>
</LinearLayout> </LinearLayout>
</LinearLayout> </LinearLayout>
-3
View File
@@ -17,11 +17,8 @@ limitations under the License.
<resources> <resources>
<color name="black">#FF000000</color> <color name="black">#FF000000</color>
<color name="blue">#FF0000FF</color> <color name="blue">#FF0000FF</color>
<color name="green">#FF00FF00</color>
<color name="gray">#FFAAAAAA</color> <color name="gray">#FFAAAAAA</color>
<color name="red">#FFFF0000</color> <color name="red">#FFFF0000</color>
<color name="stat_label_background">#FFF0F0F0</color>
<color name="stat_label_text">#FF0F0F0F</color>
<color name="white">#FFFFFFFF</color> <color name="white">#FFFFFFFF</color>
<!-- Chart colors by series. --> <!-- Chart colors by series. -->
+47 -40
View File
@@ -494,7 +494,7 @@ limitations under the License.
Accuracy (m) Accuracy (m)
</string> </string>
<string name="description_location_altitude" <string name="description_location_altitude"
translation_description="Label for location altitude in degrees."> translation_description="Label for location altitude in meters.">
Altitude (m) Altitude (m)
</string> </string>
<string name="description_location_bearing" <string name="description_location_bearing"
@@ -2067,81 +2067,81 @@ limitations under the License.
I think you might be interested in this track:\n\n%1$s I think you might be interested in this track:\n\n%1$s
</string> </string>
<!-- Stat Page --> <!-- Stats Page -->
<string name="stat_average_moving_pace" <string name="stats_average_moving_pace"
translation_description="In the 'Statistics' page, the average moving pace."> translation_description="In the 'Stats' page, the average moving pace.">
Average moving pace Average moving pace
</string> </string>
<string name="stat_average_moving_speed" <string name="stats_average_moving_speed"
translation_description="In the 'Statistics' page, the average moving speed."> translation_description="In the 'Stats' page, the average moving speed.">
Average moving speed Average moving speed
</string> </string>
<string name="stat_average_pace" <string name="stats_average_pace"
translation_description="In the 'Statistics' page, the average pace."> translation_description="In the 'Stats' page, the average pace.">
Average pace Average pace
</string> </string>
<string name="stat_average_speed" <string name="stats_average_speed"
translation_description="In the 'Statistics' page, the average speed."> translation_description="In the 'Stats' page, the average speed.">
Average speed Average speed
</string> </string>
<string name="stat_elevation" <string name="stats_elevation"
translation_description="In the 'Statistics' page, the elevation."> translation_description="In the 'Stats' page, the elevation.">
Elevation Elevation
</string> </string>
<string name="stat_elevation_gain" <string name="stats_elevation_gain"
translation_description="In the 'Statistics' page, the elevation gain."> translation_description="In the 'Stats' page, the elevation gain.">
Elevation gain Elevation gain
</string> </string>
<string name="stat_fastest_pace" <string name="stats_fastest_pace"
translation_description="In the 'Statistics' page, the fastest pace."> translation_description="In the 'Stats' page, the fastest pace.">
Fastest pace Fastest pace
</string> </string>
<string name="stat_latitude" <string name="stats_latitude"
translation_description="In the 'Statistics' page, the latitude."> translation_description="In the 'Stats' page, the latitude.">
Latitude Latitude
</string> </string>
<string name="stat_longitude" <string name="stats_longitude"
translation_description="In the 'Statistics' page, the longitude."> translation_description="In the 'Stats' page, the longitude.">
Longitude Longitude
</string> </string>
<string name="stat_max_elevation" <string name="stats_max_elevation"
translation_description="In the 'Statistics' page, the maximum elevation."> translation_description="In the 'Stats' page, the maximum elevation.">
Max elevation Max elevation
</string> </string>
<string name="stat_max_grade" <string name="stats_max_grade"
translation_description="In the 'Statistics' page, the maximum grade."> translation_description="In the 'Stats' page, the maximum grade.">
Max grade Max grade
</string> </string>
<string name="stat_max_speed" <string name="stats_max_speed"
translation_description="In the 'Statistics' page, the maximum speed."> translation_description="In the 'Stats' page, the maximum speed.">
Max speed Max speed
</string> </string>
<string name="stat_min_elevation" <string name="stats_min_elevation"
translation_description="In the 'Statistics' page, the minimum elevation."> translation_description="In the 'Stats' page, the minimum elevation.">
Min elevation Min elevation
</string> </string>
<string name="stat_min_grade" <string name="stats_min_grade"
translation_description="In the 'Statistics' page, the minimum grade."> translation_description="In the 'Stats' page, the minimum grade.">
Min grade Min grade
</string> </string>
<string name="stat_moving_time" <string name="stats_moving_time"
translation_description="In the 'Statistics' page, the moving time."> translation_description="In the 'Stats' page, the moving time.">
Moving time Moving time
</string> </string>
<string name="stat_pace" <string name="stats_pace"
translation_description="In the 'Statistics' page, the pace like hours per mile."> translation_description="In the 'Stats' page, the pace like hours per mile.">
Pace Pace
</string> </string>
<string name="stat_speed" <string name="stats_speed"
translation_description="In the 'Statistics' page, the speed like miles per hour."> translation_description="In the 'Stats' page, the speed like miles per hour.">
Speed Speed
</string> </string>
<string name="stat_total_distance" <string name="stats_total_distance"
translation_description="In the 'Statistics' page, the total distance."> translation_description="In the 'Stats' page, the total distance.">
Total distance Total distance
</string> </string>
<string name="stat_total_time" <string name="stats_total_time"
translation_description="In the 'Statistics' page, the total time."> translation_description="In the 'Stats' page, the total time.">
Total time Total time
</string> </string>
@@ -2417,6 +2417,13 @@ limitations under the License.
recommended value."> recommended value.">
Smallest (recommended) Smallest (recommended)
</string> </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>
<!-- Voice --> <!-- Voice -->
<string name="voice_hours_few" <string name="voice_hours_few"
+55 -117
View File
@@ -15,20 +15,18 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
--> -->
<resources> <resources>
<style name="ThemeSelector" parent="android:Theme" />
<!-- The style for the bottom button bar -->
<style name="BottomButtonBar" parent="@android:style/DeviceDefault.ButtonBar">
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_width">fill_parent</item>
<item name="android:orientation">horizontal</item>
</style>
<!-- The style for the bottom button --> <!-- The style for the bottom button -->
<style name="BottomButton" parent="@android:style/Widget.DeviceDefault.Button.Borderless"> <style name="BottomButton" parent="@android:style/Widget.DeviceDefault.Button.Borderless">
<item name="android:layout_height">wrap_content</item> <item name="android:layout_height">wrap_content</item>
<item name="android:layout_weight">1</item> <item name="android:layout_weight">1</item>
<item name="android:layout_width">0dp</item> <item name="android:layout_width">0dp</item>
</style> </style>
<!-- The style for the bottom button bar -->
<style name="BottomButtonBar" parent="@android:style/DeviceDefault.ButtonBar">
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_width">fill_parent</item>
<item name="android:orientation">horizontal</item>
</style>
<!-- The style for the edit category --> <!-- The style for the edit category -->
<style name="EditCategory" parent="@android:style/TextAppearance.DeviceDefault.Medium"> <style name="EditCategory" parent="@android:style/TextAppearance.DeviceDefault.Medium">
<item name="android:layout_height">wrap_content</item> <item name="android:layout_height">wrap_content</item>
@@ -38,12 +36,12 @@ limitations under the License.
</style> </style>
<!-- The style for the edit description --> <!-- The style for the edit description -->
<style name="EditDescription" parent="@android:style/TextAppearance.DeviceDefault.Medium"> <style name="EditDescription" parent="@android:style/TextAppearance.DeviceDefault.Medium">
<item name="android:inputType">textAutoCorrect|textCapSentences</item>
<item name="android:layout_height">wrap_content</item> <item name="android:layout_height">wrap_content</item>
<item name="android:layout_width">fill_parent</item> <item name="android:layout_width">fill_parent</item>
<item name="android:maxLines">50</item>
<item name="android:selectAllOnFocus">true</item> <item name="android:selectAllOnFocus">true</item>
<item name="android:singleLine">false</item> <item name="android:singleLine">false</item>
<item name="android:maxLines">50</item>
<item name="android:inputType">textAutoCorrect|textCapSentences</item>
</style> </style>
<!-- The style for the edit label --> <!-- The style for the edit label -->
<style name="EditLabel" parent="@android:style/TextAppearance.DeviceDefault.Medium"> <style name="EditLabel" parent="@android:style/TextAppearance.DeviceDefault.Medium">
@@ -52,13 +50,13 @@ limitations under the License.
</style> </style>
<!-- The style for the edit name --> <!-- The style for the edit name -->
<style name="EditName" parent="@android:style/TextAppearance.DeviceDefault.Medium"> <style name="EditName" parent="@android:style/TextAppearance.DeviceDefault.Medium">
<item name="android:drawablePadding">8dp</item>
<item name="android:gravity">center_vertical</item>
<item name="android:inputType">textAutoCorrect|textCapWords</item>
<item name="android:layout_height">wrap_content</item> <item name="android:layout_height">wrap_content</item>
<item name="android:layout_width">fill_parent</item> <item name="android:layout_width">fill_parent</item>
<item name="android:selectAllOnFocus">true</item> <item name="android:selectAllOnFocus">true</item>
<item name="android:singleLine">true</item> <item name="android:singleLine">true</item>
<item name="android:inputType">textAutoCorrect|textCapWords</item>
<item name="android:drawablePadding">8dp</item>
<item name="android:gravity">center_vertical</item>
</style> </style>
<!-- The style for the list empty text view --> <!-- The style for the list empty text view -->
<style name="ListEmptyTextView" parent="@android:style/TextAppearance.DeviceDefault.Large"> <style name="ListEmptyTextView" parent="@android:style/TextAppearance.DeviceDefault.Large">
@@ -68,138 +66,80 @@ limitations under the License.
<item name="android:layout_width">wrap_content</item> <item name="android:layout_width">wrap_content</item>
<item name="android:padding">8dp</item> <item name="android:padding">8dp</item>
</style> </style>
<!-- The style for the list item category --> <!-- The style for the list item category -->
<style name="ListItemCategory" parent="@android:style/TextAppearance.DeviceDefault.Small"> <style name="ListItemCategory" parent="@android:style/TextAppearance.DeviceDefault.Small">
<item name="android:layout_height">wrap_content</item> <item name="android:layout_height">wrap_content</item>
<item name="android:layout_marginLeft">8dp</item>
<item name="android:layout_width">wrap_content</item> <item name="android:layout_width">wrap_content</item>
<item name="android:singleLine">true</item> <item name="android:singleLine">true</item>
<item name="android:layout_marginLeft">8dp</item>
</style> </style>
<!-- The style for the list item description --> <!-- The style for the list item description -->
<style name="ListItemDescription" parent="@android:style/TextAppearance.DeviceDefault.Small"> <style name="ListItemDescription" parent="@android:style/TextAppearance.DeviceDefault.Small">
<item name="android:layout_height">wrap_content</item> <item name="android:layout_height">wrap_content</item>
<item name="android:layout_width">fill_parent</item> <item name="android:layout_width">fill_parent</item>
<item name="android:singleLine">false</item> <item name="android:singleLine">false</item>
<item name="android:textColor">@android:color/secondary_text_dark</item>
</style> </style>
<!-- The style for the list item name --> <!-- The style for the list item name -->
<style name="ListItemName" parent="@android:style/TextAppearance.DeviceDefault.Large"> <style name="ListItemName" parent="@android:style/TextAppearance.DeviceDefault.Large">
<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:gravity">center_vertical</item> <item name="android:gravity">center_vertical</item>
<item name="android:paddingLeft">9dp</item> <item name="android:layout_height">wrap_content</item>
<item name="android:layout_width">wrap_content</item>
<item name="android:drawablePadding">8dp</item>
<item name="android:singleLine">true</item>
</style> </style>
<!-- style for the list item stat --> <!-- style for the list item stats -->
<style name="ListItemStat" parent="@android:style/TextAppearance.DeviceDefault.Small"> <style name="ListItemStats" parent="@android:style/TextAppearance.DeviceDefault.Small">
<item name="android:layout_height">wrap_content</item> <item name="android:layout_height">wrap_content</item>
<item name="android:layout_width">wrap_content</item> <item name="android:layout_width">wrap_content</item>
<item name="android:singleLine">true</item> <item name="android:singleLine">true</item>
<item name="android:textColor">@color/green</item> <item name="android:textColor">@android:color/secondary_text_dark</item>
</style> </style>
<!-- The style for the marker detail label --> <!-- The style for the marker detail label -->
<style name="MarkerDetailLabel" parent="@android:style/TextAppearance.DeviceDefault.Large"> <style name="MarkerDetailLabel" parent="@android:style/TextAppearance.DeviceDefault.Large">
<item name="android:layout_height">wrap_content</item> <item name="android:layout_height">wrap_content</item>
<item name="android:layout_width">wrap_content</item> <item name="android:layout_width">wrap_content</item>
</style> </style>
<!-- The style for the marker detail statistics label --> <!-- The style for the sensor state label -->
<style name="MarkerDetailStatisticsLabel" parent="@android:style/TextAppearance.DeviceDefault.Medium"> <style name="SensorStateLabel" parent="@android:style/TextAppearance.DeviceDefault.Medium">
<item name="android:layout_height">wrap_content</item> <item name="android:layout_height">wrap_content</item>
<item name="android:layout_width">0dp</item> <item name="android:layout_width">wrap_content</item>
<item name="android:layout_weight">1</item>
</style> </style>
<!-- The style for the marker detail statistics spacer --> <!-- The style for the sensor state value -->
<style name="MarkerDetailStatisticsSpacer"> <style name="SensorStateValue" parent="@android:style/TextAppearance.DeviceDefault.Large">
<item name="android:background">@android:color/background_light</item>
<item name="android:gravity">right</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_width">fill_parent</item>
<item name="android:textColor">@android:color/primary_text_light</item>
</style>
<!-- The style for the scroll view -->
<style name="ScrollView">
<item name="android:layout_height">fill_parent</item>
<item name="android:layout_width">fill_parent</item>
<item name="android:scrollbarStyle">outsideInset</item>
</style>
<!-- The style for the stats label -->
<style name="StatsLabel" parent="@android:style/TextAppearance.DeviceDefault.Medium">
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_weight">1</item>
<item name="android:layout_width">0dp</item>
</style>
<!-- The style for the stats spacer -->
<style name="StatsSpacer">
<item name="android:layout_height">fill_parent</item> <item name="android:layout_height">fill_parent</item>
<item name="android:layout_width">8dp</item> <item name="android:layout_width">8dp</item>
</style> </style>
<!-- The style for the marker detail statistics value --> <!-- The style for the stats value -->
<style name="MarkerDetailStatisticsValue" parent="@android:style/TextAppearance.DeviceDefault.Large"> <style name="StatsValue" parent="@android:style/TextAppearance.DeviceDefault.Large">
<item name="android:gravity">right</item>
<item name="android:textColor">@color/stat_label_text</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_width">0dp</item>
<item name="android:layout_weight">1</item>
<item name="android:background">@android:color/background_light</item> <item name="android:background">@android:color/background_light</item>
</style>
<style name="SensorStateLabel">
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_width">fill_parent</item>
<item name="android:paddingLeft">4dp</item>
<item name="android:paddingRight">4dp</item>
</style>
<style name="SensorStateValue">
<item name="android:background">@color/stat_label_background</item>
<item name="android:gravity">right</item> <item name="android:gravity">right</item>
<item name="android:layout_height">wrap_content</item> <item name="android:layout_height">wrap_content</item>
<item name="android:layout_width">fill_parent</item> <item name="android:layout_weight">1</item>
<item name="android:paddingLeft">4dp</item> <item name="android:layout_width">0dp</item>
<item name="android:paddingRight">4dp</item> <item name="android:textColor">@android:color/primary_text_light</item>
<item name="android:textColor">@color/stat_label_text</item>
<item name="android:textSize">40sp</item>
</style> </style>
<style name="ThemeSelector" parent="android:Theme" />
<!-- The style for a view which divides the numerator and denominator of the units on the statistics activity. -->
<style name="StatsDivider" parent="@android:Widget.TextView">
<item name="android:background">@color/black</item>
<item name="android:layout_height">3dp</item>
<item name="android:layout_width">fill_parent</item>
</style>
<!-- The style for a text view for displaying a value on the statistics activity. -->
<style name="StatsRegister" parent="@android:Widget.TextView">
<item name="android:gravity">right</item>
<item name="android:layout_marginBottom">-9dp</item>
<item name="android:layout_marginTop">-9dp</item>
<item name="android:text">@string/value_unknown</item>
<item name="android:textColor">@color/stat_label_text</item>
<item name="android:textSize">40sp</item>
</style>
<!-- The style for a text view for displaying a large value on the statistics activity. -->
<style name="StatsRegister.Big">
<item name="android:layout_marginBottom">-13dp</item>
<item name="android:layout_marginTop">-13dp</item>
<item name="android:textSize">50sp</item>
</style>
<!-- The style for a text view for displaying a small value on the statistics activity. -->
<style name="StatsRegister.Small">
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_marginBottom">-5dp</item>
<item name="android:layout_marginTop">-5dp</item>
<item name="android:layout_width">fill_parent</item>
<item name="android:textSize">25sp</item>
</style>
<!-- The style for a view which divides two columns in the statistics activity. -->
<style name="StatsSpacer" parent="@android:Widget.TextView">
<item name="android:background">@color/black</item>
<item name="android:layout_marginBottom">-9dp</item>
<item name="android:layout_marginTop">-9dp</item>
<item name="android:layout_width">5dp</item>
<item name="android:textSize">40sp</item>
</style>
<!-- The style for the unit on the statistics activity. -->
<style name="StatsUnit" parent="@android:Widget.TextView">
<item name="android:gravity">bottom</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_marginBottom">-2dp</item>
<item name="android:layout_marginTop">-2dp</item>
<item name="android:layout_width">wrap_content</item>
<item name="android:textColor">@color/stat_label_text</item>
</style>
<!-- The style for the unit on the statistics activity where there is only one string. -->
<style name="StatsUnitSolo" parent="@android:Widget.TextView">
<item name="android:gravity">right</item>
<item name="android:layout_marginBottom">-9dp</item>
<item name="android:layout_marginTop">-9dp</item>
<item name="android:textColor">@color/stat_label_text</item>
</style>
<!-- The style for the welcome page answer --> <!-- The style for the welcome page answer -->
<style name="WelcomeAnswerTextView" parent="@android:style/TextAppearance.DeviceDefault.Small"> <style name="WelcomeAnswerTextView" parent="@android:style/TextAppearance.DeviceDefault.Small">
<item name="android:layout_height">wrap_content</item> <item name="android:layout_height">wrap_content</item>
@@ -210,19 +150,17 @@ limitations under the License.
<style name="WelcomeQuestionTextView" parent="@android:style/TextAppearance.DeviceDefault.Medium"> <style name="WelcomeQuestionTextView" parent="@android:style/TextAppearance.DeviceDefault.Medium">
<item name="android:layout_height">wrap_content</item> <item name="android:layout_height">wrap_content</item>
<item name="android:layout_width">wrap_content</item> <item name="android:layout_width">wrap_content</item>
<item name="android:textStyle">bold</item>
<item name="android:paddingTop">8dp</item> <item name="android:paddingTop">8dp</item>
<item name="android:textStyle">bold</item>
</style> </style>
<!-- The style for the widget label -->
<!-- Widget TextView -->
<style name="WidgetTextView"> <style name="WidgetTextView">
<item name="android:layout_height">wrap_content</item> <item name="android:layout_height">wrap_content</item>
<item name="android:layout_width">wrap_content</item> <item name="android:layout_width">wrap_content</item>
<item name="android:textColor">@color/appwidget_text</item> <item name="android:textColor">@color/appwidget_text</item>
<item name="android:textSize">14sp</item> <item name="android:textSize">14sp</item>
</style> </style>
<!-- The style for the widget value -->
<!-- Widget TextView value -->
<style name="WidgetTextView.Value"> <style name="WidgetTextView.Value">
<item name="android:width">160px</item> <item name="android:width">160px</item>
</style> </style>
@@ -1,3 +1,19 @@
/*
* 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.
*/
package com.google.android.apps.mytracks; package com.google.android.apps.mytracks;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils; import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
@@ -5,88 +21,41 @@ import com.google.android.apps.mytracks.content.Track;
import com.google.android.apps.mytracks.stats.TripStatistics; import com.google.android.apps.mytracks.stats.TripStatistics;
import com.google.android.apps.mytracks.util.ApiAdapterFactory; import com.google.android.apps.mytracks.util.ApiAdapterFactory;
import com.google.android.apps.mytracks.util.IntentUtils; import com.google.android.apps.mytracks.util.IntentUtils;
import com.google.android.apps.mytracks.util.StatsUtils;
import com.google.android.maps.mytracks.R; import com.google.android.maps.mytracks.R;
import android.app.Activity; import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.os.Bundle; import android.os.Bundle;
import android.util.DisplayMetrics; import android.speech.tts.TextToSpeech;
import android.util.Log;
import android.view.MenuItem; import android.view.MenuItem;
import android.widget.ScrollView;
import android.widget.TextView;
import java.util.List; import java.util.List;
/** /**
* Activity for viewing the combined statistics for all the recorded tracks. * An activity to view aggregated stats from all recorded tracks.
*
* Other features to add - menu items to change setings.
* *
* @author Fergus Nelson * @author Fergus Nelson
*/ */
public class AggregatedStatsActivity extends Activity implements public class AggregatedStatsActivity extends Activity {
OnSharedPreferenceChangeListener {
private final StatsUtilities utils;
private MyTracksProviderUtils tracksProvider;
private boolean metricUnits = true;
public AggregatedStatsActivity() {
this.utils = new StatsUtilities(this);
}
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
String key) {
Log.d(Constants.TAG, "StatsActivity: onSharedPreferences changed "
+ key);
if (key != null) {
if (key.equals(getString(R.string.metric_units_key))) {
metricUnits = sharedPreferences.getBoolean(
getString(R.string.metric_units_key), true);
utils.setMetricUnits(metricUnits);
utils.updateUnits();
loadAggregatedStats();
}
}
}
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setVolumeControlStream(TextToSpeech.Engine.DEFAULT_STREAM);
this.tracksProvider = MyTracksProviderUtils.Factory.get(this);
ApiAdapterFactory.getApiAdapter().configureActionBarHomeAsUp(this); ApiAdapterFactory.getApiAdapter().configureActionBarHomeAsUp(this);
setContentView(R.layout.aggregated_stats);
setContentView(R.layout.stats);
ScrollView sv = ((ScrollView) findViewById(R.id.scrolly));
sv.setScrollBarStyle(ScrollView.SCROLLBARS_OUTSIDE_INSET);
SharedPreferences preferences = getSharedPreferences( SharedPreferences preferences = getSharedPreferences(
Constants.SETTINGS_NAME, Context.MODE_PRIVATE); Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
if (preferences != null) { boolean metricUnits = preferences.getBoolean(getString(R.string.metric_units_key), true);
metricUnits = preferences.getBoolean(getString(R.string.metric_units_key), true); boolean reportSpeed = preferences.getBoolean(getString(R.string.report_speed_key), true);
preferences.registerOnSharedPreferenceChangeListener(this);
}
utils.setMetricUnits(metricUnits);
utils.updateUnits();
utils.setSpeedLabel(R.id.speed_label, R.string.stat_speed, R.string.stat_pace);
utils.setSpeedLabels();
DisplayMetrics metrics = new DisplayMetrics(); StatsUtils.setSpeedLabels(this, reportSpeed, false);
getWindowManager().getDefaultDisplay().getMetrics(metrics); StatsUtils.setTripStatisticsValues(this, getTripStatistics(), metricUnits, reportSpeed);
if (metrics.heightPixels > 600) { StatsUtils.setLocationElevationValue(this, Double.NaN, metricUnits);
((TextView) findViewById(R.id.speed_register)).setTextSize(80.0f);
}
loadAggregatedStats();
} }
@Override @Override
@@ -100,30 +69,18 @@ public class AggregatedStatsActivity extends Activity implements
} }
/** /**
* 1. Reads tracks from the db * Gets the aggregated trip statistics for all the recorded tracks or null if
* 2. Merges the trip stats from the tracks * there is no track.
* 3. Updates the view
*/ */
private void loadAggregatedStats() { private TripStatistics getTripStatistics() {
List<Track> tracks = retrieveTracks(); List<Track> tracks = MyTracksProviderUtils.Factory.get(this).getAllTracks();
TripStatistics rollingStats = null; TripStatistics tripStatistics = null;
if (!tracks.isEmpty()) { if (!tracks.isEmpty()) {
rollingStats = new TripStatistics(tracks.iterator().next() tripStatistics = new TripStatistics(tracks.iterator().next().getStatistics());
.getStatistics());
for (int i = 1; i < tracks.size(); i++) { for (int i = 1; i < tracks.size(); i++) {
rollingStats.merge(tracks.get(i).getStatistics()); tripStatistics.merge(tracks.get(i).getStatistics());
} }
} }
updateView(rollingStats); return tripStatistics;
}
private List<Track> retrieveTracks() {
return tracksProvider.getAllTracks();
}
private void updateView(TripStatistics aggStats) {
if (aggStats != null) {
utils.setAllStats(aggStats);
}
} }
} }
@@ -215,7 +215,7 @@ public class ChartView extends View {
R.color.elevation_border, R.color.elevation_border,
new ZoomSettings(MAX_INTERVALS, new ZoomSettings(MAX_INTERVALS,
new int[] {5, 10, 25, 50, 100, 250, 500, 1000, 2500, 5000}), new int[] {5, 10, 25, 50, 100, 250, 500, 1000, 2500, 5000}),
R.string.stat_elevation); R.string.stats_elevation);
series[SPEED_SERIES] = series[SPEED_SERIES] =
new ChartValueSeries(context, new ChartValueSeries(context,
@@ -223,7 +223,7 @@ public class ChartView extends View {
R.color.speed_border, R.color.speed_border,
new ZoomSettings(MAX_INTERVALS, 0, Integer.MIN_VALUE, new ZoomSettings(MAX_INTERVALS, 0, Integer.MIN_VALUE,
new int[] {1, 5, 10, 20, 50}), new int[] {1, 5, 10, 20, 50}),
R.string.stat_speed); R.string.stats_speed);
series[POWER_SERIES] = series[POWER_SERIES] =
new ChartValueSeries(context, new ChartValueSeries(context,
R.color.power_fill, R.color.power_fill,
@@ -270,8 +270,8 @@ public class ChartView extends View {
public void setReportSpeed(boolean reportSpeed, Context c) { public void setReportSpeed(boolean reportSpeed, Context c) {
series[SPEED_SERIES].setTitle(c.getString(reportSpeed series[SPEED_SERIES].setTitle(c.getString(reportSpeed
? R.string.stat_speed ? R.string.stats_speed
: R.string.stat_pace)); : R.string.stats_pace));
} }
private void addDataPointInternal(double[] theData) { private void addDataPointInternal(double[] theData) {
@@ -19,7 +19,6 @@ package com.google.android.apps.mytracks;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils; import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.content.Waypoint; import com.google.android.apps.mytracks.content.Waypoint;
import com.google.android.apps.mytracks.fragments.DeleteOneMarkerDialogFragment; import com.google.android.apps.mytracks.fragments.DeleteOneMarkerDialogFragment;
import com.google.android.apps.mytracks.stats.TripStatistics;
import com.google.android.apps.mytracks.util.ApiAdapterFactory; import com.google.android.apps.mytracks.util.ApiAdapterFactory;
import com.google.android.apps.mytracks.util.IntentUtils; import com.google.android.apps.mytracks.util.IntentUtils;
import com.google.android.apps.mytracks.util.StatsUtils; import com.google.android.apps.mytracks.util.StatsUtils;
@@ -94,44 +93,9 @@ public class MarkerDetailActivity extends FragmentActivity {
boolean metricUnits = preferences.getBoolean(getString(R.string.metric_units_key), true); boolean metricUnits = preferences.getBoolean(getString(R.string.metric_units_key), true);
boolean reportSpeed = preferences.getBoolean(getString(R.string.report_speed_key), true); boolean reportSpeed = preferences.getBoolean(getString(R.string.report_speed_key), true);
StatsUtils.setSpeedLabel(this, R.id.marker_detail_max_speed_label, R.string.stat_max_speed, StatsUtils.setSpeedLabels(this, reportSpeed, false);
R.string.stat_fastest_pace, reportSpeed); StatsUtils.setTripStatisticsValues(this, waypoint.getStatistics(), metricUnits, reportSpeed);
StatsUtils.setSpeedLabel(this, R.id.marker_detail_average_speed_label, StatsUtils.setLocationElevationValue(this, waypoint.getLocation().getAltitude(), metricUnits);
R.string.stat_average_speed, R.string.stat_average_pace, reportSpeed);
StatsUtils.setSpeedLabel(this, R.id.marker_detail_average_moving_speed_label,
R.string.stat_average_moving_speed, R.string.stat_average_moving_pace, reportSpeed);
TripStatistics tripStatistics = waypoint.getStatistics();
StatsUtils.setDistanceValue(this, R.id.marker_detail_total_distance_value,
tripStatistics.getTotalDistance(), metricUnits);
StatsUtils.setSpeedValue(this, R.id.marker_detail_max_speed_value,
tripStatistics.getMaxSpeed(), reportSpeed, metricUnits);
StatsUtils.setTimeValue(
this, R.id.marker_detail_total_time_value, tripStatistics.getTotalTime());
StatsUtils.setSpeedValue(this, R.id.marker_detail_average_speed_value,
tripStatistics.getAverageSpeed(), reportSpeed, metricUnits);
StatsUtils.setTimeValue(
this, R.id.marker_detail_moving_time_value, tripStatistics.getMovingTime());
StatsUtils.setSpeedValue(this, R.id.marker_detail_average_moving_speed_value,
tripStatistics.getAverageMovingSpeed(), reportSpeed, metricUnits);
StatsUtils.setAltitudeValue(this, R.id.marker_detail_elevation_value,
waypoint.getLocation().getAltitude(), metricUnits);
StatsUtils.setAltitudeValue(this, R.id.marker_detail_elevation_gain_value,
tripStatistics.getTotalElevationGain(), metricUnits);
StatsUtils.setAltitudeValue(this, R.id.marker_detail_min_elevation_value,
tripStatistics.getMinElevation(), metricUnits);
StatsUtils.setAltitudeValue(this, R.id.marker_detail_max_elevation_value,
tripStatistics.getMaxElevation(), metricUnits);
StatsUtils.setGradeValue(
this, R.id.marker_detail_min_grade_value, tripStatistics.getMinGrade());
StatsUtils.setGradeValue(
this, R.id.marker_detail_max_grade_value, tripStatistics.getMaxGrade());
} }
} }
@@ -45,8 +45,6 @@ public class SensorStateActivity extends Activity {
private static final long REFRESH_PERIOD_MS = 250; private static final long REFRESH_PERIOD_MS = 250;
private final StatsUtilities utils;
/** /**
* This timer periodically invokes the refresh timer task. * This timer periodically invokes the refresh timer task.
*/ */
@@ -91,11 +89,6 @@ public class SensorStateActivity extends Activity {
*/ */
private boolean isVisible = false; private boolean isVisible = false;
public SensorStateActivity() {
utils = new StatsUtilities(this);
Log.w(TAG, "SensorStateActivity()");
}
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
@@ -239,18 +232,18 @@ public class SensorStateActivity extends Activity {
} }
private void updateSensorData(Sensor.SensorDataSet sds) { private void updateSensorData(Sensor.SensorDataSet sds) {
if (sds == null) { String lastSensorTime = sds == null ? getString(R.string.value_unknown)
utils.setUnknown(R.id.sensor_state_last_sensor_time); : getLastSensorTime(sds);
utils.setUnknown(R.id.sensor_state_power); String power = sds == null ? getString(R.string.value_unknown) : getPower(sds);
utils.setUnknown(R.id.sensor_state_cadence); String cadence = sds == null ? getString(R.string.value_unknown) : getCadence(sds);
utils.setUnknown(R.id.sensor_state_battery); String heartRate = sds == null ? getString(R.string.value_unknown) : getHeartRate(sds);
} else { String battery = sds == null ? getString(R.string.value_unknown) : getBattery(sds);
((TextView) findViewById(R.id.sensor_state_last_sensor_time)).setText(getLastSensorTime(sds));
((TextView) findViewById(R.id.sensor_state_power)).setText(getPower(sds)); ((TextView) findViewById(R.id.sensor_state_last_sensor_time)).setText(lastSensorTime);
((TextView) findViewById(R.id.sensor_state_cadence)).setText(getCadence(sds)); ((TextView) findViewById(R.id.sensor_state_power)).setText(power);
((TextView) findViewById(R.id.sensor_state_heart_rate)).setText(getHeartRate(sds)); ((TextView) findViewById(R.id.sensor_state_cadence)).setText(cadence);
((TextView) findViewById(R.id.sensor_state_battery)).setText(getBattery(sds)); ((TextView) findViewById(R.id.sensor_state_heart_rate)).setText(heartRate);
} ((TextView) findViewById(R.id.sensor_state_battery)).setText(battery);
} }
/** /**
@@ -325,8 +318,7 @@ public class SensorStateActivity extends Activity {
String value; String value;
if (sds.hasBatteryLevel() && sds.getBatteryLevel().hasValue() if (sds.hasBatteryLevel() && sds.getBatteryLevel().hasValue()
&& sds.getBatteryLevel().getState() == Sensor.SensorState.SENDING) { && sds.getBatteryLevel().getState() == Sensor.SensorState.SENDING) {
String format = getString(R.string.value_integer_percent); value = getString(R.string.value_integer_percent, sds.getBatteryLevel().getValue());
value = String.format(format, sds.getBatteryLevel().getValue());
} else { } else {
value = SensorUtils.getStateAsString( value = SensorUtils.getStateAsString(
sds.hasBatteryLevel() ? sds.getBatteryLevel().getState() : Sensor.SensorState.NONE, this); sds.hasBatteryLevel() ? sds.getBatteryLevel().getState() : Sensor.SensorState.NONE, this);
@@ -1,270 +0,0 @@
/*
* Copyright 2009 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks;
import com.google.android.apps.mytracks.stats.TripStatistics;
import com.google.android.apps.mytracks.util.StatsUtils;
import com.google.android.apps.mytracks.util.StringUtils;
import com.google.android.apps.mytracks.util.UnitConversions;
import com.google.android.maps.mytracks.R;
import android.app.Activity;
import android.util.Log;
import android.widget.TextView;
import java.text.NumberFormat;
/**
* Various utility functions for views that display statistics information.
*
* @deprecated use {@link StatsUtils}.
*
* @author Sandor Dornbush
*/
public class StatsUtilities {
private final Activity activity;
private static final NumberFormat LAT_LONG_FORMAT = NumberFormat.getNumberInstance();
private static final NumberFormat ALTITUDE_FORMAT = NumberFormat.getIntegerInstance();
private static final NumberFormat SPEED_FORMAT = NumberFormat.getNumberInstance();
private static final NumberFormat GRADE_FORMAT = NumberFormat.getPercentInstance();
static {
LAT_LONG_FORMAT.setMaximumFractionDigits(5);
LAT_LONG_FORMAT.setMinimumFractionDigits(5);
SPEED_FORMAT.setMaximumFractionDigits(2);
SPEED_FORMAT.setMinimumFractionDigits(2);
GRADE_FORMAT.setMaximumFractionDigits(1);
GRADE_FORMAT.setMinimumFractionDigits(1);
}
/**
* True if distances should be displayed in metric units (from shared
* preferences).
*/
private boolean metricUnits = true;
/**
* True - report speed
* False - report pace
*/
private boolean reportSpeed = true;
public StatsUtilities(Activity a) {
this.activity = a;
}
public boolean isMetricUnits() {
return metricUnits;
}
public void setMetricUnits(boolean metricUnits) {
this.metricUnits = metricUnits;
}
public boolean isReportSpeed() {
return reportSpeed;
}
public void setReportSpeed(boolean reportSpeed) {
this.reportSpeed = reportSpeed;
}
public void setUnknown(int id) {
((TextView) activity.findViewById(id)).setText(R.string.value_unknown);
}
public void setText(int id, double d, NumberFormat format) {
if (!Double.isNaN(d) && !Double.isInfinite(d)) {
setText(id, format.format(d));
} else {
setUnknown(id);
}
}
public void setText(int id, String s) {
int lengthLimit = 8;
String displayString = s.length() > lengthLimit
? s.substring(0, lengthLimit - 3) + "..."
: s;
((TextView) activity.findViewById(id)).setText(displayString);
}
public void setLatLong(int id, double d) {
TextView msgTextView = (TextView) activity.findViewById(id);
msgTextView.setText(LAT_LONG_FORMAT.format(d));
}
public void setAltitude(int id, double d) {
setText(id, (metricUnits ? d : (d * UnitConversions.M_TO_FT)),
ALTITUDE_FORMAT);
}
public void setDistance(int id, double d) {
setText(id, (metricUnits ? d : (d * UnitConversions.KM_TO_MI)),
SPEED_FORMAT);
}
public void setSpeed(int id, double d) {
if (d == 0) {
setUnknown(id);
return;
}
double speed = metricUnits ? d : d * UnitConversions.KM_TO_MI;
if (reportSpeed) {
setText(id, speed, SPEED_FORMAT);
} else {
// Format as milliseconds per unit
long pace = (long) (3600000.0 / speed);
setTime(id, pace);
}
}
public void setAltitudeUnits(int unitLabelId) {
TextView unitTextView = (TextView) activity.findViewById(unitLabelId);
unitTextView.setText(metricUnits ? R.string.unit_meter : R.string.unit_feet);
}
public void setDistanceUnits(int unitLabelId) {
TextView unitTextView = (TextView) activity.findViewById(unitLabelId);
unitTextView.setText(metricUnits ? R.string.unit_kilometer : R.string.unit_mile);
}
public void setSpeedUnits(int unitLabelId, int unitLabelBottomId) {
TextView unitTextView = (TextView) activity.findViewById(unitLabelId);
unitTextView.setText(reportSpeed
? (metricUnits ? R.string.unit_kilometer : R.string.unit_mile)
: R.string.unit_minute);
unitTextView = (TextView) activity.findViewById(unitLabelBottomId);
unitTextView.setText(reportSpeed
? R.string.unit_hour
: (metricUnits ? R.string.unit_kilometer : R.string.unit_mile));
}
public void setTime(int id, long l) {
setText(id, StringUtils.formatElapsedTime(l));
}
public void setGrade(int id, double d) {
setText(id, d, GRADE_FORMAT);
}
/**
* Updates the unit fields.
*/
public void updateUnits() {
setSpeedUnits(R.id.speed_unit_label_top, R.id.speed_unit_label_bottom);
updateWaypointUnits();
}
/**
* Updates the units fields used by waypoints.
*/
public void updateWaypointUnits() {
setSpeedUnits(R.id.average_moving_speed_unit_label_top,
R.id.average_moving_speed_unit_label_bottom);
setSpeedUnits(R.id.average_speed_unit_label_top,
R.id.average_speed_unit_label_bottom);
setDistanceUnits(R.id.total_distance_unit_label);
setSpeedUnits(R.id.max_speed_unit_label_top,
R.id.max_speed_unit_label_bottom);
setAltitudeUnits(R.id.elevation_unit_label);
setAltitudeUnits(R.id.elevation_gain_unit_label);
setAltitudeUnits(R.id.min_elevation_unit_label);
setAltitudeUnits(R.id.max_elevation_unit_label);
}
/**
* Sets all fields to "-" (unknown).
*/
public void setAllToUnknown() {
// "Instant" values:
setUnknown(R.id.elevation_register);
setUnknown(R.id.latitude_register);
setUnknown(R.id.longitude_register);
setUnknown(R.id.speed_register);
// Values from provider:
setUnknown(R.id.total_time_register);
setUnknown(R.id.moving_time_register);
setUnknown(R.id.total_distance_register);
setUnknown(R.id.average_speed_register);
setUnknown(R.id.average_moving_speed_register);
setUnknown(R.id.max_speed_register);
setUnknown(R.id.min_elevation_register);
setUnknown(R.id.max_elevation_register);
setUnknown(R.id.elevation_gain_register);
setUnknown(R.id.min_grade_register);
setUnknown(R.id.max_grade_register);
}
public void setAllStats(long movingTime, double totalDistance,
double averageSpeed, double averageMovingSpeed, double maxSpeed,
double minElevation, double maxElevation, double elevationGain,
double minGrade, double maxGrade) {
setTime(R.id.moving_time_register, movingTime);
setDistance(R.id.total_distance_register, totalDistance * UnitConversions.M_TO_KM);
setSpeed(R.id.average_speed_register, averageSpeed * UnitConversions.MS_TO_KMH);
setSpeed(R.id.average_moving_speed_register, averageMovingSpeed * UnitConversions.MS_TO_KMH);
setSpeed(R.id.max_speed_register, maxSpeed * UnitConversions.MS_TO_KMH);
setAltitude(R.id.min_elevation_register, minElevation);
setAltitude(R.id.max_elevation_register, maxElevation);
setAltitude(R.id.elevation_gain_register, elevationGain);
setGrade(R.id.min_grade_register, minGrade);
setGrade(R.id.max_grade_register, maxGrade);
}
public void setAllStats(TripStatistics stats) {
setTime(R.id.moving_time_register, stats.getMovingTime());
setDistance(R.id.total_distance_register, stats.getTotalDistance() * UnitConversions.M_TO_KM);
setSpeed(R.id.average_speed_register, stats.getAverageSpeed() * UnitConversions.MS_TO_KMH);
setSpeed(R.id.average_moving_speed_register,
stats.getAverageMovingSpeed() * UnitConversions.MS_TO_KMH);
setSpeed(R.id.max_speed_register, stats.getMaxSpeed() * UnitConversions.MS_TO_KMH);
setAltitude(R.id.min_elevation_register, stats.getMinElevation());
setAltitude(R.id.max_elevation_register, stats.getMaxElevation());
setAltitude(R.id.elevation_gain_register, stats.getTotalElevationGain());
setGrade(R.id.min_grade_register, stats.getMinGrade());
setGrade(R.id.max_grade_register, stats.getMaxGrade());
setTime(R.id.total_time_register, stats.getTotalTime());
}
public void setSpeedLabel(int id, int speedString, int paceString) {
Log.w(Constants.TAG, "Setting view " + id +
" to " + reportSpeed +
" speed: " + speedString +
" pace: " + paceString);
TextView tv = ((TextView) activity.findViewById(id));
if (tv != null) {
tv.setText(reportSpeed ? speedString : paceString);
} else {
Log.w(Constants.TAG, "Could not find id: " + id);
}
}
public void setSpeedLabels() {
setSpeedLabel(R.id.average_speed_label,
R.string.stat_average_speed,
R.string.stat_average_pace);
setSpeedLabel(R.id.average_moving_speed_label,
R.string.stat_average_moving_speed,
R.string.stat_average_moving_pace);
setSpeedLabel(R.id.max_speed_label,
R.string.stat_max_speed,
R.string.stat_fastest_pace);
}
}
@@ -63,7 +63,7 @@ public class ChartSettingsDialogFragment extends DialogFragment {
checkBoxes[i].setChecked(chartFragment.isChartValueSeriesEnabled(i)); checkBoxes[i].setChecked(chartFragment.isChartValueSeriesEnabled(i));
} }
checkBoxes[ChartView.SPEED_SERIES].setText(chartFragment.isReportSpeed() checkBoxes[ChartView.SPEED_SERIES].setText(chartFragment.isReportSpeed()
? R.string.stat_speed : R.string.stat_pace); ? R.string.stats_speed : R.string.stats_pace);
return new AlertDialog.Builder(getActivity()) return new AlertDialog.Builder(getActivity())
.setCancelable(true) .setCancelable(true)
@@ -16,17 +16,20 @@
package com.google.android.apps.mytracks.fragments; package com.google.android.apps.mytracks.fragments;
import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.MyTracksApplication; import com.google.android.apps.mytracks.MyTracksApplication;
import com.google.android.apps.mytracks.StatsUtilities;
import com.google.android.apps.mytracks.content.Track; import com.google.android.apps.mytracks.content.Track;
import com.google.android.apps.mytracks.content.TrackDataHub; import com.google.android.apps.mytracks.content.TrackDataHub;
import com.google.android.apps.mytracks.content.TrackDataHub.ListenerDataType; import com.google.android.apps.mytracks.content.TrackDataHub.ListenerDataType;
import com.google.android.apps.mytracks.content.TrackDataListener; import com.google.android.apps.mytracks.content.TrackDataListener;
import com.google.android.apps.mytracks.content.Waypoint; import com.google.android.apps.mytracks.content.Waypoint;
import com.google.android.apps.mytracks.stats.TripStatistics;
import com.google.android.apps.mytracks.util.PreferencesUtils; import com.google.android.apps.mytracks.util.PreferencesUtils;
import com.google.android.apps.mytracks.util.UnitConversions; import com.google.android.apps.mytracks.util.StatsUtils;
import com.google.android.maps.mytracks.R; import com.google.android.maps.mytracks.R;
import android.content.Context;
import android.content.SharedPreferences;
import android.location.Location; import android.location.Location;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
@@ -34,7 +37,6 @@ import android.util.Log;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.ScrollView;
import java.util.EnumSet; import java.util.EnumSet;
@@ -48,18 +50,22 @@ public class StatsFragment extends Fragment implements TrackDataListener {
private static final String TAG = StatsFragment.class.getSimpleName(); private static final String TAG = StatsFragment.class.getSimpleName();
private StatsUtilities statsUtilities;
private TrackDataHub trackDataHub; private TrackDataHub trackDataHub;
private UiUpdateThread uiUpdateThread; private UiUpdateThread uiUpdateThread;
// The start time of the current track. // The start time of the current track.
private long startTime = -1L; private long startTime = -1L;
private boolean metricUnits = true;
private boolean reportSpeed = true;
private Location lastLocation = null;
private TripStatistics lastTripStatistics = null;
// A runnable to update the total time field. // A runnable to update the total time field.
private final Runnable updateTotalTime = new Runnable() { private final Runnable updateTotalTime = new Runnable() {
public void run() { public void run() {
if (isRecording()) { if (isRecording()) {
statsUtilities.setTime(R.id.total_time_register, System.currentTimeMillis() - startTime); StatsUtils.setTotalTimeValue(getActivity(), System.currentTimeMillis() - startTime);
} }
} }
}; };
@@ -68,7 +74,6 @@ public class StatsFragment extends Fragment implements TrackDataListener {
* A thread that updates the total time field every second. * A thread that updates the total time field every second.
*/ */
private class UiUpdateThread extends Thread { private class UiUpdateThread extends Thread {
@Override @Override
public void run() { public void run() {
Log.d(TAG, "UI update thread started"); Log.d(TAG, "UI update thread started");
@@ -85,12 +90,6 @@ public class StatsFragment extends Fragment implements TrackDataListener {
} }
} }
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
statsUtilities = new StatsUtilities(getActivity());
}
@Override @Override
public View onCreateView( public View onCreateView(
LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
@@ -100,10 +99,11 @@ public class StatsFragment extends Fragment implements TrackDataListener {
@Override @Override
public void onActivityCreated(Bundle savedInstanceState) { public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState); super.onActivityCreated(savedInstanceState);
ScrollView scrollView = (ScrollView) getActivity().findViewById(R.id.scrolly); SharedPreferences preferences = getActivity().getSharedPreferences(
scrollView.setScrollBarStyle(ScrollView.SCROLLBARS_OUTSIDE_INSET); Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
updateLabels(); metricUnits = preferences.getBoolean(getString(R.string.metric_units_key), true);
setLocationUnknown(); reportSpeed = preferences.getBoolean(getString(R.string.report_speed_key), true);
updateUi();
} }
@Override @Override
@@ -128,7 +128,8 @@ public class StatsFragment extends Fragment implements TrackDataListener {
getActivity().runOnUiThread(new Runnable() { getActivity().runOnUiThread(new Runnable() {
@Override @Override
public void run() { public void run() {
setLocationUnknown(); lastLocation = null;
StatsUtils.setLocationValues(getActivity(), lastLocation, metricUnits, reportSpeed);
} }
}); });
} }
@@ -140,11 +141,8 @@ public class StatsFragment extends Fragment implements TrackDataListener {
getActivity().runOnUiThread(new Runnable() { getActivity().runOnUiThread(new Runnable() {
@Override @Override
public void run() { public void run() {
if (location != null) { lastLocation = location;
setLocation(location); StatsUtils.setLocationValues(getActivity(), lastLocation, metricUnits, reportSpeed);
} else {
setLocationUnknown();
}
} }
}); });
} }
@@ -172,16 +170,18 @@ public class StatsFragment extends Fragment implements TrackDataListener {
@Override @Override
public void run() { public void run() {
if (track == null || track.getStatistics() == null) { if (track == null || track.getStatistics() == null) {
statsUtilities.setAllToUnknown(); lastLocation = null;
lastTripStatistics = null;
updateUi();
return; return;
} }
lastTripStatistics = track.getStatistics();
startTime = track.getStatistics().getStartTime(); startTime = track.getStatistics().getStartTime();
if (!isRecording()) { if (!isRecording()) {
statsUtilities.setTime(R.id.total_time_register, track.getStatistics().getTotalTime()); lastLocation = null;
setLocationUnknown();
} }
statsUtilities.setAllStats(track.getStatistics()); updateUi();
} }
}); });
} }
@@ -227,30 +227,24 @@ public class StatsFragment extends Fragment implements TrackDataListener {
} }
@Override @Override
public boolean onUnitsChanged(boolean metric) { public boolean onUnitsChanged(final boolean metric) {
if (statsUtilities.isMetricUnits() == metric) {
return false;
}
statsUtilities.setMetricUnits(metric);
getActivity().runOnUiThread(new Runnable() { getActivity().runOnUiThread(new Runnable() {
@Override @Override
public void run() { public void run() {
updateLabels(); metricUnits = metric;
updateUi();
} }
}); });
return true; return true;
} }
@Override @Override
public boolean onReportSpeedChanged(boolean speed) { public boolean onReportSpeedChanged(final boolean speed) {
if (statsUtilities.isReportSpeed() == speed) {
return false;
}
statsUtilities.setReportSpeed(speed);
getActivity().runOnUiThread(new Runnable() { getActivity().runOnUiThread(new Runnable() {
@Override @Override
public void run() { public void run() {
updateLabels(); reportSpeed = speed;
updateUi();
} }
}); });
return true; return true;
@@ -286,34 +280,9 @@ public class StatsFragment extends Fragment implements TrackDataListener {
return trackDataHub != null && trackDataHub.isRecordingSelected(); return trackDataHub != null && trackDataHub.isRecordingSelected();
} }
/** private void updateUi() {
* Updates the labels. StatsUtils.setSpeedLabels(getActivity(), reportSpeed, true);
*/ StatsUtils.setTripStatisticsValues(getActivity(), lastTripStatistics, metricUnits, reportSpeed);
private void updateLabels() { StatsUtils.setLocationValues(getActivity(), lastLocation, metricUnits, reportSpeed);
statsUtilities.updateUnits();
statsUtilities.setSpeedLabel(R.id.speed_label, R.string.stat_speed, R.string.stat_pace);
statsUtilities.setSpeedLabels();
}
/**
* Sets the current location.
*
* @param location the current location
*/
private void setLocation(Location location) {
statsUtilities.setAltitude(R.id.elevation_register, location.getAltitude());
statsUtilities.setLatLong(R.id.latitude_register, location.getLatitude());
statsUtilities.setLatLong(R.id.longitude_register, location.getLongitude());
statsUtilities.setSpeed(R.id.speed_register, location.getSpeed() * UnitConversions.MS_TO_KMH);
}
/**
* Sets the current location to unknown.
*/
private void setLocationUnknown() {
statsUtilities.setUnknown(R.id.elevation_register);
statsUtilities.setUnknown(R.id.latitude_register);
statsUtilities.setUnknown(R.id.longitude_register);
statsUtilities.setUnknown(R.id.speed_register);
} }
} }
@@ -58,7 +58,7 @@ public class ChartURLGenerator {
} }
return getChartUrl(distances, elevations, track, return getChartUrl(distances, elevations, track,
context.getString(R.string.stat_elevation), metricUnits); context.getString(R.string.stats_elevation), metricUnits);
} }
/** /**
@@ -16,9 +16,11 @@
package com.google.android.apps.mytracks.util; package com.google.android.apps.mytracks.util;
import com.google.android.apps.mytracks.stats.TripStatistics;
import com.google.android.maps.mytracks.R; import com.google.android.maps.mytracks.R;
import android.app.Activity; import android.app.Activity;
import android.location.Location;
import android.widget.TextView; import android.widget.TextView;
/** /**
@@ -30,6 +32,114 @@ public class StatsUtils {
private StatsUtils() {} private StatsUtils() {}
/**
* Sets the speed labels.
*
* @param activity the activity
* @param reportSpeed true to report speed
* @param includeLocationSpeed true to include the current location speed
*/
public static void setSpeedLabels(
Activity activity, boolean reportSpeed, boolean includeLocationSpeed) {
StatsUtils.setSpeedLabel(activity, R.id.stats_max_speed_label, R.string.stats_max_speed,
R.string.stats_fastest_pace, reportSpeed);
StatsUtils.setSpeedLabel(activity, R.id.stats_average_speed_label, R.string.stats_average_speed,
R.string.stats_average_pace, reportSpeed);
StatsUtils.setSpeedLabel(activity, R.id.stats_average_moving_speed_label,
R.string.stats_average_moving_speed, R.string.stats_average_moving_pace, reportSpeed);
if (includeLocationSpeed) {
StatsUtils.setSpeedLabel(
activity, R.id.stats_speed_label, R.string.stats_speed, R.string.stats_pace, reportSpeed);
}
}
/**
* Sets the trip statistics values.
*
* @param activity the activity
* @param tripStatistics the trip statistics
* @param metricUnits true to display in metric units
* @param reportSpeed true to report speed
*/
public static void setTripStatisticsValues(
Activity activity, TripStatistics tripStatistics, boolean metricUnits, boolean reportSpeed) {
double totalDistance = tripStatistics == null ? Double.NaN : tripStatistics.getTotalDistance();
double maxSpeed = tripStatistics == null ? Double.NaN : tripStatistics.getMaxSpeed();
long totalTime = tripStatistics == null ? -1L : tripStatistics.getTotalTime();
double averageSpeed = tripStatistics == null ? Double.NaN : tripStatistics.getAverageSpeed();
long movingTime = tripStatistics == null ? -1L : tripStatistics.getMovingTime();
double averageMovingSpeed = tripStatistics == null ? Double.NaN
: tripStatistics.getAverageMovingSpeed();
double elevationGain = tripStatistics == null ? Double.NaN
: tripStatistics.getTotalElevationGain();
double minElevation = tripStatistics == null ? Double.NaN : tripStatistics.getMinElevation();
double maxElevation = tripStatistics == null ? Double.NaN : tripStatistics.getMaxElevation();
double minGrade = tripStatistics == null ? Double.NaN : tripStatistics.getMinGrade();
double maxGrade = tripStatistics == null ? Double.NaN : tripStatistics.getMaxGrade();
StatsUtils.setDistanceValue(
activity, R.id.stats_total_distance_value, totalDistance, metricUnits);
StatsUtils.setSpeedValue(
activity, R.id.stats_max_speed_value, maxSpeed, metricUnits, reportSpeed);
StatsUtils.setTimeValue(activity, R.id.stats_total_time_value, totalTime);
StatsUtils.setSpeedValue(
activity, R.id.stats_average_speed_value, averageSpeed, metricUnits, reportSpeed);
StatsUtils.setTimeValue(activity, R.id.stats_moving_time_value, movingTime);
StatsUtils.setSpeedValue(activity, R.id.stats_average_moving_speed_value, averageMovingSpeed,
metricUnits, reportSpeed);
StatsUtils.setAltitudeValue(
activity, R.id.stats_elevation_gain_value, elevationGain, metricUnits);
StatsUtils.setAltitudeValue(
activity, R.id.stats_min_elevation_value, minElevation, metricUnits);
StatsUtils.setAltitudeValue(
activity, R.id.stats_max_elevation_value, maxElevation, metricUnits);
StatsUtils.setGradeValue(activity, R.id.stats_min_grade_value, minGrade);
StatsUtils.setGradeValue(activity, R.id.stats_max_grade_value, maxGrade);
}
/**
* Sets the location values.
*
* @param activity the activity
* @param location the location
* @param metricUnits true to display in metric units
* @param reportSpeed true to report speed
*/
public static void setLocationValues(
Activity activity, Location location, boolean metricUnits, boolean reportSpeed) {
double speed = location == null ? Double.NaN : location.getSpeed();
double altitude = location == null ? Double.NaN : location.getAltitude();
double latitude = location == null ? Double.NaN : location.getLatitude();
double longitude = location == null ? Double.NaN : location.getLongitude();
StatsUtils.setSpeedValue(activity, R.id.stats_speed_value, speed, metricUnits, reportSpeed);
StatsUtils.setAltitudeValue(activity, R.id.stats_elevation_value, altitude, metricUnits);
StatsUtils.setCoordinateValue(activity, R.id.stats_latitude_value, latitude);
StatsUtils.setCoordinateValue(activity, R.id.stats_longitude_value, longitude);
}
/**
* Sets the location elevation value.
*
* @param activity the activity
* @param elevation the elevation in meters
* @param metricUnits true to display in metric units
*/
public static void setLocationElevationValue(
Activity activity, double elevation, boolean metricUnits) {
StatsUtils.setAltitudeValue(activity, R.id.stats_elevation_value, elevation, metricUnits);
}
/**
* Sets the total time value.
*
* @param activity the activity
* @param totalTime the total time
*/
public static void setTotalTimeValue(Activity activity, long totalTime) {
StatsUtils.setTimeValue(activity, R.id.stats_total_time_value, totalTime);
}
/** /**
* Sets a speed label. * Sets a speed label.
* *
@@ -39,7 +149,7 @@ public class StatsUtils {
* @param paceId the pace string id * @param paceId the pace string id
* @param reportSpeed true to report speed * @param reportSpeed true to report speed
*/ */
public static void setSpeedLabel( private static void setSpeedLabel(
Activity activity, int id, int speedId, int paceId, boolean reportSpeed) { Activity activity, int id, int speedId, int paceId, boolean reportSpeed) {
TextView textView = (TextView) activity.findViewById(id); TextView textView = (TextView) activity.findViewById(id);
textView.setText(reportSpeed ? speedId : paceId); textView.setText(reportSpeed ? speedId : paceId);
@@ -51,30 +161,34 @@ public class StatsUtils {
* @param activity the activity * @param activity the activity
* @param id the speed value resource id * @param id the speed value resource id
* @param speed the speed in meters per second * @param speed the speed in meters per second
* @param reportSpeed true to report speed
* @param metricUnits true to display in metric units * @param metricUnits true to display in metric units
* @param reportSpeed true to report speed
*/ */
public static void setSpeedValue( private static void setSpeedValue(
Activity activity, int id, double speed, boolean reportSpeed, boolean metricUnits) { Activity activity, int id, double speed, boolean metricUnits, boolean reportSpeed) {
TextView textView = (TextView) activity.findViewById(id); TextView textView = (TextView) activity.findViewById(id);
speed *= UnitConversions.MS_TO_KMH;
String value; String value;
if (metricUnits) { if (Double.isNaN(speed) || Double.isInfinite(speed)) {
if (reportSpeed) { value = activity.getString(R.string.value_unknown);
value = activity.getString(R.string.value_float_kilometer_hour, speed);
} else {
// convert from hours to minutes
double pace = speed == 0 ? 0.0 : 60.0 / speed;
value = activity.getString(R.string.value_float_minute_kilometer, pace);
}
} else { } else {
speed *= UnitConversions.KM_TO_MI; speed *= UnitConversions.MS_TO_KMH;
if (reportSpeed) { if (metricUnits) {
value = activity.getString(R.string.value_float_mile_hour, speed); if (reportSpeed) {
value = activity.getString(R.string.value_float_kilometer_hour, speed);
} else {
// convert from hours to minutes
double pace = speed == 0 ? 0.0 : 60.0 / speed;
value = activity.getString(R.string.value_float_minute_kilometer, pace);
}
} else { } else {
// convert from hours to minutes speed *= UnitConversions.KM_TO_MI;
double pace = speed == 0 ? 0.0 : 60.0 / speed; if (reportSpeed) {
value = activity.getString(R.string.value_float_minute_mile, pace); value = activity.getString(R.string.value_float_mile_hour, speed);
} else {
// convert from hours to minutes
double pace = speed == 0 ? 0.0 : 60.0 / speed;
value = activity.getString(R.string.value_float_minute_mile, pace);
}
} }
} }
textView.setText(value); textView.setText(value);
@@ -88,16 +202,20 @@ public class StatsUtils {
* @param distance the distance in meters * @param distance the distance in meters
* @param metricUnits true to display in metric units * @param metricUnits true to display in metric units
*/ */
public static void setDistanceValue( private static void setDistanceValue(
Activity activity, int id, double distance, boolean metricUnits) { Activity activity, int id, double distance, boolean metricUnits) {
TextView textView = (TextView) activity.findViewById(id); TextView textView = (TextView) activity.findViewById(id);
distance *= UnitConversions.M_TO_KM;
String value; String value;
if (metricUnits) { if (Double.isNaN(distance) || Double.isInfinite(distance)) {
value = activity.getString(R.string.value_float_kilometer, distance); value = activity.getString(R.string.value_unknown);
} else { } else {
distance *= UnitConversions.KM_TO_MI; distance *= UnitConversions.M_TO_KM;
value = activity.getString(R.string.value_float_mile, distance); if (metricUnits) {
value = activity.getString(R.string.value_float_kilometer, distance);
} else {
distance *= UnitConversions.KM_TO_MI;
value = activity.getString(R.string.value_float_mile, distance);
}
} }
textView.setText(value); textView.setText(value);
} }
@@ -109,9 +227,11 @@ public class StatsUtils {
* @param id the time value resource id * @param id the time value resource id
* @param time the time * @param time the time
*/ */
public static void setTimeValue(Activity activity, int id, long time) { private static void setTimeValue(Activity activity, int id, long time) {
TextView textView = (TextView) activity.findViewById(id); TextView textView = (TextView) activity.findViewById(id);
textView.setText(StringUtils.formatElapsedTime(time)); String value = time == -1L ? activity.getString(R.string.value_unknown)
: StringUtils.formatElapsedTime(time);
textView.setText(value);
} }
/** /**
@@ -122,7 +242,7 @@ public class StatsUtils {
* @param altitude the altitude in meters * @param altitude the altitude in meters
* @param metricUnits true to display in metric units * @param metricUnits true to display in metric units
*/ */
public static void setAltitudeValue( private static void setAltitudeValue(
Activity activity, int id, double altitude, boolean metricUnits) { Activity activity, int id, double altitude, boolean metricUnits) {
TextView textView = (TextView) activity.findViewById(id); TextView textView = (TextView) activity.findViewById(id);
String value; String value;
@@ -146,7 +266,7 @@ public class StatsUtils {
* @param id the grade value resource id * @param id the grade value resource id
* @param grade the grade in fraction between 0 and 1 * @param grade the grade in fraction between 0 and 1
*/ */
public static void setGradeValue(Activity activity, int id, double grade) { private static void setGradeValue(Activity activity, int id, double grade) {
TextView textView = (TextView) activity.findViewById(id); TextView textView = (TextView) activity.findViewById(id);
String value; String value;
if (Double.isNaN(grade) || Double.isInfinite(grade)) { if (Double.isNaN(grade) || Double.isInfinite(grade)) {
@@ -156,4 +276,23 @@ public class StatsUtils {
} }
textView.setText(value); textView.setText(value);
} }
/**
* Sets a coordinate value.
*
* @param activity the activity
* @param id the coordinate value resource id
* @param coordinate the coordinate in degrees
*/
private static void setCoordinateValue(Activity activity, int id, double coordinate) {
TextView textView = (TextView) activity.findViewById(id);
String value;
if (Double.isNaN(coordinate) || Double.isInfinite(coordinate)) {
value = activity.getString(R.string.value_unknown);
} else {
value = activity.getString(
R.string.value_coordinate_degree, Location.convert(coordinate, Location.FORMAT_DEGREES));
}
textView.setText(value);
}
} }
@@ -33,7 +33,7 @@ public class ChartValueSeriesTest extends AndroidTestCase {
R.color.elevation_fill, R.color.elevation_fill,
R.color.elevation_border, R.color.elevation_border,
new ZoomSettings(5, new int[] {100}), new ZoomSettings(5, new int[] {100}),
R.string.stat_elevation); R.string.stats_elevation);
} }
public void testInitialConditions() { public void testInitialConditions() {
@@ -43,7 +43,7 @@ public class ChartValueSeriesTest extends AndroidTestCase {
assertEquals(0, series.getMax()); assertEquals(0, series.getMax());
assertEquals(0.0, series.getSpread()); assertEquals(0.0, series.getSpread());
assertEquals(Style.STROKE, series.getPaint().getStyle()); assertEquals(Style.STROKE, series.getPaint().getStyle());
assertEquals(getContext().getString(R.string.stat_elevation), assertEquals(getContext().getString(R.string.stats_elevation),
series.getTitle()); series.getTitle());
assertTrue(series.isEnabled()); assertTrue(series.isEnabled());
} }