forked from upstream-mirrors/OpenTracks
merge heads
This commit is contained in:
@@ -15,7 +15,7 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
-->
|
-->
|
||||||
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
|
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:duration="2000"
|
android:duration="1000"
|
||||||
android:fromAlpha="1.0"
|
android:fromAlpha="1.0"
|
||||||
android:interpolator="@android:anim/linear_interpolator"
|
android:interpolator="@android:anim/linear_interpolator"
|
||||||
android:toAlpha="0.0" />
|
android:toAlpha="0.0" />
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 3.3 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 3.1 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 3.6 KiB |
@@ -0,0 +1,144 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
Copyright 2013 Google Inc.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
-->
|
||||||
|
<merge xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||||
|
<!-- Distance, calorie, total time, and moving time -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_width="match_parent" >
|
||||||
|
<include
|
||||||
|
android:id="@+id/stats_distance"
|
||||||
|
layout="@layout/stats_large_item" />
|
||||||
|
<include
|
||||||
|
android:id="@+id/stats_calorie"
|
||||||
|
layout="@layout/stats_calorie" />
|
||||||
|
<View
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_width="1dp"
|
||||||
|
android:visibility="invisible" />
|
||||||
|
<include
|
||||||
|
android:id="@+id/stats_total_time"
|
||||||
|
layout="@layout/stats_large_item" />
|
||||||
|
<include
|
||||||
|
android:id="@+id/stats_moving_time"
|
||||||
|
layout="@layout/stats_large_item" />
|
||||||
|
</LinearLayout>
|
||||||
|
<!-- Horizontal line -->
|
||||||
|
<View style="@style/StatsHorizontalLine" />
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_width="match_parent" >
|
||||||
|
<TableLayout
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:layout_width="0dp" >
|
||||||
|
<!-- Speed and average speed -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_width="match_parent" >
|
||||||
|
<include
|
||||||
|
android:id="@+id/stats_speed"
|
||||||
|
layout="@layout/stats_small_item" />
|
||||||
|
<include
|
||||||
|
android:id="@+id/stats_average_speed"
|
||||||
|
layout="@layout/stats_small_item" />
|
||||||
|
</LinearLayout>
|
||||||
|
<!-- Max speed and average moving speed -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_width="match_parent" >
|
||||||
|
<include
|
||||||
|
android:id="@+id/stats_max_speed"
|
||||||
|
layout="@layout/stats_small_item" />
|
||||||
|
<include
|
||||||
|
android:id="@+id/stats_average_moving_speed"
|
||||||
|
layout="@layout/stats_small_item" />
|
||||||
|
</LinearLayout>
|
||||||
|
<!-- Latitude and longitude -->
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/stats_coordinate_container"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_width="match_parent" >
|
||||||
|
<include
|
||||||
|
android:id="@+id/stats_latitude"
|
||||||
|
layout="@layout/stats_small_item" />
|
||||||
|
<include
|
||||||
|
android:id="@+id/stats_longitude"
|
||||||
|
layout="@layout/stats_small_item" />
|
||||||
|
</LinearLayout>
|
||||||
|
</TableLayout>
|
||||||
|
<!-- Vertical line -->
|
||||||
|
<View
|
||||||
|
android:background="@color/stats_separator"
|
||||||
|
android:id="@+id/stats_grade_elevation_separator"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_width="1dp" />
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/stats_grade_elevation_container"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:layout_width="0dp" >
|
||||||
|
<!-- Grade -->
|
||||||
|
<LinearLayout style="@style/StatsSmallGroupContainer" >
|
||||||
|
<!-- Grade label -->
|
||||||
|
<TextView
|
||||||
|
android:text="@string/stats_grade"
|
||||||
|
style="@style/StatsSmallLabel" />
|
||||||
|
<TableLayout
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_width="wrap_content" >
|
||||||
|
<!-- Grade min -->
|
||||||
|
<include
|
||||||
|
android:id="@+id/stats_grade_min"
|
||||||
|
layout="@layout/stats_small_group_item" />
|
||||||
|
<!-- Grade max -->
|
||||||
|
<include
|
||||||
|
android:id="@+id/stats_grade_max"
|
||||||
|
layout="@layout/stats_small_group_item" />
|
||||||
|
</TableLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
<!-- Elevation -->
|
||||||
|
<LinearLayout style="@style/StatsSmallGroupContainer" >
|
||||||
|
<!-- Elevation label -->
|
||||||
|
<TextView
|
||||||
|
android:text="@string/stats_elevation"
|
||||||
|
style="@style/StatsSmallLabel" />
|
||||||
|
<TableLayout
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_width="wrap_content" >
|
||||||
|
<!-- Elevation -->
|
||||||
|
<include
|
||||||
|
android:id="@+id/stats_elevation"
|
||||||
|
layout="@layout/stats_small_group_item" />
|
||||||
|
<!-- Elevation gain -->
|
||||||
|
<include
|
||||||
|
android:id="@+id/stats_elevation_gain"
|
||||||
|
layout="@layout/stats_small_group_item" />
|
||||||
|
<!-- Elevation min -->
|
||||||
|
<include
|
||||||
|
android:id="@+id/stats_elevation_min"
|
||||||
|
layout="@layout/stats_small_group_item" />
|
||||||
|
<!-- Elevation max -->
|
||||||
|
<include
|
||||||
|
android:id="@+id/stats_elevation_max"
|
||||||
|
layout="@layout/stats_small_group_item" />
|
||||||
|
</TableLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
</merge>
|
||||||
@@ -17,8 +17,7 @@ limitations under the License.
|
|||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:baselineAligned="false"
|
android:baselineAligned="false"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent" >
|
||||||
android:orientation="horizontal" >
|
|
||||||
<include layout="@layout/track_controller" />
|
<include layout="@layout/track_controller" />
|
||||||
<TabHost
|
<TabHost
|
||||||
android:id="@android:id/tabhost"
|
android:id="@android:id/tabhost"
|
||||||
|
|||||||
@@ -16,8 +16,7 @@ limitations under the License.
|
|||||||
-->
|
-->
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent" >
|
||||||
android:orientation="horizontal" >
|
|
||||||
<include layout="@layout/track_controller" />
|
<include layout="@layout/track_controller" />
|
||||||
<ListView
|
<ListView
|
||||||
android:id="@+id/track_list"
|
android:id="@+id/track_list"
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ limitations under the License.
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:minHeight="?android:attr/listPreferredItemHeight"
|
android:minHeight="?android:attr/listPreferredItemHeight"
|
||||||
android:orientation="horizontal"
|
|
||||||
android:paddingLeft="16dp"
|
android:paddingLeft="16dp"
|
||||||
android:paddingRight="16dp" >
|
android:paddingRight="16dp" >
|
||||||
<ImageView
|
<ImageView
|
||||||
|
|||||||
@@ -14,10 +14,54 @@ 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.
|
||||||
-->
|
-->
|
||||||
<GridView xmlns:android="http://schemas.android.com/apk/res/android"
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:numColumns="4"
|
android:orientation="vertical" >
|
||||||
android:padding="4dp"
|
<GridView
|
||||||
android:stretchMode="spacingWidth"
|
android:id="@+id/choose_activity_type_grid_view"
|
||||||
android:verticalSpacing="4dp" />
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:numColumns="4"
|
||||||
|
android:padding="4dp"
|
||||||
|
android:stretchMode="spacingWidth"
|
||||||
|
android:verticalSpacing="4dp" />
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/choose_activity_type_weight_container"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:orientation="vertical" >
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/choose_activity_type_weight_label"
|
||||||
|
android:layout_marginBottom="2dp"
|
||||||
|
android:layout_marginLeft="16dp"
|
||||||
|
android:layout_marginRight="16dp"
|
||||||
|
android:layout_marginTop="4dp"
|
||||||
|
android:paddingLeft="12dp"
|
||||||
|
style="@style/TextMedium" />
|
||||||
|
<FrameLayout
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_width="fill_parent" >
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/choose_activity_type_weight"
|
||||||
|
android:inputType="numberDecimal"
|
||||||
|
android:layout_marginBottom="4dp"
|
||||||
|
android:layout_marginLeft="16dp"
|
||||||
|
android:layout_marginRight="16dp"
|
||||||
|
android:layout_marginTop="2dp"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:selectAllOnFocus="true"
|
||||||
|
android:singleLine="true"
|
||||||
|
style="@style/TextMedium" />
|
||||||
|
<ImageButton
|
||||||
|
android:background="@android:color/transparent"
|
||||||
|
android:id="@+id/choose_activity_type_weight_image_button"
|
||||||
|
android:layout_gravity="right|center_vertical"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginRight="16dp"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:paddingRight="12dp"
|
||||||
|
android:src="@android:drawable/ic_menu_close_clear_cancel" />
|
||||||
|
</FrameLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
||||||
@@ -24,103 +24,107 @@ limitations under the License.
|
|||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:scaleType="centerCrop" />
|
android:scaleType="centerCrop" />
|
||||||
<!-- A gradient on top of the text -->
|
<FrameLayout
|
||||||
<ImageView
|
android:layout_height="wrap_content"
|
||||||
android:alpha=".6"
|
android:layout_width="match_parent" >
|
||||||
android:contentDescription="@string/icon_marker"
|
<!-- A gradient on top of the text -->
|
||||||
android:id="@+id/list_item_text_gradient"
|
<ImageView
|
||||||
android:layout_height="match_parent"
|
android:alpha=".6"
|
||||||
android:layout_width="match_parent"
|
android:contentDescription="@string/icon_marker"
|
||||||
android:src="@drawable/text_gradient" />
|
android:id="@+id/list_item_text_gradient"
|
||||||
<!-- Table 1 -->
|
android:layout_height="match_parent"
|
||||||
<TableLayout
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:src="@drawable/text_gradient" />
|
||||||
android:layout_width="match_parent"
|
<!-- Table 1 -->
|
||||||
android:minHeight="?android:attr/listPreferredItemHeight"
|
<TableLayout
|
||||||
android:paddingBottom="12dp"
|
android:layout_height="wrap_content"
|
||||||
android:paddingRight="12dp"
|
android:layout_width="match_parent"
|
||||||
android:paddingTop="8dp"
|
android:minHeight="?android:attr/listPreferredItemHeight"
|
||||||
android:shrinkColumns="1"
|
android:paddingBottom="12dp"
|
||||||
android:stretchColumns="1"
|
android:paddingRight="12dp"
|
||||||
style="@style/ListItem" >
|
android:paddingTop="8dp"
|
||||||
<!-- Table 1: Row 1 -->
|
android:shrinkColumns="1"
|
||||||
<TableRow>
|
android:stretchColumns="1"
|
||||||
<!-- Table 1: Row 1: Column 1: (icon) -->
|
style="@style/ListItem" >
|
||||||
<ImageView
|
<!-- Table 1: Row 1 -->
|
||||||
android:contentDescription="@string/icon_track"
|
<TableRow>
|
||||||
android:id="@+id/list_item_icon"
|
<!-- Table 1: Row 1: Column 1: (icon) -->
|
||||||
android:layout_gravity="center_vertical"
|
<ImageView
|
||||||
android:layout_height="wrap_content"
|
android:contentDescription="@string/icon_track"
|
||||||
android:layout_marginLeft="8dp"
|
android:id="@+id/list_item_icon"
|
||||||
android:layout_marginRight="8dp"
|
android:layout_gravity="center_vertical"
|
||||||
android:layout_width="wrap_content" />
|
android:layout_height="wrap_content"
|
||||||
<!-- Table 1: Row 1: Column 2: (Table 2) -->
|
android:layout_marginLeft="8dp"
|
||||||
<TableLayout
|
android:layout_marginRight="8dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_width="wrap_content" />
|
||||||
android:layout_width="match_parent"
|
<!-- Table 1: Row 1: Column 2: (Table 2) -->
|
||||||
android:shrinkColumns="0"
|
<TableLayout
|
||||||
android:stretchColumns="0" >
|
android:layout_height="wrap_content"
|
||||||
<TableRow>
|
android:layout_width="match_parent"
|
||||||
<!-- Table 2: Row 1: Column 1: (name) -->
|
android:shrinkColumns="0"
|
||||||
<TextView
|
android:stretchColumns="0" >
|
||||||
android:ellipsize="end"
|
<TableRow>
|
||||||
android:id="@+id/list_item_name"
|
<!-- Table 2: Row 1: Column 1: (name) -->
|
||||||
android:layout_gravity="bottom"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:singleLine="true"
|
|
||||||
style="@style/TextMedium" />
|
|
||||||
<!-- Table 2: Row 1: Column 2: (date) -->
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/list_item_date"
|
|
||||||
style="@style/ListItemDate" />
|
|
||||||
</TableRow>
|
|
||||||
<TableRow>
|
|
||||||
<!-- Need to match the style set in ListItemUtils.setListItem -->
|
|
||||||
<!-- Table 2: Row 2: Column 1: (shared owner, total time, total distance, and marker count) -->
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_gravity="bottom"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_width="match_parent" >
|
|
||||||
<TextView
|
<TextView
|
||||||
android:ellipsize="end"
|
android:ellipsize="end"
|
||||||
android:id="@+id/list_item_owner_time_distance"
|
android:id="@+id/list_item_name"
|
||||||
android:layout_gravity="bottom"
|
android:layout_gravity="bottom"
|
||||||
|
android:layout_width="match_parent"
|
||||||
android:singleLine="true"
|
android:singleLine="true"
|
||||||
style="@style/TextSmall" />
|
style="@style/TextMedium" />
|
||||||
<ImageView
|
<!-- Table 2: Row 1: Column 2: (date) -->
|
||||||
android:contentDescription="@string/icon_marker"
|
<TextView
|
||||||
android:id="@+id/list_item_marker_count_icon"
|
android:id="@+id/list_item_date"
|
||||||
|
style="@style/ListItemDate" />
|
||||||
|
</TableRow>
|
||||||
|
<TableRow>
|
||||||
|
<!-- Need to match the style set in ListItemUtils.setListItem -->
|
||||||
|
<!-- Table 2: Row 2: Column 1: (shared owner, total time, total distance, and marker count) -->
|
||||||
|
<LinearLayout
|
||||||
android:layout_gravity="bottom"
|
android:layout_gravity="bottom"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginLeft="2dp"
|
android:layout_width="match_parent" >
|
||||||
android:layout_marginRight="2dp"
|
<TextView
|
||||||
android:layout_marginBottom="1dp"
|
android:ellipsize="end"
|
||||||
android:layout_width="wrap_content"
|
android:id="@+id/list_item_owner_time_distance"
|
||||||
android:scaleType="centerInside"
|
android:layout_gravity="bottom"
|
||||||
android:src="@drawable/ic_menu_insert_marker" />
|
android:singleLine="true"
|
||||||
|
style="@style/TextSmall" />
|
||||||
|
<ImageView
|
||||||
|
android:contentDescription="@string/icon_marker"
|
||||||
|
android:id="@+id/list_item_marker_count_icon"
|
||||||
|
android:layout_gravity="bottom"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="1dp"
|
||||||
|
android:layout_marginLeft="2dp"
|
||||||
|
android:layout_marginRight="2dp"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:scaleType="centerInside"
|
||||||
|
android:src="@drawable/ic_menu_insert_marker" />
|
||||||
|
<TextView
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:id="@+id/list_item_marker_count"
|
||||||
|
android:layout_gravity="bottom"
|
||||||
|
android:singleLine="true"
|
||||||
|
style="@style/TextSmall" />
|
||||||
|
</LinearLayout>
|
||||||
|
<!-- Table 2: Row 2: Column 2: (time) -->
|
||||||
<TextView
|
<TextView
|
||||||
android:ellipsize="end"
|
android:id="@+id/list_item_time"
|
||||||
android:id="@+id/list_item_marker_count"
|
style="@style/ListItemDate" />
|
||||||
android:layout_gravity="bottom"
|
</TableRow>
|
||||||
android:singleLine="true"
|
</TableLayout>
|
||||||
style="@style/TextSmall" />
|
</TableRow>
|
||||||
</LinearLayout>
|
<TableRow>
|
||||||
<!-- Table 2: Row 2: Column 2: (time) -->
|
<!-- Table 1: Row 2: (category and description) -->
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/list_item_time"
|
android:ellipsize="end"
|
||||||
style="@style/ListItemDate" />
|
android:id="@+id/list_item_category_description"
|
||||||
</TableRow>
|
android:layout_column="1"
|
||||||
</TableLayout>
|
android:maxLines="2"
|
||||||
</TableRow>
|
android:singleLine="false"
|
||||||
<TableRow>
|
style="@style/TextSmall" />
|
||||||
<!-- Table 1: Row 2: (category and description) -->
|
</TableRow>
|
||||||
<TextView
|
</TableLayout>
|
||||||
android:ellipsize="end"
|
</FrameLayout>
|
||||||
android:id="@+id/list_item_category_description"
|
|
||||||
android:layout_column="1"
|
|
||||||
android:maxLines="2"
|
|
||||||
android:singleLine="false"
|
|
||||||
style="@style/TextSmall" />
|
|
||||||
</TableRow>
|
|
||||||
</TableLayout>
|
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
@@ -19,9 +19,7 @@ limitations under the License.
|
|||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical">
|
||||||
android:paddingLeft="8dp"
|
|
||||||
android:paddingRight="8dp" >
|
|
||||||
<include layout="@layout/stats_content" />
|
<include layout="@layout/stats_content" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
+22
-11
@@ -15,17 +15,28 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
-->
|
-->
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:id="@+id/stats_small_1line_id"
|
style="@style/StatsLargeItemContainer" >
|
||||||
style="@style/StatsSmallValueContainer" >
|
<!-- Label -->
|
||||||
<TextView
|
|
||||||
android:id="@+id/stats_value"
|
|
||||||
style="@style/StatsSmallValue" />
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/stats_unit"
|
|
||||||
style="@style/StatsUnit" />
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/stats_label"
|
android:id="@+id/stats_label"
|
||||||
android:layout_gravity="bottom"
|
style="@style/StatsLargeLabel" />
|
||||||
android:paddingLeft="8dp"
|
<!-- Value container -->
|
||||||
style="@style/StatsSmallLabel" />
|
<LinearLayout style="@style/StatsLargeValueContainer" >
|
||||||
|
<!-- Value -->
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/stats_value"
|
||||||
|
style="@style/StatsLargeValue" />
|
||||||
|
<!-- Unit -->
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/stats_unit"
|
||||||
|
style="@style/StatsUnit" />
|
||||||
|
<!-- Activity type -->
|
||||||
|
<Spinner
|
||||||
|
android:id="@+id/stats_activity_type_icon"
|
||||||
|
android:layout_gravity="bottom"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginLeft="4dp"
|
||||||
|
android:layout_marginTop="-6dp"
|
||||||
|
android:layout_width="wrap_content" />
|
||||||
|
</LinearLayout>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
@@ -15,108 +15,114 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
-->
|
-->
|
||||||
<merge xmlns:android="http://schemas.android.com/apk/res/android" >
|
<merge xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||||
<!-- Row 1: distance and speed -->
|
<!-- Distance and calorie -->
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_width="match_parent" >
|
android:layout_width="match_parent" >
|
||||||
<include
|
<include
|
||||||
android:id="@+id/stats_distance"
|
android:id="@+id/stats_distance"
|
||||||
layout="@layout/stats_large_item" />
|
layout="@layout/stats_large_item" />
|
||||||
<View style="@style/StatsVerticalSpacer" />
|
|
||||||
<include
|
<include
|
||||||
android:id="@+id/stats_speed"
|
android:id="@+id/stats_calorie"
|
||||||
layout="@layout/stats_large_item" />
|
layout="@layout/stats_calorie" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
<!-- Row 2: total time and average speed -->
|
<!-- Total time and moving time -->
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_width="match_parent" >
|
android:layout_width="match_parent" >
|
||||||
<include
|
<include
|
||||||
android:id="@+id/stats_total_time"
|
android:id="@+id/stats_total_time"
|
||||||
layout="@layout/stats_large_item" />
|
layout="@layout/stats_large_item" />
|
||||||
<View style="@style/StatsVerticalSpacer" />
|
|
||||||
<include
|
|
||||||
android:id="@+id/stats_average_speed"
|
|
||||||
layout="@layout/stats_large_item" />
|
|
||||||
</LinearLayout>
|
|
||||||
<!-- Row 3: horizontal line -->
|
|
||||||
<View style="@style/StatsHorizontalLine" />
|
|
||||||
<!-- Row 3: moving time and average moving speed -->
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_width="match_parent" >
|
|
||||||
<include
|
<include
|
||||||
android:id="@+id/stats_moving_time"
|
android:id="@+id/stats_moving_time"
|
||||||
layout="@layout/stats_small_item" />
|
layout="@layout/stats_large_item" />
|
||||||
<View style="@style/StatsVerticalSpacer" />
|
|
||||||
<include
|
|
||||||
android:id="@+id/stats_average_moving_time"
|
|
||||||
layout="@layout/stats_small_item" />
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
<!-- Row 4: empty and max speed -->
|
<!-- Horizontal line -->
|
||||||
|
<View style="@style/StatsHorizontalLine" />
|
||||||
|
<!-- Speed and average speed -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_width="match_parent" >
|
||||||
|
<include
|
||||||
|
android:id="@+id/stats_speed"
|
||||||
|
layout="@layout/stats_small_item" />
|
||||||
|
<include
|
||||||
|
android:id="@+id/stats_average_speed"
|
||||||
|
layout="@layout/stats_small_item" />
|
||||||
|
</LinearLayout>
|
||||||
|
<!-- Max speed and average moving speed -->
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_width="match_parent" >
|
android:layout_width="match_parent" >
|
||||||
<LinearLayout style="@style/StatsSmallItemContainer" />
|
|
||||||
<View style="@style/StatsVerticalSpacer" />
|
|
||||||
<include
|
<include
|
||||||
android:id="@+id/stats_max_speed"
|
android:id="@+id/stats_max_speed"
|
||||||
layout="@layout/stats_small_item" />
|
layout="@layout/stats_small_item" />
|
||||||
|
<include
|
||||||
|
android:id="@+id/stats_average_moving_speed"
|
||||||
|
layout="@layout/stats_small_item" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
<!-- Row 5: horizontal line -->
|
<!-- Horizontal line -->
|
||||||
<View
|
<View
|
||||||
android:id="@+id/stats_grade_elevation_horizontal_line"
|
android:id="@+id/stats_grade_elevation_separator"
|
||||||
style="@style/StatsHorizontalLine" />
|
style="@style/StatsHorizontalLine" />
|
||||||
<!-- Row 5: grade and elevation -->
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/stats_grade_elevation_container"
|
android:id="@+id/stats_grade_elevation_container"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_width="match_parent" >
|
android:layout_width="match_parent" >
|
||||||
<!-- Grade -->
|
<!-- Grade -->
|
||||||
<LinearLayout style="@style/StatsSmallItemContainer" >
|
<LinearLayout style="@style/StatsSmallGroupContainer" >
|
||||||
<!-- Grade label -->
|
<!-- Grade label -->
|
||||||
<TextView
|
<TextView
|
||||||
android:text="@string/stats_grade"
|
android:text="@string/stats_grade"
|
||||||
style="@style/StatsSmallLabel" />
|
style="@style/StatsSmallLabel" />
|
||||||
<!-- Grade min -->
|
<TableLayout
|
||||||
<include
|
android:layout_gravity="center"
|
||||||
android:id="@+id/stats_grade_min"
|
android:layout_height="wrap_content"
|
||||||
layout="@layout/stats_small_item_1line" />
|
android:layout_width="wrap_content" >
|
||||||
<!-- Grade max -->
|
<!-- Grade min -->
|
||||||
<include
|
<include
|
||||||
android:id="@+id/stats_grade_max"
|
android:id="@+id/stats_grade_min"
|
||||||
layout="@layout/stats_small_item_1line" />
|
layout="@layout/stats_small_group_item" />
|
||||||
|
<!-- Grade max -->
|
||||||
|
<include
|
||||||
|
android:id="@+id/stats_grade_max"
|
||||||
|
layout="@layout/stats_small_group_item" />
|
||||||
|
</TableLayout>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
<View style="@style/StatsVerticalSpacer" />
|
|
||||||
<!-- Elevation -->
|
<!-- Elevation -->
|
||||||
<LinearLayout style="@style/StatsSmallItemContainer" >
|
<LinearLayout style="@style/StatsSmallGroupContainer" >
|
||||||
<!-- Elevation label -->
|
<!-- Elevation label -->
|
||||||
<TextView
|
<TextView
|
||||||
android:text="@string/stats_elevation"
|
android:text="@string/stats_elevation"
|
||||||
style="@style/StatsSmallLabel" />
|
style="@style/StatsSmallLabel" />
|
||||||
<!-- Elevation -->
|
<TableLayout
|
||||||
<include
|
android:layout_gravity="center"
|
||||||
android:id="@+id/stats_elevation"
|
android:layout_height="wrap_content"
|
||||||
layout="@layout/stats_small_item_1line" />
|
android:layout_width="wrap_content" >
|
||||||
<!-- Elevation gain -->
|
<!-- Elevation -->
|
||||||
<include
|
<include
|
||||||
android:id="@+id/stats_elevation_gain"
|
android:id="@+id/stats_elevation"
|
||||||
layout="@layout/stats_small_item_1line" />
|
layout="@layout/stats_small_group_item" />
|
||||||
<!-- Elevation min -->
|
<!-- Elevation gain -->
|
||||||
<include
|
<include
|
||||||
android:id="@+id/stats_elevation_min"
|
android:id="@+id/stats_elevation_gain"
|
||||||
layout="@layout/stats_small_item_1line" />
|
layout="@layout/stats_small_group_item" />
|
||||||
<!-- Elevation max -->
|
<!-- Elevation min -->
|
||||||
<include
|
<include
|
||||||
android:id="@+id/stats_elevation_max"
|
android:id="@+id/stats_elevation_min"
|
||||||
layout="@layout/stats_small_item_1line" />
|
layout="@layout/stats_small_group_item" />
|
||||||
|
<!-- Elevation max -->
|
||||||
|
<include
|
||||||
|
android:id="@+id/stats_elevation_max"
|
||||||
|
layout="@layout/stats_small_group_item" />
|
||||||
|
</TableLayout>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
<!-- Row 6: horizontal line -->
|
<!-- Horizontal line -->
|
||||||
<View
|
<View
|
||||||
android:id="@+id/stats_coordinate_horizontal_line"
|
android:id="@+id/stats_coordinate_separator"
|
||||||
style="@style/StatsHorizontalLine" />
|
style="@style/StatsHorizontalLine" />
|
||||||
<!-- Row 6: latitude and longitude -->
|
<!-- Latitude and longitude -->
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/stats_coordinate_container"
|
android:id="@+id/stats_coordinate_container"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
@@ -124,30 +130,8 @@ limitations under the License.
|
|||||||
<include
|
<include
|
||||||
android:id="@+id/stats_latitude"
|
android:id="@+id/stats_latitude"
|
||||||
layout="@layout/stats_small_item" />
|
layout="@layout/stats_small_item" />
|
||||||
<View style="@style/StatsVerticalSpacer" />
|
|
||||||
<include
|
<include
|
||||||
android:id="@+id/stats_longitude"
|
android:id="@+id/stats_longitude"
|
||||||
layout="@layout/stats_small_item" />
|
layout="@layout/stats_small_item" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
<!-- Row 7: calorie horizontal line -->
|
|
||||||
<View
|
|
||||||
android:id="@+id/stats_calorie_horizontal_line"
|
|
||||||
style="@style/StatsHorizontalLine" />
|
|
||||||
<!-- Row 7: calorie -->
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/stats_calorie_container"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_width="match_parent" >
|
|
||||||
<!-- calorie value -->
|
|
||||||
<include
|
|
||||||
android:id="@+id/stats_calorie"
|
|
||||||
layout="@layout/stats_small_item" />
|
|
||||||
<!-- Setup activity type-->
|
|
||||||
<Button
|
|
||||||
android:id="@+id/stats_calorie_setup"
|
|
||||||
android:layout_gravity="right"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:text="@string/stats_calorie_setup" />
|
|
||||||
</LinearLayout>
|
|
||||||
</merge>
|
</merge>
|
||||||
@@ -15,17 +15,18 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
-->
|
-->
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:id="@+id/stats_large_item_id"
|
|
||||||
style="@style/StatsLargeItemContainer" >
|
style="@style/StatsLargeItemContainer" >
|
||||||
<!-- Distance label -->
|
<!-- Label -->
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/stats_label"
|
android:id="@+id/stats_label"
|
||||||
style="@style/StatsLargeLabel" />
|
style="@style/StatsLargeLabel" />
|
||||||
<!-- Distance value -->
|
<!-- Value container -->
|
||||||
<LinearLayout style="@style/StatsLargeValueContainer" >
|
<LinearLayout style="@style/StatsLargeValueContainer" >
|
||||||
|
<!-- Value -->
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/stats_value"
|
android:id="@+id/stats_value"
|
||||||
style="@style/StatsLargeValue" />
|
style="@style/StatsLargeValue" />
|
||||||
|
<!-- Unit -->
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/stats_unit"
|
android:id="@+id/stats_unit"
|
||||||
style="@style/StatsUnit" />
|
style="@style/StatsUnit" />
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
Copyright 2013 Google Inc.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
-->
|
||||||
|
<TableRow xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_width="wrap_content" >
|
||||||
|
<!-- Value container -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_gravity="right|bottom"
|
||||||
|
style="@style/StatsSmallValueContainer" >
|
||||||
|
<!-- Value -->
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/stats_value"
|
||||||
|
style="@style/StatsSmallValue" />
|
||||||
|
<!-- Unit -->
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/stats_unit"
|
||||||
|
style="@style/StatsUnit" />
|
||||||
|
</LinearLayout>
|
||||||
|
<!-- Label container -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_gravity="left|bottom"
|
||||||
|
style="@style/StatsSmallValueContainer" >
|
||||||
|
<TextView
|
||||||
|
android:visibility="invisible"
|
||||||
|
style="@style/StatsSmallValue" />
|
||||||
|
<!-- Label -->
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/stats_label"
|
||||||
|
android:layout_gravity="bottom"
|
||||||
|
android:paddingLeft="8dp"
|
||||||
|
style="@style/StatsSmallLabel" />
|
||||||
|
</LinearLayout>
|
||||||
|
</TableRow>
|
||||||
@@ -15,16 +15,18 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
-->
|
-->
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:id="@+id/stats_small_item_id"
|
|
||||||
style="@style/StatsSmallItemContainer" >
|
style="@style/StatsSmallItemContainer" >
|
||||||
|
<!-- Label -->
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/stats_label"
|
android:id="@+id/stats_label"
|
||||||
style="@style/StatsSmallLabel" />
|
style="@style/StatsSmallLabel" />
|
||||||
<!-- Distance value -->
|
<!-- Value container -->
|
||||||
<LinearLayout style="@style/StatsSmallValueContainer" >
|
<LinearLayout style="@style/StatsSmallValueContainer" >
|
||||||
|
<!-- Value -->
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/stats_value"
|
android:id="@+id/stats_value"
|
||||||
style="@style/StatsSmallValue" />
|
style="@style/StatsSmallValue" />
|
||||||
|
<!-- Unit -->
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/stats_unit"
|
android:id="@+id/stats_unit"
|
||||||
style="@style/StatsUnit" />
|
style="@style/StatsUnit" />
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ limitations under the License.
|
|||||||
android:id="@+id/track_controler_container"
|
android:id="@+id/track_controler_container"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:orientation="horizontal"
|
|
||||||
android:paddingBottom="8dp"
|
android:paddingBottom="8dp"
|
||||||
android:paddingTop="8dp" >
|
android:paddingTop="8dp" >
|
||||||
<View
|
<View
|
||||||
|
|||||||
@@ -23,8 +23,7 @@ limitations under the License.
|
|||||||
android:id="@android:id/tabs"
|
android:id="@android:id/tabs"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="0"
|
android:layout_weight="0"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent" />
|
||||||
android:orientation="horizontal" />
|
|
||||||
<FrameLayout
|
<FrameLayout
|
||||||
android:id="@android:id/tabcontent"
|
android:id="@android:id/tabcontent"
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
|
|||||||
@@ -38,8 +38,7 @@ limitations under the License.
|
|||||||
style="@style/EditLabel.WithPaddingTop" />
|
style="@style/EditLabel.WithPaddingTop" />
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent" >
|
||||||
android:orientation="horizontal" >
|
|
||||||
<AutoCompleteTextView
|
<AutoCompleteTextView
|
||||||
android:gravity="bottom"
|
android:gravity="bottom"
|
||||||
android:hint="@string/track_edit_activity_type_hint"
|
android:hint="@string/track_edit_activity_type_hint"
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ limitations under the License.
|
|||||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
style="@style/TrackWidgetBoundingBox" >
|
style="@style/TrackWidgetBoundingBox" >
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:orientation="horizontal"
|
|
||||||
android:paddingBottom="4dp"
|
android:paddingBottom="4dp"
|
||||||
android:paddingTop="4dp"
|
android:paddingTop="4dp"
|
||||||
style="@style/TrackWidgetFrame" >
|
style="@style/TrackWidgetFrame" >
|
||||||
|
|||||||
@@ -34,7 +34,6 @@ limitations under the License.
|
|||||||
<item name="android:layout_height">wrap_content</item>
|
<item name="android:layout_height">wrap_content</item>
|
||||||
<item name="android:layout_width">match_parent</item>
|
<item name="android:layout_width">match_parent</item>
|
||||||
<item name="android:measureWithLargestChild">true</item>
|
<item name="android:measureWithLargestChild">true</item>
|
||||||
<item name="android:orientation">horizontal</item>
|
|
||||||
</style>
|
</style>
|
||||||
<style name="BottomButtonDivider">
|
<style name="BottomButtonDivider">
|
||||||
<item name="android:background">?android:attr/dividerVertical</item>
|
<item name="android:background">?android:attr/dividerVertical</item>
|
||||||
|
|||||||
@@ -18,22 +18,22 @@ limitations under the License.
|
|||||||
<!-- The style for choose activity text -->
|
<!-- The style for choose activity text -->
|
||||||
<style name="StatsSmallLabel" parent="@style/TextSmall">
|
<style name="StatsSmallLabel" parent="@style/TextSmall">
|
||||||
<!-- same as StatsSmallLabel in values/styles.xml except adding textAllCaps -->
|
<!-- same as StatsSmallLabel in values/styles.xml except adding textAllCaps -->
|
||||||
<item name="android:gravity">right</item>
|
<item name="android:gravity">center</item>
|
||||||
<item name="android:layout_gravity">right</item>
|
<item name="android:layout_gravity">center</item>
|
||||||
<item name="android:singleLine">false</item>
|
<item name="android:singleLine">false</item>
|
||||||
<item name="android:textAllCaps">true</item>
|
<item name="android:textAllCaps">true</item>
|
||||||
<item name="android:textStyle">bold</item>
|
<item name="android:textStyle">bold</item>
|
||||||
</style>
|
</style>
|
||||||
<style name="StatsLargeLabel" parent="@style/TextSmall">
|
<style name="StatsLargeLabel" parent="@style/TextSmall">
|
||||||
<!-- same as StatsLargeLabel in values/styles.xml except adding textAllCaps -->
|
<!-- same as StatsLargeLabel in values/styles.xml except adding textAllCaps -->
|
||||||
<item name="android:gravity">right</item>
|
<item name="android:gravity">center</item>
|
||||||
<item name="android:layout_gravity">right</item>
|
<item name="android:layout_gravity">center</item>
|
||||||
<item name="android:singleLine">false</item>
|
<item name="android:singleLine">false</item>
|
||||||
<item name="android:textAllCaps">true</item>
|
<item name="android:textAllCaps">true</item>
|
||||||
<item name="android:textColor">@color/stats_large_label</item>
|
<item name="android:textColor">@color/stats_large_label</item>
|
||||||
<item name="android:textStyle">bold</item>
|
<item name="android:textStyle">bold</item>
|
||||||
</style>
|
</style>
|
||||||
<style name="TextChooseActivity">
|
<style name="TextChooseActivity">
|
||||||
<!-- Same as TextChooseActivity in values/styles.xml except removing textSize and using textAppearance -->
|
<!-- Same as TextChooseActivity in values/styles.xml except removing textSize and using textAppearance -->
|
||||||
<item name="android:textAppearance">?android:attr/textAppearanceListItemSmall</item>
|
<item name="android:textAppearance">?android:attr/textAppearanceListItemSmall</item>
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -42,8 +42,6 @@ limitations under the License.
|
|||||||
<string name="stats_rate_key">statsRate</string>
|
<string name="stats_rate_key">statsRate</string>
|
||||||
<string name="stats_show_coordinate_key">statsShowCoordinate</string>
|
<string name="stats_show_coordinate_key">statsShowCoordinate</string>
|
||||||
<string name="stats_show_grade_elevation_key">statsShowGradeElevation</string>
|
<string name="stats_show_grade_elevation_key">statsShowGradeElevation</string>
|
||||||
<string name="stats_show_calorie_key">statsShowCalorie</string>
|
|
||||||
<string name="stats_weight_key">statsWeight</string>
|
|
||||||
<string name="stats_units_key">statsUnits</string>
|
<string name="stats_units_key">statsUnits</string>
|
||||||
<string name="track_color_mode_medium_key">trackColorModeMedium</string>
|
<string name="track_color_mode_medium_key">trackColorModeMedium</string>
|
||||||
<string name="track_color_mode_percentage_key">trackColorModePercentage</string>
|
<string name="track_color_mode_percentage_key">trackColorModePercentage</string>
|
||||||
@@ -70,6 +68,7 @@ limitations under the License.
|
|||||||
<string name="google_account_key">googleAccount</string>
|
<string name="google_account_key">googleAccount</string>
|
||||||
<string name="recording_track_id_key">recordingTrackId</string>
|
<string name="recording_track_id_key">recordingTrackId</string>
|
||||||
<string name="recording_track_paused_key">recordingTrackPaused</string>
|
<string name="recording_track_paused_key">recordingTrackPaused</string>
|
||||||
|
<string name="weight_key">weight</string>
|
||||||
<!-- Keys for non-persisted preferences. Sorted alphabetically. DO NOT TRANSLATE. -->
|
<!-- Keys for non-persisted preferences. Sorted alphabetically. DO NOT TRANSLATE. -->
|
||||||
<string name="settings_advanced_key">settingsAdvanced</string>
|
<string name="settings_advanced_key">settingsAdvanced</string>
|
||||||
<string name="settings_backup_key">settingsBackup</string>
|
<string name="settings_backup_key">settingsBackup</string>
|
||||||
|
|||||||
@@ -555,7 +555,15 @@ limitations under the License.
|
|||||||
translation_description="Label for a track segment">
|
translation_description="Label for a track segment">
|
||||||
Segment
|
Segment
|
||||||
</string>
|
</string>
|
||||||
|
<string name="description_weight_imperial"
|
||||||
|
translation_description="Label for weight in pounds.">
|
||||||
|
Weight (lb)
|
||||||
|
</string>
|
||||||
|
<string name="description_weight_metric"
|
||||||
|
translation_description="Label for weight in kilograms.">
|
||||||
|
Weight (kg)
|
||||||
|
</string>
|
||||||
|
|
||||||
<!-- Eula -->
|
<!-- Eula -->
|
||||||
<string name="eula_accept"
|
<string name="eula_accept"
|
||||||
translation_description="In the 'Terms of Service' dialog, the button to accept.">
|
translation_description="In the 'Terms of Service' dialog, the button to accept.">
|
||||||
@@ -2025,16 +2033,6 @@ limitations under the License.
|
|||||||
Character limit: ~23 (1 line)">
|
Character limit: ~23 (1 line)">
|
||||||
Grade/Elevation
|
Grade/Elevation
|
||||||
</string>
|
</string>
|
||||||
<string name="settings_stats_calorie_weight"
|
|
||||||
translation_description="In the 'Stats settings, the option to configure user's weight.
|
|
||||||
|
|
||||||
Character limit: ~23 (1 line)">
|
|
||||||
Weight
|
|
||||||
</string>
|
|
||||||
<string name="settings_stats_calorie_weight_description"
|
|
||||||
translation_description="In the 'Stats settings, the description message about weight setting item.">
|
|
||||||
Weight for calculating calories.
|
|
||||||
</string>
|
|
||||||
<string name="settings_stats_rate_title"
|
<string name="settings_stats_rate_title"
|
||||||
translation_description="In the 'Stats' settings, the option to change the preferred rate,
|
translation_description="In the 'Stats' settings, the option to change the preferred rate,
|
||||||
either speed (mi/hr) or pace (min/mi).
|
either speed (mi/hr) or pace (min/mi).
|
||||||
@@ -2157,11 +2155,11 @@ limitations under the License.
|
|||||||
Character limit: ~23 (1 line)">
|
Character limit: ~23 (1 line)">
|
||||||
Calories
|
Calories
|
||||||
</string>
|
</string>
|
||||||
<string name="stats_calorie_setup"
|
<string name="stats_calorie_no_calculation"
|
||||||
translation_description="In the 'Stats' page, the button to setup calorie.
|
translation_description="In the 'Stats' page, the message when calories cannot be calculated.
|
||||||
|
|
||||||
Character limit: ~23 (1 line)">
|
%1$s activity type. E.g., 'driving'.">
|
||||||
Setup Activity Type
|
Calories can\'t be calculated with %1$s.
|
||||||
</string>
|
</string>
|
||||||
<string name="stats_fastest_pace"
|
<string name="stats_fastest_pace"
|
||||||
translation_description="In the 'Stats' page, the fastest pace.">
|
translation_description="In the 'Stats' page, the fastest pace.">
|
||||||
@@ -2514,12 +2512,6 @@ limitations under the License.
|
|||||||
%1$d an integer value. E.g., '2'.">
|
%1$d an integer value. E.g., '2'.">
|
||||||
%1$d kB
|
%1$d kB
|
||||||
</string>
|
</string>
|
||||||
<string name="value_integer_kilogram"
|
|
||||||
translation_description="Display an integer value in kilogram (kg).
|
|
||||||
|
|
||||||
%1$d an integer value. E.g., '2'.">
|
|
||||||
%1$d kg
|
|
||||||
</string>
|
|
||||||
<string name="value_integer_kilometer"
|
<string name="value_integer_kilometer"
|
||||||
translation_description="In a setting picker, the string format to display an integer value in
|
translation_description="In a setting picker, the string format to display an integer value in
|
||||||
kilometers (km).
|
kilometers (km).
|
||||||
@@ -2594,12 +2586,6 @@ limitations under the License.
|
|||||||
%1$d an integer value. E.g., '2'.">
|
%1$d an integer value. E.g., '2'.">
|
||||||
%1$d %%
|
%1$d %%
|
||||||
</string>
|
</string>
|
||||||
<string name="value_integer_pound"
|
|
||||||
translation_description="Display an integer value in pound (lb).
|
|
||||||
|
|
||||||
%1$d an integer value. E.g., '2'.">
|
|
||||||
%1$d lb
|
|
||||||
</string>
|
|
||||||
<string name="value_integer_second"
|
<string name="value_integer_second"
|
||||||
translation_description="In a setting picker, the string format to display an integer value in
|
translation_description="In a setting picker, the string format to display an integer value in
|
||||||
seconds (s).
|
seconds (s).
|
||||||
|
|||||||
@@ -30,7 +30,6 @@ limitations under the License.
|
|||||||
<style name="BottomButtonBar">
|
<style name="BottomButtonBar">
|
||||||
<item name="android:layout_height">wrap_content</item>
|
<item name="android:layout_height">wrap_content</item>
|
||||||
<item name="android:layout_width">match_parent</item>
|
<item name="android:layout_width">match_parent</item>
|
||||||
<item name="android:orientation">horizontal</item>
|
|
||||||
</style>
|
</style>
|
||||||
<!-- bottom button divider -->
|
<!-- bottom button divider -->
|
||||||
<style name="BottomButtonDivider">
|
<style name="BottomButtonDivider">
|
||||||
@@ -84,7 +83,7 @@ limitations under the License.
|
|||||||
<item name="android:layout_marginBottom">8dp</item>
|
<item name="android:layout_marginBottom">8dp</item>
|
||||||
<item name="android:layout_marginLeft">20dp</item>
|
<item name="android:layout_marginLeft">20dp</item>
|
||||||
<item name="android:layout_width">match_parent</item>
|
<item name="android:layout_width">match_parent</item>
|
||||||
</style>
|
</style>
|
||||||
<!-- help answer -->
|
<!-- help answer -->
|
||||||
<style name="HelpAnswer" parent="@style/TextSmall">
|
<style name="HelpAnswer" parent="@style/TextSmall">
|
||||||
<item name="android:autoLink">web</item>
|
<item name="android:autoLink">web</item>
|
||||||
@@ -133,30 +132,31 @@ limitations under the License.
|
|||||||
<style name="StatsHorizontalLine">
|
<style name="StatsHorizontalLine">
|
||||||
<item name="android:background">@color/stats_separator</item>
|
<item name="android:background">@color/stats_separator</item>
|
||||||
<item name="android:layout_height">1dp</item>
|
<item name="android:layout_height">1dp</item>
|
||||||
|
<item name="android:layout_marginLeft">8dp</item>
|
||||||
|
<item name="android:layout_marginRight">8dp</item>
|
||||||
<item name="android:layout_width">match_parent</item>
|
<item name="android:layout_width">match_parent</item>
|
||||||
</style>
|
</style>
|
||||||
<!-- stats large item container -->
|
<!-- stats large item container -->
|
||||||
<style name="StatsLargeItemContainer">
|
<style name="StatsLargeItemContainer">
|
||||||
<item name="android:layout_gravity">top</item>
|
<item name="android:layout_gravity">center</item>
|
||||||
<item name="android:layout_height">wrap_content</item>
|
<item name="android:layout_height">wrap_content</item>
|
||||||
<item name="android:layout_weight">10</item>
|
<item name="android:layout_weight">1</item>
|
||||||
<item name="android:layout_width">0dp</item>
|
<item name="android:layout_width">0dp</item>
|
||||||
<item name="android:orientation">vertical</item>
|
<item name="android:orientation">vertical</item>
|
||||||
<item name="android:paddingBottom">6dp</item>
|
<item name="android:paddingBottom">6dp</item>
|
||||||
<item name="android:paddingLeft">8dp</item>
|
|
||||||
<item name="android:paddingRight">8dp</item>
|
|
||||||
<item name="android:paddingTop">6dp</item>
|
<item name="android:paddingTop">6dp</item>
|
||||||
</style>
|
</style>
|
||||||
<!-- stats large label -->
|
<!-- stats large label -->
|
||||||
<style name="StatsLargeLabel" parent="@style/TextSmall">
|
<style name="StatsLargeLabel" parent="@style/TextSmall">
|
||||||
<item name="android:gravity">right</item>
|
<item name="android:gravity">center</item>
|
||||||
<item name="android:layout_gravity">right</item>
|
<item name="android:layout_gravity">center</item>
|
||||||
<item name="android:singleLine">false</item>
|
<item name="android:singleLine">false</item>
|
||||||
<item name="android:textColor">@color/stats_large_label</item>
|
<item name="android:textColor">@color/stats_large_label</item>
|
||||||
<item name="android:textStyle">bold</item>
|
<item name="android:textStyle">bold</item>
|
||||||
</style>
|
</style>
|
||||||
<!-- stats large value -->
|
<!-- stats large value -->
|
||||||
<style name="StatsLargeValue">
|
<style name="StatsLargeValue">
|
||||||
|
<item name="android:layout_gravity">bottom</item>
|
||||||
<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>
|
||||||
@@ -166,7 +166,7 @@ limitations under the License.
|
|||||||
</style>
|
</style>
|
||||||
<!-- stats large value container -->
|
<!-- stats large value container -->
|
||||||
<style name="StatsLargeValueContainer">
|
<style name="StatsLargeValueContainer">
|
||||||
<item name="android:layout_gravity">right</item>
|
<item name="android:layout_gravity">center</item>
|
||||||
<item name="android:layout_height">wrap_content</item>
|
<item name="android:layout_height">wrap_content</item>
|
||||||
<item name="android:layout_marginTop">-4dp</item>
|
<item name="android:layout_marginTop">-4dp</item>
|
||||||
<item name="android:layout_width">wrap_content</item>
|
<item name="android:layout_width">wrap_content</item>
|
||||||
@@ -174,20 +174,26 @@ limitations under the License.
|
|||||||
<!-- stats scroll view -->
|
<!-- stats scroll view -->
|
||||||
<style name="StatsScrollView" parent="@style/ScrollView">
|
<style name="StatsScrollView" parent="@style/ScrollView">
|
||||||
<item name="android:scrollbarStyle">outsideOverlay</item>
|
<item name="android:scrollbarStyle">outsideOverlay</item>
|
||||||
</style>
|
</style>
|
||||||
<!-- stats small item container -->
|
<!-- stats small group container -->
|
||||||
|
<style name="StatsSmallGroupContainer" parent="@style/StatsLargeItemContainer">
|
||||||
|
<item name="android:layout_gravity">top|center</item>
|
||||||
|
<item name="android:paddingTop">12dp</item>
|
||||||
|
</style>
|
||||||
|
<!-- stats small item container, for placing inside StatsSmallGroupContainer -->
|
||||||
<style name="StatsSmallItemContainer" parent="@style/StatsLargeItemContainer">
|
<style name="StatsSmallItemContainer" parent="@style/StatsLargeItemContainer">
|
||||||
<item name="android:paddingTop">12dp</item>
|
<item name="android:paddingTop">12dp</item>
|
||||||
</style>
|
</style>
|
||||||
<!-- stats small label -->
|
<!-- stats small label -->
|
||||||
<style name="StatsSmallLabel" parent="@style/TextSmall">
|
<style name="StatsSmallLabel" parent="@style/TextSmall">
|
||||||
<item name="android:gravity">right</item>
|
<item name="android:gravity">center</item>
|
||||||
<item name="android:layout_gravity">right</item>
|
<item name="android:layout_gravity">center</item>
|
||||||
<item name="android:singleLine">false</item>
|
<item name="android:singleLine">false</item>
|
||||||
<item name="android:textStyle">bold</item>
|
<item name="android:textStyle">bold</item>
|
||||||
</style>
|
</style>
|
||||||
<!-- stats small value -->
|
<!-- stats small value -->
|
||||||
<style name="StatsSmallValue" parent="@style/TextLarge">
|
<style name="StatsSmallValue" parent="@style/TextLarge">
|
||||||
|
<item name="android:layout_gravity">bottom</item>
|
||||||
<item name="android:singleLine">true</item>
|
<item name="android:singleLine">true</item>
|
||||||
<item name="android:textColor">@android:color/white</item>
|
<item name="android:textColor">@android:color/white</item>
|
||||||
</style>
|
</style>
|
||||||
@@ -197,20 +203,15 @@ limitations under the License.
|
|||||||
</style>
|
</style>
|
||||||
<!-- stats unit -->
|
<!-- stats unit -->
|
||||||
<style name="StatsUnit" parent="@style/TextSmall">
|
<style name="StatsUnit" parent="@style/TextSmall">
|
||||||
|
<item name="android:layout_gravity">bottom</item>
|
||||||
<item name="android:paddingLeft">4dp</item>
|
<item name="android:paddingLeft">4dp</item>
|
||||||
<item name="android:singleLine">true</item>
|
<item name="android:singleLine">true</item>
|
||||||
</style>
|
</style>
|
||||||
<!-- stats vertical spacer -->
|
<style name="Text">
|
||||||
<style name="StatsVerticalSpacer">
|
|
||||||
<item name="android:layout_height">match_parent</item>
|
|
||||||
<item name="android:layout_weight">1</item>
|
|
||||||
<item name="android:layout_width">0dp</item>
|
|
||||||
</style>
|
|
||||||
<style name="Text">
|
|
||||||
<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">@android:color/white</item>
|
<item name="android:textColor">@android:color/white</item>
|
||||||
</style>
|
</style>
|
||||||
<!-- text choose activity -->
|
<!-- text choose activity -->
|
||||||
<style name="TextChooseActivity">
|
<style name="TextChooseActivity">
|
||||||
<item name="android:textSize">18sp</item>
|
<item name="android:textSize">18sp</item>
|
||||||
@@ -257,7 +258,6 @@ limitations under the License.
|
|||||||
<item name="android:layout_height">0dp</item>
|
<item name="android:layout_height">0dp</item>
|
||||||
<item name="android:layout_weight">1</item>
|
<item name="android:layout_weight">1</item>
|
||||||
<item name="android:layout_width">match_parent</item>
|
<item name="android:layout_width">match_parent</item>
|
||||||
<item name="android:orientation">horizontal</item>
|
|
||||||
<item name="android:paddingBottom">4dp</item>
|
<item name="android:paddingBottom">4dp</item>
|
||||||
<item name="android:paddingTop">4dp</item>
|
<item name="android:paddingTop">4dp</item>
|
||||||
</style>
|
</style>
|
||||||
@@ -290,7 +290,6 @@ limitations under the License.
|
|||||||
<style name="TrackWidgetHorizontalSeparator">
|
<style name="TrackWidgetHorizontalSeparator">
|
||||||
<item name="android:layout_height">wrap_content</item>
|
<item name="android:layout_height">wrap_content</item>
|
||||||
<item name="android:layout_width">match_parent</item>
|
<item name="android:layout_width">match_parent</item>
|
||||||
<item name="android:orientation">horizontal</item>
|
|
||||||
</style>
|
</style>
|
||||||
<!-- track widget item container -->
|
<!-- track widget item container -->
|
||||||
<style name="TrackWidgetItemContainer">
|
<style name="TrackWidgetItemContainer">
|
||||||
@@ -354,7 +353,7 @@ limitations under the License.
|
|||||||
<item name="android:layout_weight">2</item>
|
<item name="android:layout_weight">2</item>
|
||||||
<item name="android:layout_width">0dp</item>
|
<item name="android:layout_width">0dp</item>
|
||||||
<item name="android:singleLine">true</item>
|
<item name="android:singleLine">true</item>
|
||||||
</style>
|
</style>
|
||||||
<!-- track widget stats container -->
|
<!-- track widget stats container -->
|
||||||
<style name="TrackWidgetStatsContainer">
|
<style name="TrackWidgetStatsContainer">
|
||||||
<item name="android:clickable">true</item>
|
<item name="android:clickable">true</item>
|
||||||
@@ -369,7 +368,6 @@ limitations under the License.
|
|||||||
<item name="android:layout_height">0dp</item>
|
<item name="android:layout_height">0dp</item>
|
||||||
<item name="android:layout_weight">1</item>
|
<item name="android:layout_weight">1</item>
|
||||||
<item name="android:layout_width">match_parent</item>
|
<item name="android:layout_width">match_parent</item>
|
||||||
<item name="android:orientation">horizontal</item>
|
|
||||||
</style>
|
</style>
|
||||||
<!-- track widget unit -->
|
<!-- track widget unit -->
|
||||||
<style name="TrackWidgetUnit">
|
<style name="TrackWidgetUnit">
|
||||||
@@ -412,7 +410,6 @@ limitations under the License.
|
|||||||
<item name="android:layout_height">wrap_content</item>
|
<item name="android:layout_height">wrap_content</item>
|
||||||
<item name="android:layout_marginTop">-4dp</item>
|
<item name="android:layout_marginTop">-4dp</item>
|
||||||
<item name="android:layout_width">wrap_content</item>
|
<item name="android:layout_width">wrap_content</item>
|
||||||
<item name="android:orientation">horizontal</item>
|
|
||||||
</style>
|
</style>
|
||||||
<!-- track widget value container 4x3 -->
|
<!-- track widget value container 4x3 -->
|
||||||
<style name="TrackWidgetValueContainer4x3" parent="@style/TrackWidgetValueContainer">
|
<style name="TrackWidgetValueContainer4x3" parent="@style/TrackWidgetValueContainer">
|
||||||
|
|||||||
@@ -33,16 +33,5 @@ limitations under the License.
|
|||||||
android:defaultValue="false"
|
android:defaultValue="false"
|
||||||
android:key="@string/stats_show_coordinate_key"
|
android:key="@string/stats_show_coordinate_key"
|
||||||
android:title="@string/settings_stats_coordinate" />
|
android:title="@string/settings_stats_coordinate" />
|
||||||
<CheckBoxPreference
|
|
||||||
android:defaultValue="false"
|
|
||||||
android:key="@string/stats_show_calorie_key"
|
|
||||||
android:title="@string/stats_calorie" />
|
|
||||||
<EditTextPreference
|
|
||||||
android:dependency="@string/stats_show_calorie_key"
|
|
||||||
android:imeOptions="actionDone"
|
|
||||||
android:inputType="number"
|
|
||||||
android:key="@string/stats_weight_key"
|
|
||||||
android:persistent="false"
|
|
||||||
android:title="@string/settings_stats_calorie_weight" />
|
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
</PreferenceScreen>
|
</PreferenceScreen>
|
||||||
@@ -19,7 +19,7 @@ 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.Track;
|
import com.google.android.apps.mytracks.content.Track;
|
||||||
import com.google.android.apps.mytracks.stats.TripStatistics;
|
import com.google.android.apps.mytracks.stats.TripStatistics;
|
||||||
import com.google.android.apps.mytracks.util.PreferencesUtils;
|
import com.google.android.apps.mytracks.util.CalorieUtils.ActivityType;
|
||||||
import com.google.android.apps.mytracks.util.StatsUtils;
|
import com.google.android.apps.mytracks.util.StatsUtils;
|
||||||
import com.google.android.maps.mytracks.R;
|
import com.google.android.maps.mytracks.R;
|
||||||
|
|
||||||
@@ -38,7 +38,7 @@ public class AggregatedStatsActivity extends AbstractMyTracksActivity {
|
|||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
StatsUtils.setTripStatisticsValues(
|
StatsUtils.setTripStatisticsValues(
|
||||||
this, this, null, getTripStatistics(), PreferencesUtils.RECORDING_TRACK_ID_DEFAULT);
|
this, this, null, getTripStatistics(), ActivityType.WALKING, null);
|
||||||
StatsUtils.setLocationValues(this, this, null, null, false);
|
StatsUtils.setLocationValues(this, this, null, null, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,12 +30,6 @@ public class Constants {
|
|||||||
*/
|
*/
|
||||||
public static final String ACCOUNT_TYPE = "com.google";
|
public static final String ACCOUNT_TYPE = "com.google";
|
||||||
|
|
||||||
/**
|
|
||||||
* Maximum number of track points that will be loaded at one time. With
|
|
||||||
* recording frequency of 2 seconds, 20000 corresponds to 11.1 hours.
|
|
||||||
*/
|
|
||||||
public static final int MAX_LOADED_TRACK_POINTS = 20000;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Maximum number of waypoints that will be loaded at one time.
|
* Maximum number of waypoints that will be loaded at one time.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
|
|||||||
import com.google.android.apps.mytracks.content.Track;
|
import com.google.android.apps.mytracks.content.Track;
|
||||||
import com.google.android.apps.mytracks.io.sync.SyncUtils;
|
import com.google.android.apps.mytracks.io.sync.SyncUtils;
|
||||||
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.maps.mytracks.R;
|
import com.google.android.maps.mytracks.R;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
@@ -32,6 +33,9 @@ import android.os.AsyncTask;
|
|||||||
*/
|
*/
|
||||||
public class DeleteAsyncTask extends AsyncTask<Void, Integer, Boolean> {
|
public class DeleteAsyncTask extends AsyncTask<Void, Integer, Boolean> {
|
||||||
|
|
||||||
|
// 1 second in milliseconds
|
||||||
|
private static final long ONE_SECOND = (long) UnitConversions.S_TO_MS;
|
||||||
|
|
||||||
private DeleteActivity deleteActivity;
|
private DeleteActivity deleteActivity;
|
||||||
private final long[] trackIds;
|
private final long[] trackIds;
|
||||||
private final Context context;
|
private final Context context;
|
||||||
@@ -82,7 +86,7 @@ public class DeleteAsyncTask extends AsyncTask<Void, Integer, Boolean> {
|
|||||||
if (isCancelled()) {
|
if (isCancelled()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
Thread.sleep(1000);
|
Thread.sleep(ONE_SECOND);
|
||||||
}
|
}
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import com.google.android.apps.mytracks.services.sensors.SensorManager;
|
|||||||
import com.google.android.apps.mytracks.services.sensors.SensorManagerFactory;
|
import com.google.android.apps.mytracks.services.sensors.SensorManagerFactory;
|
||||||
import com.google.android.apps.mytracks.services.sensors.SensorUtils;
|
import com.google.android.apps.mytracks.services.sensors.SensorUtils;
|
||||||
import com.google.android.apps.mytracks.util.TrackRecordingServiceConnectionUtils;
|
import com.google.android.apps.mytracks.util.TrackRecordingServiceConnectionUtils;
|
||||||
|
import com.google.android.apps.mytracks.util.UnitConversions;
|
||||||
import com.google.android.maps.mytracks.R;
|
import com.google.android.maps.mytracks.R;
|
||||||
import com.google.protobuf.InvalidProtocolBufferException;
|
import com.google.protobuf.InvalidProtocolBufferException;
|
||||||
|
|
||||||
@@ -41,7 +42,9 @@ import android.widget.TextView;
|
|||||||
public class SensorStateActivity extends AbstractMyTracksActivity {
|
public class SensorStateActivity extends AbstractMyTracksActivity {
|
||||||
|
|
||||||
private static final String TAG = SensorStateActivity.class.getName();
|
private static final String TAG = SensorStateActivity.class.getName();
|
||||||
private static final long ONE_SECOND = 1000;
|
|
||||||
|
// 1 second in milliseconds
|
||||||
|
private static final long ONE_SECOND = (long) UnitConversions.S_TO_MS;
|
||||||
|
|
||||||
private TrackRecordingServiceConnection trackRecordingServiceConnection;
|
private TrackRecordingServiceConnection trackRecordingServiceConnection;
|
||||||
private Handler handler;
|
private Handler handler;
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ package com.google.android.apps.mytracks;
|
|||||||
import com.google.android.apps.mytracks.services.ITrackRecordingService;
|
import com.google.android.apps.mytracks.services.ITrackRecordingService;
|
||||||
import com.google.android.apps.mytracks.services.TrackRecordingServiceConnection;
|
import com.google.android.apps.mytracks.services.TrackRecordingServiceConnection;
|
||||||
import com.google.android.apps.mytracks.util.StringUtils;
|
import com.google.android.apps.mytracks.util.StringUtils;
|
||||||
|
import com.google.android.apps.mytracks.util.UnitConversions;
|
||||||
import com.google.android.maps.mytracks.R;
|
import com.google.android.maps.mytracks.R;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
@@ -38,7 +39,9 @@ import android.widget.TextView;
|
|||||||
public class TrackController {
|
public class TrackController {
|
||||||
|
|
||||||
private static final String TAG = TrackController.class.getSimpleName();
|
private static final String TAG = TrackController.class.getSimpleName();
|
||||||
private static final int ONE_SECOND = 1000;
|
|
||||||
|
// 1 second in milliseconds
|
||||||
|
private static final long ONE_SECOND = (long) UnitConversions.S_TO_MS;
|
||||||
|
|
||||||
private final Activity activity;
|
private final Activity activity;
|
||||||
private final TrackRecordingServiceConnection trackRecordingServiceConnection;
|
private final TrackRecordingServiceConnection trackRecordingServiceConnection;
|
||||||
|
|||||||
@@ -23,6 +23,8 @@ import com.google.android.apps.mytracks.content.Waypoint;
|
|||||||
import com.google.android.apps.mytracks.content.Waypoint.WaypointType;
|
import com.google.android.apps.mytracks.content.Waypoint.WaypointType;
|
||||||
import com.google.android.apps.mytracks.content.WaypointCreationRequest;
|
import com.google.android.apps.mytracks.content.WaypointCreationRequest;
|
||||||
import com.google.android.apps.mytracks.fragments.ChartFragment;
|
import com.google.android.apps.mytracks.fragments.ChartFragment;
|
||||||
|
import com.google.android.apps.mytracks.fragments.ChooseActivityTypeDialogFragment;
|
||||||
|
import com.google.android.apps.mytracks.fragments.ChooseActivityTypeDialogFragment.ChooseActivityTypeCaller;
|
||||||
import com.google.android.apps.mytracks.fragments.ConfirmDeleteDialogFragment;
|
import com.google.android.apps.mytracks.fragments.ConfirmDeleteDialogFragment;
|
||||||
import com.google.android.apps.mytracks.fragments.ExportDialogFragment;
|
import com.google.android.apps.mytracks.fragments.ExportDialogFragment;
|
||||||
import com.google.android.apps.mytracks.fragments.ExportDialogFragment.ExportCaller;
|
import com.google.android.apps.mytracks.fragments.ExportDialogFragment.ExportCaller;
|
||||||
@@ -37,11 +39,15 @@ import com.google.android.apps.mytracks.services.TrackRecordingServiceConnection
|
|||||||
import com.google.android.apps.mytracks.settings.SettingsActivity;
|
import com.google.android.apps.mytracks.settings.SettingsActivity;
|
||||||
import com.google.android.apps.mytracks.util.AnalyticsUtils;
|
import com.google.android.apps.mytracks.util.AnalyticsUtils;
|
||||||
import com.google.android.apps.mytracks.util.ApiAdapterFactory;
|
import com.google.android.apps.mytracks.util.ApiAdapterFactory;
|
||||||
|
import com.google.android.apps.mytracks.util.CalorieUtils;
|
||||||
|
import com.google.android.apps.mytracks.util.CalorieUtils.ActivityType;
|
||||||
import com.google.android.apps.mytracks.util.FileUtils;
|
import com.google.android.apps.mytracks.util.FileUtils;
|
||||||
import com.google.android.apps.mytracks.util.GoogleFeedbackUtils;
|
import com.google.android.apps.mytracks.util.GoogleFeedbackUtils;
|
||||||
import com.google.android.apps.mytracks.util.IntentUtils;
|
import com.google.android.apps.mytracks.util.IntentUtils;
|
||||||
import com.google.android.apps.mytracks.util.PreferencesUtils;
|
import com.google.android.apps.mytracks.util.PreferencesUtils;
|
||||||
|
import com.google.android.apps.mytracks.util.TrackIconUtils;
|
||||||
import com.google.android.apps.mytracks.util.TrackRecordingServiceConnectionUtils;
|
import com.google.android.apps.mytracks.util.TrackRecordingServiceConnectionUtils;
|
||||||
|
import com.google.android.apps.mytracks.util.TrackUtils;
|
||||||
import com.google.android.maps.mytracks.R;
|
import com.google.android.maps.mytracks.R;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
@@ -74,7 +80,8 @@ import java.util.Date;
|
|||||||
* @author Leif Hendrik Wilden
|
* @author Leif Hendrik Wilden
|
||||||
* @author Rodrigo Damazio
|
* @author Rodrigo Damazio
|
||||||
*/
|
*/
|
||||||
public class TrackDetailActivity extends AbstractSendToGoogleActivity implements ExportCaller {
|
public class TrackDetailActivity extends AbstractSendToGoogleActivity
|
||||||
|
implements ChooseActivityTypeCaller, ExportCaller {
|
||||||
|
|
||||||
public static final String EXTRA_TRACK_ID = "track_id";
|
public static final String EXTRA_TRACK_ID = "track_id";
|
||||||
public static final String EXTRA_MARKER_ID = "marker_id";
|
public static final String EXTRA_MARKER_ID = "marker_id";
|
||||||
@@ -612,4 +619,23 @@ public class TrackDetailActivity extends AbstractSendToGoogleActivity implements
|
|||||||
}
|
}
|
||||||
setTitle(title);
|
setTitle(title);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void chooseActivityType(String category) {
|
||||||
|
ChooseActivityTypeDialogFragment.newInstance(category).show(getSupportFragmentManager(),
|
||||||
|
ChooseActivityTypeDialogFragment.CHOOSE_ACTIVITY_TYPE_DIALOG_TAG);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onChooseActivityTypeDone(String iconValue, boolean newWeight) {
|
||||||
|
Track track = myTracksProviderUtils.getTrack(trackId);
|
||||||
|
String category = getString(TrackIconUtils.getIconActivityType(iconValue));
|
||||||
|
TrackUtils.updateTrack(
|
||||||
|
this, track, null, category, null, myTracksProviderUtils, trackRecordingServiceConnection, newWeight);
|
||||||
|
|
||||||
|
// Add toast if cannot calculate calorie
|
||||||
|
if (CalorieUtils.getActivityType(this, category) == ActivityType.INVALID) {
|
||||||
|
String message = getString(R.string.stats_calorie_no_calculation, category);
|
||||||
|
Toast.makeText(this, message, Toast.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -21,17 +21,12 @@ import com.google.android.apps.mytracks.content.Track;
|
|||||||
import com.google.android.apps.mytracks.fragments.ChooseActivityTypeDialogFragment;
|
import com.google.android.apps.mytracks.fragments.ChooseActivityTypeDialogFragment;
|
||||||
import com.google.android.apps.mytracks.fragments.ChooseActivityTypeDialogFragment.ChooseActivityTypeCaller;
|
import com.google.android.apps.mytracks.fragments.ChooseActivityTypeDialogFragment.ChooseActivityTypeCaller;
|
||||||
import com.google.android.apps.mytracks.services.TrackRecordingServiceConnection;
|
import com.google.android.apps.mytracks.services.TrackRecordingServiceConnection;
|
||||||
import com.google.android.apps.mytracks.util.ApiAdapterFactory;
|
|
||||||
import com.google.android.apps.mytracks.util.CalorieUtils;
|
|
||||||
import com.google.android.apps.mytracks.util.PreferencesUtils;
|
|
||||||
import com.google.android.apps.mytracks.util.TrackIconUtils;
|
import com.google.android.apps.mytracks.util.TrackIconUtils;
|
||||||
import com.google.android.apps.mytracks.util.TrackNameUtils;
|
import com.google.android.apps.mytracks.util.TrackNameUtils;
|
||||||
import com.google.android.apps.mytracks.util.TrackRecordingServiceConnectionUtils;
|
import com.google.android.apps.mytracks.util.TrackRecordingServiceConnectionUtils;
|
||||||
|
import com.google.android.apps.mytracks.util.TrackUtils;
|
||||||
import com.google.android.maps.mytracks.R;
|
import com.google.android.maps.mytracks.R;
|
||||||
|
|
||||||
import android.graphics.Bitmap;
|
|
||||||
import android.graphics.BitmapFactory;
|
|
||||||
import android.graphics.BitmapFactory.Options;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.KeyEvent;
|
import android.view.KeyEvent;
|
||||||
@@ -42,7 +37,6 @@ import android.widget.ArrayAdapter;
|
|||||||
import android.widget.AutoCompleteTextView;
|
import android.widget.AutoCompleteTextView;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
import android.widget.EditText;
|
import android.widget.EditText;
|
||||||
import android.widget.ImageView;
|
|
||||||
import android.widget.Spinner;
|
import android.widget.Spinner;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -70,6 +64,8 @@ public class TrackEditActivity extends AbstractMyTracksActivity
|
|||||||
private AutoCompleteTextView activityType;
|
private AutoCompleteTextView activityType;
|
||||||
private Spinner activityTypeIcon;
|
private Spinner activityTypeIcon;
|
||||||
private EditText description;
|
private EditText description;
|
||||||
|
|
||||||
|
private boolean newWeight = false;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle bundle) {
|
protected void onCreate(Bundle bundle) {
|
||||||
@@ -101,14 +97,14 @@ public class TrackEditActivity extends AbstractMyTracksActivity
|
|||||||
this, R.array.activity_types, android.R.layout.simple_dropdown_item_1line);
|
this, R.array.activity_types, android.R.layout.simple_dropdown_item_1line);
|
||||||
activityType.setAdapter(adapter);
|
activityType.setAdapter(adapter);
|
||||||
activityType.setOnItemClickListener(new AdapterView.OnItemClickListener() {
|
activityType.setOnItemClickListener(new AdapterView.OnItemClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||||
setActivityTypeIcon(TrackIconUtils.getIconValue(
|
setActivityTypeIcon(TrackIconUtils.getIconValue(
|
||||||
TrackEditActivity.this, (String) activityType.getAdapter().getItem(position)));
|
TrackEditActivity.this, (String) activityType.getAdapter().getItem(position)));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
activityType.setOnFocusChangeListener(new View.OnFocusChangeListener() {
|
activityType.setOnFocusChangeListener(new View.OnFocusChangeListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onFocusChange(View v, boolean hasFocus) {
|
public void onFocusChange(View v, boolean hasFocus) {
|
||||||
if (!hasFocus) {
|
if (!hasFocus) {
|
||||||
setActivityTypeIcon(TrackIconUtils.getIconValue(
|
setActivityTypeIcon(TrackIconUtils.getIconValue(
|
||||||
@@ -125,55 +121,28 @@ public class TrackEditActivity extends AbstractMyTracksActivity
|
|||||||
iconValue = track.getIcon();
|
iconValue = track.getIcon();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a border around the icon
|
|
||||||
Options options = new BitmapFactory.Options();
|
|
||||||
options.inJustDecodeBounds = true;
|
|
||||||
BitmapFactory.decodeResource(getResources(), R.drawable.ic_track_airplane, options);
|
|
||||||
final int padding = 4;
|
|
||||||
final int width = options.outWidth + 2 * padding;
|
|
||||||
final int height = options.outHeight + 2 * padding;
|
|
||||||
|
|
||||||
activityTypeIcon = (Spinner) findViewById(R.id.track_edit_activity_type_icon);
|
activityTypeIcon = (Spinner) findViewById(R.id.track_edit_activity_type_icon);
|
||||||
ArrayAdapter<StringBuilder> activityTypeIconAdapter = new ArrayAdapter<StringBuilder>(
|
activityTypeIcon.setAdapter(TrackIconUtils.getIconSpinnerAdapter(this, iconValue));
|
||||||
this, android.R.layout.simple_spinner_item,
|
|
||||||
new StringBuilder[] {new StringBuilder(iconValue)}) {
|
|
||||||
@Override
|
|
||||||
public View getView(int position, View convertView, android.view.ViewGroup parent) {
|
|
||||||
ImageView imageView =
|
|
||||||
convertView != null ? (ImageView) convertView : new ImageView(getContext());
|
|
||||||
Bitmap source = BitmapFactory.decodeResource(
|
|
||||||
getResources(), TrackIconUtils.getIconDrawable(getItem(position).toString()));
|
|
||||||
if (ApiAdapterFactory.getApiAdapter().isSpinnerBackgroundLight()) {
|
|
||||||
source = TrackIconUtils.invertBitmap(source);
|
|
||||||
}
|
|
||||||
imageView.setImageBitmap(source);
|
|
||||||
imageView.setMinimumHeight(height);
|
|
||||||
imageView.setMinimumWidth(width);
|
|
||||||
imageView.setPadding(padding, padding, padding, padding);
|
|
||||||
return imageView;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
activityTypeIcon.setAdapter(activityTypeIconAdapter);
|
|
||||||
activityTypeIcon.setOnTouchListener(new View.OnTouchListener() {
|
activityTypeIcon.setOnTouchListener(new View.OnTouchListener() {
|
||||||
@Override
|
@Override
|
||||||
public boolean onTouch(View v, MotionEvent event) {
|
public boolean onTouch(View v, MotionEvent event) {
|
||||||
if (event.getAction() == MotionEvent.ACTION_UP) {
|
if (event.getAction() == MotionEvent.ACTION_UP) {
|
||||||
new ChooseActivityTypeDialogFragment().show(getSupportFragmentManager(),
|
ChooseActivityTypeDialogFragment.newInstance(activityType.getText().toString()).show(
|
||||||
|
getSupportFragmentManager(),
|
||||||
ChooseActivityTypeDialogFragment.CHOOSE_ACTIVITY_TYPE_DIALOG_TAG);
|
ChooseActivityTypeDialogFragment.CHOOSE_ACTIVITY_TYPE_DIALOG_TAG);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
activityTypeIcon.setOnKeyListener(new View.OnKeyListener() {
|
activityTypeIcon.setOnKeyListener(new View.OnKeyListener() {
|
||||||
@Override
|
@Override
|
||||||
public boolean onKey(View v, int keyCode, KeyEvent event) {
|
public boolean onKey(View v, int keyCode, KeyEvent event) {
|
||||||
if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
|
if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
|
||||||
new ChooseActivityTypeDialogFragment().show(getSupportFragmentManager(),
|
ChooseActivityTypeDialogFragment.newInstance(activityType.getText().toString()).show(
|
||||||
|
getSupportFragmentManager(),
|
||||||
ChooseActivityTypeDialogFragment.CHOOSE_ACTIVITY_TYPE_DIALOG_TAG);
|
ChooseActivityTypeDialogFragment.CHOOSE_ACTIVITY_TYPE_DIALOG_TAG);
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -184,36 +153,9 @@ public class TrackEditActivity extends AbstractMyTracksActivity
|
|||||||
save.setOnClickListener(new View.OnClickListener() {
|
save.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
track.setName(name.getText().toString());
|
TrackUtils.updateTrack(TrackEditActivity.this, track, name.getText().toString(),
|
||||||
|
activityType.getText().toString(), description.getText().toString(),
|
||||||
String category = activityType.getText().toString();
|
myTracksProviderUtils, trackRecordingServiceConnection, newWeight);
|
||||||
boolean newCategory = !category.equals(track.getCategory());
|
|
||||||
boolean isRecording = trackId
|
|
||||||
== PreferencesUtils.getLong(TrackEditActivity.this, R.string.recording_track_id_key);
|
|
||||||
|
|
||||||
if (newCategory && !isRecording) {
|
|
||||||
// Update calorie
|
|
||||||
double calorie = CalorieUtils.getTrackCalorie(TrackEditActivity.this, track, -1L);
|
|
||||||
track.getTripStatistics().setCalorie(calorie);
|
|
||||||
}
|
|
||||||
|
|
||||||
track.setCategory(category);
|
|
||||||
track.setIcon(TrackIconUtils.getIconValue(TrackEditActivity.this, category));
|
|
||||||
track.setDescription(description.getText().toString());
|
|
||||||
track.setModifiedTime(System.currentTimeMillis());
|
|
||||||
myTracksProviderUtils.updateTrack(track);
|
|
||||||
|
|
||||||
if (newCategory && isRecording) {
|
|
||||||
// Update calorie through track recording service
|
|
||||||
TrackRecordingServiceConnectionUtils.updateCalorie(trackRecordingServiceConnection);
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean driveSync = PreferencesUtils.getBoolean(
|
|
||||||
TrackEditActivity.this, R.string.drive_sync_key, PreferencesUtils.DRIVE_SYNC_DEFAULT);
|
|
||||||
if (driveSync) {
|
|
||||||
PreferencesUtils.addToList(TrackEditActivity.this, R.string.drive_edited_list_key,
|
|
||||||
PreferencesUtils.DRIVE_EDITED_LIST_DEFAULT, String.valueOf(track.getId()));
|
|
||||||
}
|
|
||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -261,26 +203,18 @@ public class TrackEditActivity extends AbstractMyTracksActivity
|
|||||||
protected int getLayoutResId() {
|
protected int getLayoutResId() {
|
||||||
return R.layout.track_edit;
|
return R.layout.track_edit;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the activity type icon.
|
|
||||||
*
|
|
||||||
* @param value the icon value
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
private void setActivityTypeIcon(String value) {
|
private void setActivityTypeIcon(String value) {
|
||||||
iconValue = value;
|
iconValue = value;
|
||||||
ArrayAdapter<StringBuilder> adapter =
|
TrackIconUtils.setIconSpinner(activityTypeIcon, value);
|
||||||
(ArrayAdapter<StringBuilder>) activityTypeIcon.getAdapter();
|
|
||||||
StringBuilder stringBuilder = adapter.getItem(0);
|
|
||||||
stringBuilder.delete(0, stringBuilder.length());
|
|
||||||
stringBuilder.append(value);
|
|
||||||
adapter.notifyDataSetChanged();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onChooseActivityTypeDone(String value) {
|
public void onChooseActivityTypeDone(String value, boolean hasNewWeight) {
|
||||||
activityType.setText(getString(TrackIconUtils.getIconActivityType(value)));
|
if (!newWeight) {
|
||||||
|
newWeight = hasNewWeight;
|
||||||
|
}
|
||||||
setActivityTypeIcon(value);
|
setActivityTypeIcon(value);
|
||||||
|
activityType.setText(getString(TrackIconUtils.getIconActivityType(value)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -91,50 +91,58 @@ public class MyTracksProvider extends ContentProvider {
|
|||||||
} else {
|
} else {
|
||||||
// Incremental upgrades. One if statement per DB version.
|
// Incremental upgrades. One if statement per DB version.
|
||||||
|
|
||||||
// Add track points SENSOR column
|
// Add track point SENSOR column
|
||||||
if (oldVersion <= 17) {
|
if (oldVersion <= 17) {
|
||||||
Log.w(TAG, "Upgrade DB: Adding sensor column.");
|
Log.w(TAG, "Upgrade DB: Adding track point sensor column.");
|
||||||
db.execSQL("ALTER TABLE " + TrackPointsColumns.TABLE_NAME + " ADD "
|
db.execSQL("ALTER TABLE " + TrackPointsColumns.TABLE_NAME + " ADD "
|
||||||
+ TrackPointsColumns.SENSOR + " BLOB");
|
+ TrackPointsColumns.SENSOR + " BLOB");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add tracks TABLEID column
|
// Add track TABLEID column
|
||||||
if (oldVersion <= 18) {
|
if (oldVersion <= 18) {
|
||||||
Log.w(TAG, "Upgrade DB: Adding tableid column.");
|
Log.w(TAG, "Upgrade DB: Adding track tableid column.");
|
||||||
db.execSQL("ALTER TABLE " + TracksColumns.TABLE_NAME + " ADD " + TracksColumns.TABLEID
|
db.execSQL("ALTER TABLE " + TracksColumns.TABLE_NAME + " ADD " + TracksColumns.TABLEID
|
||||||
+ " STRING");
|
+ " STRING");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add tracks ICON column
|
// Add track ICON column
|
||||||
if (oldVersion <= 19) {
|
if (oldVersion <= 19) {
|
||||||
Log.w(TAG, "Upgrade DB: Adding icon column.");
|
Log.w(TAG, "Upgrade DB: Adding track icon column.");
|
||||||
db.execSQL(
|
db.execSQL(
|
||||||
"ALTER TABLE " + TracksColumns.TABLE_NAME + " ADD " + TracksColumns.ICON + " STRING");
|
"ALTER TABLE " + TracksColumns.TABLE_NAME + " ADD " + TracksColumns.ICON + " STRING");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add track DRIVEID, MODIFIEDTIME, and SHAREDWITHME columns
|
// Add track DRIVEID, MODIFIEDTIME, and SHAREDWITHME columns
|
||||||
if (oldVersion <= 20) {
|
if (oldVersion <= 20) {
|
||||||
Log.w(TAG, "Upgrade DB: Adding driveid column.");
|
Log.w(TAG, "Upgrade DB: Adding track driveid column.");
|
||||||
db.execSQL("ALTER TABLE " + TracksColumns.TABLE_NAME + " ADD " + TracksColumns.DRIVEID
|
db.execSQL("ALTER TABLE " + TracksColumns.TABLE_NAME + " ADD " + TracksColumns.DRIVEID
|
||||||
+ " STRING");
|
+ " STRING");
|
||||||
Log.w(TAG, "Upgrade DB: Adding modifiedtime column.");
|
Log.w(TAG, "Upgrade DB: Adding track modifiedtime column.");
|
||||||
db.execSQL("ALTER TABLE " + TracksColumns.TABLE_NAME + " ADD "
|
db.execSQL("ALTER TABLE " + TracksColumns.TABLE_NAME + " ADD "
|
||||||
+ TracksColumns.MODIFIEDTIME + " INTEGER");
|
+ TracksColumns.MODIFIEDTIME + " INTEGER");
|
||||||
Log.w(TAG, "Upgrade DB: Adding sharedwithme column.");
|
|
||||||
|
Log.w(TAG, "Upgrade DB: Adding track sharedwithme column.");
|
||||||
db.execSQL("ALTER TABLE " + TracksColumns.TABLE_NAME + " ADD "
|
db.execSQL("ALTER TABLE " + TracksColumns.TABLE_NAME + " ADD "
|
||||||
+ TracksColumns.SHAREDWITHME + " INTEGER");
|
+ TracksColumns.SHAREDWITHME + " INTEGER");
|
||||||
Log.w(TAG, "Upgrade DB: Adding sharedowner column.");
|
|
||||||
|
Log.w(TAG, "Upgrade DB: Adding track sharedowner column.");
|
||||||
db.execSQL("ALTER TABLE " + TracksColumns.TABLE_NAME + " ADD " + TracksColumns.SHAREDOWNER
|
db.execSQL("ALTER TABLE " + TracksColumns.TABLE_NAME + " ADD " + TracksColumns.SHAREDOWNER
|
||||||
+ " STRING");
|
+ " STRING");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add waypoint CALORIE and PHOTOURL columns. Add track CALORIE column.
|
||||||
if (oldVersion <= 21) {
|
if (oldVersion <= 21) {
|
||||||
Log.w(TAG, "Upgrade DB: Adding photo url column.");
|
Log.w(TAG, "Upgrade DB: Adding waypoint calorie column.");
|
||||||
db.execSQL("ALTER TABLE " + WaypointsColumns.TABLE_NAME + " ADD " + WaypointsColumns.PHOTOURL
|
db.execSQL("ALTER TABLE " + WaypointsColumns.TABLE_NAME + " ADD "
|
||||||
+ " STRING");
|
+ WaypointsColumns.CALORIE + " FLOAT");
|
||||||
|
|
||||||
|
Log.w(TAG, "Upgrade DB: Adding waypoint photo url column.");
|
||||||
|
db.execSQL("ALTER TABLE " + WaypointsColumns.TABLE_NAME + " ADD "
|
||||||
|
+ WaypointsColumns.PHOTOURL + " STRING");
|
||||||
|
|
||||||
Log.w(TAG, "Upgrade DB: Adding track calorie column.");
|
Log.w(TAG, "Upgrade DB: Adding track calorie column.");
|
||||||
db.execSQL("ALTER TABLE " + TracksColumns.TABLE_NAME + " ADD " + TracksColumns.CALORIE
|
db.execSQL("ALTER TABLE " + TracksColumns.TABLE_NAME + " ADD " + TracksColumns.CALORIE
|
||||||
+ " INTEGER");
|
+ " FLOAT");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -360,7 +360,8 @@ public class SearchEngine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Score recent tracks higher.
|
// Score recent tracks higher.
|
||||||
long timeAgoHours = (query.currentTimestamp - timestamp) / (60L * 60L * 1000L);
|
long timeAgoHours = (long) ((query.currentTimestamp - timestamp) * UnitConversions.MS_TO_S
|
||||||
|
* UnitConversions.S_TO_MIN * UnitConversions.MIN_TO_HR);
|
||||||
if (timeAgoHours > 0L) {
|
if (timeAgoHours > 0L) {
|
||||||
return squash(timeAgoHours);
|
return squash(timeAgoHours);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -492,52 +492,60 @@ public class TrackDataHub implements DataSourceListener {
|
|||||||
|
|
||||||
long lastTrackPointId = myTracksProviderUtils.getLastTrackPointId(selectedTrackId);
|
long lastTrackPointId = myTracksProviderUtils.getLastTrackPointId(selectedTrackId);
|
||||||
int samplingFrequency = -1;
|
int samplingFrequency = -1;
|
||||||
LocationIterator iterator = myTracksProviderUtils.getTrackPointLocationIterator(selectedTrackId,
|
|
||||||
localLastSeenLocationId + 1, false, MyTracksProviderUtils.DEFAULT_LOCATION_FACTORY);
|
|
||||||
boolean includeNextPoint = false;
|
boolean includeNextPoint = false;
|
||||||
while (iterator.hasNext()) {
|
LocationIterator locationIterator = null;
|
||||||
Location location = iterator.next();
|
|
||||||
long locationId = iterator.getLocationId();
|
|
||||||
|
|
||||||
// Stop if past the last wanted point
|
try {
|
||||||
if (maxPointId != -1L && locationId > maxPointId) {
|
locationIterator = myTracksProviderUtils.getTrackPointLocationIterator(selectedTrackId,
|
||||||
break;
|
localLastSeenLocationId + 1, false, MyTracksProviderUtils.DEFAULT_LOCATION_FACTORY);
|
||||||
}
|
|
||||||
|
|
||||||
if (localFirstSeenLocationId == -1) {
|
while (locationIterator.hasNext()) {
|
||||||
localFirstSeenLocationId = locationId;
|
Location location = locationIterator.next();
|
||||||
}
|
long locationId = locationIterator.getLocationId();
|
||||||
|
|
||||||
if (samplingFrequency == -1) {
|
// Stop if past the last wanted point
|
||||||
long numTotalPoints = Math.max(0L, lastTrackPointId - localFirstSeenLocationId);
|
if (maxPointId != -1L && locationId > maxPointId) {
|
||||||
samplingFrequency = 1 + (int) (numTotalPoints / targetNumPoints);
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
if (!LocationUtils.isValidLocation(location)) {
|
|
||||||
// TODO: also include the last valid point before a split
|
|
||||||
for (TrackDataListener trackDataListener : sampledInListeners) {
|
|
||||||
trackDataListener.onSegmentSplit(location);
|
|
||||||
includeNextPoint = true;
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// Also include the last point if the selected track is not recording.
|
if (localFirstSeenLocationId == -1) {
|
||||||
if (includeNextPoint || (localNumLoadedPoints % samplingFrequency == 0)
|
localFirstSeenLocationId = locationId;
|
||||||
|| (locationId == lastTrackPointId && !isSelectedTrackRecording())) {
|
}
|
||||||
includeNextPoint = false;
|
|
||||||
|
if (samplingFrequency == -1) {
|
||||||
|
long numTotalPoints = Math.max(0L, lastTrackPointId - localFirstSeenLocationId);
|
||||||
|
samplingFrequency = 1 + (int) (numTotalPoints / targetNumPoints);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!LocationUtils.isValidLocation(location)) {
|
||||||
|
// TODO: also include the last valid point before a split
|
||||||
for (TrackDataListener trackDataListener : sampledInListeners) {
|
for (TrackDataListener trackDataListener : sampledInListeners) {
|
||||||
trackDataListener.onSampledInTrackPoint(location);
|
trackDataListener.onSegmentSplit(location);
|
||||||
|
includeNextPoint = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (TrackDataListener trackDataListener : sampledOutListeners) {
|
// Also include the last point if the selected track is not recording.
|
||||||
trackDataListener.onSampledOutTrackPoint(location);
|
if (includeNextPoint || (localNumLoadedPoints % samplingFrequency == 0)
|
||||||
|
|| (locationId == lastTrackPointId && !isSelectedTrackRecording())) {
|
||||||
|
includeNextPoint = false;
|
||||||
|
for (TrackDataListener trackDataListener : sampledInListeners) {
|
||||||
|
trackDataListener.onSampledInTrackPoint(location);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (TrackDataListener trackDataListener : sampledOutListeners) {
|
||||||
|
trackDataListener.onSampledOutTrackPoint(location);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
localNumLoadedPoints++;
|
localNumLoadedPoints++;
|
||||||
localLastSeenLocationId = locationId;
|
localLastSeenLocationId = locationId;
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
if (locationIterator != null) {
|
||||||
|
locationIterator.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
iterator.close();
|
|
||||||
|
|
||||||
if (updateSamplingState) {
|
if (updateSamplingState) {
|
||||||
numLoadedPoints = localNumLoadedPoints;
|
numLoadedPoints = localNumLoadedPoints;
|
||||||
|
|||||||
@@ -453,7 +453,7 @@ public class ChartFragment extends Fragment implements TrackDataListener {
|
|||||||
|
|
||||||
if (tripStatisticsUpdater != null) {
|
if (tripStatisticsUpdater != null) {
|
||||||
tripStatisticsUpdater.addLocation(location, recordingDistanceInterval, false,
|
tripStatisticsUpdater.addLocation(location, recordingDistanceInterval, false,
|
||||||
ActivityType.INVALID, PreferencesUtils.STATS_WEIGHT_DEFAULT);
|
ActivityType.INVALID, PreferencesUtils.WEIGHT_DEFAULT);
|
||||||
TripStatistics tripStatistics = tripStatisticsUpdater.getTripStatistics();
|
TripStatistics tripStatistics = tripStatisticsUpdater.getTripStatistics();
|
||||||
if (chartByDistance) {
|
if (chartByDistance) {
|
||||||
double distance = tripStatistics.getTotalDistance() * UnitConversions.M_TO_KM;
|
double distance = tripStatistics.getTotalDistance() * UnitConversions.M_TO_KM;
|
||||||
|
|||||||
+115
-15
@@ -16,12 +16,16 @@
|
|||||||
|
|
||||||
package com.google.android.apps.mytracks.fragments;
|
package com.google.android.apps.mytracks.fragments;
|
||||||
|
|
||||||
|
import com.google.android.apps.mytracks.util.PreferencesUtils;
|
||||||
|
import com.google.android.apps.mytracks.util.StringUtils;
|
||||||
import com.google.android.apps.mytracks.util.TrackIconUtils;
|
import com.google.android.apps.mytracks.util.TrackIconUtils;
|
||||||
|
import com.google.android.apps.mytracks.util.UnitConversions;
|
||||||
import com.google.android.maps.mytracks.R;
|
import com.google.android.maps.mytracks.R;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
import android.app.Dialog;
|
import android.app.Dialog;
|
||||||
|
import android.content.DialogInterface;
|
||||||
import android.graphics.BitmapFactory;
|
import android.graphics.BitmapFactory;
|
||||||
import android.graphics.BitmapFactory.Options;
|
import android.graphics.BitmapFactory.Options;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
@@ -30,20 +34,22 @@ import android.view.View;
|
|||||||
import android.widget.AdapterView;
|
import android.widget.AdapterView;
|
||||||
import android.widget.AdapterView.OnItemClickListener;
|
import android.widget.AdapterView.OnItemClickListener;
|
||||||
import android.widget.GridView;
|
import android.widget.GridView;
|
||||||
|
import android.widget.ImageButton;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A DialogFragment to choose an activity type.
|
* A DialogFragment to choose an activity type.
|
||||||
*
|
*
|
||||||
* @author apoorvn
|
* @author apoorvn
|
||||||
*/
|
*/
|
||||||
public class ChooseActivityTypeDialogFragment extends DialogFragment {
|
public class ChooseActivityTypeDialogFragment extends DialogFragment {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface for caller of this dialog fragment.
|
* Interface for caller of this dialog fragment.
|
||||||
*
|
*
|
||||||
* @author apoorvn
|
* @author apoorvn
|
||||||
*/
|
*/
|
||||||
public interface ChooseActivityTypeCaller {
|
public interface ChooseActivityTypeCaller {
|
||||||
@@ -51,12 +57,28 @@ public class ChooseActivityTypeDialogFragment extends DialogFragment {
|
|||||||
/**
|
/**
|
||||||
* Called when choose activity type is done.
|
* Called when choose activity type is done.
|
||||||
*/
|
*/
|
||||||
public void onChooseActivityTypeDone(String iconValue);
|
public void onChooseActivityTypeDone(String iconValue, boolean newWeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final String CHOOSE_ACTIVITY_TYPE_DIALOG_TAG = "chooseActivityType";
|
public static final String CHOOSE_ACTIVITY_TYPE_DIALOG_TAG = "chooseActivityType";
|
||||||
|
|
||||||
|
private static final String KEY_CATEGORY = "category";
|
||||||
|
|
||||||
private ChooseActivityTypeCaller caller;
|
private ChooseActivityTypeCaller caller;
|
||||||
|
private ChooseActivityTypeImageAdapter imageAdapter;
|
||||||
|
private AlertDialog alertDialog;
|
||||||
|
private View weightContainer;
|
||||||
|
private TextView weight;
|
||||||
|
private String weightValue;
|
||||||
|
|
||||||
|
public static ChooseActivityTypeDialogFragment newInstance(String category) {
|
||||||
|
Bundle bundle = new Bundle();
|
||||||
|
bundle.putString(KEY_CATEGORY, category);
|
||||||
|
|
||||||
|
ChooseActivityTypeDialogFragment fragment = new ChooseActivityTypeDialogFragment();
|
||||||
|
fragment.setArguments(bundle);
|
||||||
|
return fragment;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onAttach(Activity activity) {
|
public void onAttach(Activity activity) {
|
||||||
@@ -71,12 +93,31 @@ public class ChooseActivityTypeDialogFragment extends DialogFragment {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||||
GridView gridView =
|
View view = getActivity().getLayoutInflater().inflate(R.layout.choose_activity_type, null);
|
||||||
(GridView) getActivity().getLayoutInflater().inflate(R.layout.choose_activity_type, null);
|
GridView gridView = (GridView) view.findViewById(R.id.choose_activity_type_grid_view);
|
||||||
|
weightContainer = view.findViewById(R.id.choose_activity_type_weight_container);
|
||||||
final List<String> iconValues = TrackIconUtils.getAllIconValues();
|
|
||||||
|
TextView weightLabel = (TextView) view.findViewById(R.id.choose_activity_type_weight_label);
|
||||||
|
weightLabel.setText(
|
||||||
|
PreferencesUtils.isMetricUnits(getActivity()) ? R.string.description_weight_metric
|
||||||
|
: R.string.description_weight_imperial);
|
||||||
|
|
||||||
|
weight = (TextView) view.findViewById(R.id.choose_activity_type_weight);
|
||||||
|
ImageButton imageButton = (ImageButton) view.findViewById(
|
||||||
|
R.id.choose_activity_type_weight_image_button);
|
||||||
|
imageButton.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
double weightDefault = PreferencesUtils.WEIGHT_DEFAULT;
|
||||||
|
if (!PreferencesUtils.isMetricUnits(getActivity())) {
|
||||||
|
weightDefault *= UnitConversions.KG_TO_LB;
|
||||||
|
}
|
||||||
|
weight.setText(StringUtils.formatWeight(weightDefault));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
List<Integer> imageIds = new ArrayList<Integer>();
|
List<Integer> imageIds = new ArrayList<Integer>();
|
||||||
for (String iconValue : iconValues) {
|
for (String iconValue : TrackIconUtils.getAllIconValues()) {
|
||||||
imageIds.add(TrackIconUtils.getIconDrawable(iconValue));
|
imageIds.add(TrackIconUtils.getIconDrawable(iconValue));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,18 +129,77 @@ public class ChooseActivityTypeDialogFragment extends DialogFragment {
|
|||||||
int height = options.outHeight + 2 * padding;
|
int height = options.outHeight + 2 * padding;
|
||||||
gridView.setColumnWidth(width);
|
gridView.setColumnWidth(width);
|
||||||
|
|
||||||
ChooseActivityTypeImageAdapter imageAdapter =
|
imageAdapter = new ChooseActivityTypeImageAdapter(
|
||||||
new ChooseActivityTypeImageAdapter(getActivity(), imageIds, width, height, padding);
|
getActivity(), imageIds, width, height, padding);
|
||||||
gridView.setAdapter(imageAdapter);
|
gridView.setAdapter(imageAdapter);
|
||||||
gridView.setOnItemClickListener(new OnItemClickListener() {
|
gridView.setOnItemClickListener(new OnItemClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
|
public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
|
||||||
dismiss();
|
alertDialog.getButton(Dialog.BUTTON_POSITIVE).setEnabled(true);
|
||||||
caller.onChooseActivityTypeDone(iconValues.get(position));
|
imageAdapter.setSelected(position);
|
||||||
|
imageAdapter.notifyDataSetChanged();
|
||||||
|
updateWeightContainer(position);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return new AlertDialog.Builder(getActivity()).setNegativeButton(R.string.generic_cancel, null)
|
alertDialog = new AlertDialog.Builder(getActivity()).setNegativeButton(
|
||||||
.setTitle(R.string.track_edit_activity_type_hint).setView(gridView).create();
|
R.string.generic_cancel, null)
|
||||||
|
.setPositiveButton(R.string.generic_ok, new Dialog.OnClickListener() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
boolean newWeight = false;
|
||||||
|
if (weightContainer.getVisibility() == View.VISIBLE) {
|
||||||
|
String newValue = weight.getText().toString();
|
||||||
|
if (!newValue.equals(weightValue)) {
|
||||||
|
newWeight = true;
|
||||||
|
PreferencesUtils.storeWeightValue(getActivity(), newValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int selected = imageAdapter.getSelected();
|
||||||
|
caller.onChooseActivityTypeDone(
|
||||||
|
TrackIconUtils.getAllIconValues().get(selected), newWeight);
|
||||||
|
}
|
||||||
|
}).setTitle(R.string.track_edit_activity_type_hint).setView(view).create();
|
||||||
|
alertDialog.setOnShowListener(new DialogInterface.OnShowListener() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onShow(DialogInterface dialog) {
|
||||||
|
int position = getPosition();
|
||||||
|
alertDialog.getButton(Dialog.BUTTON_POSITIVE).setEnabled(position != -1);
|
||||||
|
if (position != -1) {
|
||||||
|
imageAdapter.setSelected(position);
|
||||||
|
imageAdapter.notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
updateWeightContainer(position);
|
||||||
|
double weightDisplayValue = PreferencesUtils.getWeightDisplayValue(getActivity());
|
||||||
|
weightValue = StringUtils.formatWeight(weightDisplayValue);
|
||||||
|
weight.setText(weightValue);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return alertDialog;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getPosition() {
|
||||||
|
String category = getArguments().getString(KEY_CATEGORY);
|
||||||
|
if (category == null) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
String iconValue = TrackIconUtils.getIconValue(getActivity(), category);
|
||||||
|
if (iconValue.equals("")) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
List<String> iconValues = TrackIconUtils.getAllIconValues();
|
||||||
|
for (int i = 0; i < iconValues.size(); i++) {
|
||||||
|
if (iconValues.get(i).equals(iconValue)) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateWeightContainer(int position) {
|
||||||
|
boolean showWeight = position == 0 || position == 1 || position == 2;
|
||||||
|
weightContainer.setVisibility(showWeight ? View.VISIBLE : View.GONE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+17
@@ -16,7 +16,10 @@
|
|||||||
|
|
||||||
package com.google.android.apps.mytracks.fragments;
|
package com.google.android.apps.mytracks.fragments;
|
||||||
|
|
||||||
|
import com.google.android.maps.mytracks.R;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.graphics.Color;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.BaseAdapter;
|
import android.widget.BaseAdapter;
|
||||||
@@ -36,6 +39,7 @@ public class ChooseActivityTypeImageAdapter extends BaseAdapter {
|
|||||||
private final int width;
|
private final int width;
|
||||||
private final int height;
|
private final int height;
|
||||||
private final int padding;
|
private final int padding;
|
||||||
|
private int selected = -1;
|
||||||
|
|
||||||
public ChooseActivityTypeImageAdapter(
|
public ChooseActivityTypeImageAdapter(
|
||||||
Context context, List<Integer> imageIds, int width, int height, int padding) {
|
Context context, List<Integer> imageIds, int width, int height, int padding) {
|
||||||
@@ -61,6 +65,14 @@ public class ChooseActivityTypeImageAdapter extends BaseAdapter {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getSelected() {
|
||||||
|
return selected;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSelected(int position) {
|
||||||
|
selected = position;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public View getView(int position, View convertView, ViewGroup parent) {
|
public View getView(int position, View convertView, ViewGroup parent) {
|
||||||
ImageView imageView;
|
ImageView imageView;
|
||||||
@@ -69,6 +81,11 @@ public class ChooseActivityTypeImageAdapter extends BaseAdapter {
|
|||||||
} else {
|
} else {
|
||||||
imageView = (ImageView) convertView;
|
imageView = (ImageView) convertView;
|
||||||
}
|
}
|
||||||
|
if (position == selected) {
|
||||||
|
imageView.setBackgroundResource(R.drawable.list_selector_background_transition_holo_dark);
|
||||||
|
} else {
|
||||||
|
imageView.setBackgroundColor(Color.TRANSPARENT);
|
||||||
|
}
|
||||||
imageView.setImageResource(imageIds.get(position));
|
imageView.setImageResource(imageIds.get(position));
|
||||||
imageView.setMinimumHeight(height);
|
imageView.setMinimumHeight(height);
|
||||||
imageView.setMinimumWidth(width);
|
imageView.setMinimumWidth(width);
|
||||||
|
|||||||
@@ -22,9 +22,10 @@ import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
|
|||||||
import com.google.android.apps.mytracks.content.Track;
|
import com.google.android.apps.mytracks.content.Track;
|
||||||
import com.google.android.apps.mytracks.content.Waypoint;
|
import com.google.android.apps.mytracks.content.Waypoint;
|
||||||
import com.google.android.apps.mytracks.content.Waypoint.WaypointType;
|
import com.google.android.apps.mytracks.content.Waypoint.WaypointType;
|
||||||
|
import com.google.android.apps.mytracks.util.CalorieUtils;
|
||||||
|
import com.google.android.apps.mytracks.util.CalorieUtils.ActivityType;
|
||||||
import com.google.android.apps.mytracks.util.IntentUtils;
|
import com.google.android.apps.mytracks.util.IntentUtils;
|
||||||
import com.google.android.apps.mytracks.util.PhotoUtils;
|
import com.google.android.apps.mytracks.util.PhotoUtils;
|
||||||
import com.google.android.apps.mytracks.util.PreferencesUtils;
|
|
||||||
import com.google.android.apps.mytracks.util.StatsUtils;
|
import com.google.android.apps.mytracks.util.StatsUtils;
|
||||||
import com.google.android.apps.mytracks.util.StringUtils;
|
import com.google.android.apps.mytracks.util.StringUtils;
|
||||||
import com.google.android.maps.mytracks.R;
|
import com.google.android.maps.mytracks.R;
|
||||||
@@ -128,6 +129,9 @@ public class MarkerDetailFragment extends Fragment {
|
|||||||
int visibility = waypointInfo.getVisibility() == View.GONE ? View.VISIBLE : View.GONE;
|
int visibility = waypointInfo.getVisibility() == View.GONE ? View.VISIBLE : View.GONE;
|
||||||
textGradient.setVisibility(visibility);
|
textGradient.setVisibility(visibility);
|
||||||
waypointInfo.setVisibility(visibility);
|
waypointInfo.setVisibility(visibility);
|
||||||
|
if (visibility == View.VISIBLE) {
|
||||||
|
handler.postDelayed(hideText, HIDE_TEXT_DELAY);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
textGradient = (ImageView) view.findViewById(R.id.marker_detail_waypoint_text_gradient);
|
textGradient = (ImageView) view.findViewById(R.id.marker_detail_waypoint_text_gradient);
|
||||||
@@ -277,8 +281,12 @@ public class MarkerDetailFragment extends Fragment {
|
|||||||
TextView name = (TextView) getView().findViewById(R.id.marker_detail_statistics_name);
|
TextView name = (TextView) getView().findViewById(R.id.marker_detail_statistics_name);
|
||||||
setTextView(name, waypoint.getName());
|
setTextView(name, waypoint.getName());
|
||||||
|
|
||||||
StatsUtils.setTripStatisticsValues(getActivity(), null, getView(),
|
Track track = myTracksProviderUtils.getTrack(waypoint.getTrackId());
|
||||||
waypoint.getTripStatistics(), PreferencesUtils.RECORDING_TRACK_ID_DEFAULT);
|
ActivityType activityType = track != null ? CalorieUtils.getActivityType(
|
||||||
|
getActivity(), track.getCategory())
|
||||||
|
: ActivityType.INVALID;
|
||||||
|
StatsUtils.setTripStatisticsValues(
|
||||||
|
getActivity(), null, getView(), waypoint.getTripStatistics(), activityType, null);
|
||||||
StatsUtils.setLocationValues(getActivity(), null, getView(), waypoint.getLocation(), false);
|
StatsUtils.setLocationValues(getActivity(), null, getView(), waypoint.getLocation(), false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,9 +23,13 @@ import com.google.android.apps.mytracks.content.TrackDataListener;
|
|||||||
import com.google.android.apps.mytracks.content.TrackDataType;
|
import com.google.android.apps.mytracks.content.TrackDataType;
|
||||||
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.stats.TripStatistics;
|
||||||
|
import com.google.android.apps.mytracks.util.CalorieUtils;
|
||||||
|
import com.google.android.apps.mytracks.util.CalorieUtils.ActivityType;
|
||||||
import com.google.android.apps.mytracks.util.LocationUtils;
|
import com.google.android.apps.mytracks.util.LocationUtils;
|
||||||
import com.google.android.apps.mytracks.util.PreferencesUtils;
|
import com.google.android.apps.mytracks.util.PreferencesUtils;
|
||||||
import com.google.android.apps.mytracks.util.StatsUtils;
|
import com.google.android.apps.mytracks.util.StatsUtils;
|
||||||
|
import com.google.android.apps.mytracks.util.TrackIconUtils;
|
||||||
|
import com.google.android.apps.mytracks.util.UnitConversions;
|
||||||
import com.google.android.maps.mytracks.R;
|
import com.google.android.maps.mytracks.R;
|
||||||
|
|
||||||
import android.location.Location;
|
import android.location.Location;
|
||||||
@@ -33,9 +37,12 @@ import android.os.Bundle;
|
|||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.support.v4.app.Fragment;
|
import android.support.v4.app.Fragment;
|
||||||
import android.support.v4.app.FragmentActivity;
|
import android.support.v4.app.FragmentActivity;
|
||||||
|
import android.view.KeyEvent;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.MotionEvent;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.Spinner;
|
||||||
|
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
|
|
||||||
@@ -49,13 +56,15 @@ public class StatsFragment extends Fragment implements TrackDataListener {
|
|||||||
|
|
||||||
public static final String STATS_FRAGMENT_TAG = "statsFragment";
|
public static final String STATS_FRAGMENT_TAG = "statsFragment";
|
||||||
|
|
||||||
private static final int ONE_SECOND = 1000;
|
// 1 second in milliseconds
|
||||||
|
private static final long ONE_SECOND = (long) UnitConversions.S_TO_MS;
|
||||||
|
|
||||||
private TrackDataHub trackDataHub;
|
private TrackDataHub trackDataHub;
|
||||||
private Handler handler;
|
private Handler handler;
|
||||||
|
|
||||||
private Location lastLocation = null;
|
private Location lastLocation = null;
|
||||||
private TripStatistics lastTripStatistics = null;
|
private TripStatistics lastTripStatistics = null;
|
||||||
|
private String category = "";
|
||||||
private int recordingGpsAccuracy = PreferencesUtils.RECORDING_GPS_ACCURACY_DEFAULT;
|
private int recordingGpsAccuracy = PreferencesUtils.RECORDING_GPS_ACCURACY_DEFAULT;
|
||||||
|
|
||||||
// A runnable to update the total time field.
|
// A runnable to update the total time field.
|
||||||
@@ -81,13 +90,34 @@ public class StatsFragment extends Fragment implements TrackDataListener {
|
|||||||
public void onActivityCreated(Bundle savedInstanceState) {
|
public void onActivityCreated(Bundle savedInstanceState) {
|
||||||
super.onActivityCreated(savedInstanceState);
|
super.onActivityCreated(savedInstanceState);
|
||||||
handler = new Handler();
|
handler = new Handler();
|
||||||
updateUi(getActivity());
|
|
||||||
|
Spinner activityTypeIcon = (Spinner) getView().findViewById(R.id.stats_activity_type_icon);
|
||||||
|
activityTypeIcon.setAdapter(TrackIconUtils.getIconSpinnerAdapter(getActivity(), ""));
|
||||||
|
activityTypeIcon.setOnTouchListener(new View.OnTouchListener() {
|
||||||
|
@Override
|
||||||
|
public boolean onTouch(View v, MotionEvent event) {
|
||||||
|
if (event.getAction() == MotionEvent.ACTION_UP) {
|
||||||
|
((TrackDetailActivity) getActivity()).chooseActivityType(category);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
activityTypeIcon.setOnKeyListener(new View.OnKeyListener() {
|
||||||
|
@Override
|
||||||
|
public boolean onKey(View v, int keyCode, KeyEvent event) {
|
||||||
|
if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
|
||||||
|
((TrackDetailActivity) getActivity()).chooseActivityType(category);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onResume() {
|
public void onResume() {
|
||||||
super.onResume();
|
super.onResume();
|
||||||
resumeTrackDataHub();
|
resumeTrackDataHub();
|
||||||
|
updateUi(getActivity());
|
||||||
if (isSelectedTrackRecording()) {
|
if (isSelectedTrackRecording()) {
|
||||||
handler.post(updateTotalTime);
|
handler.post(updateTotalTime);
|
||||||
}
|
}
|
||||||
@@ -106,8 +136,9 @@ public class StatsFragment extends Fragment implements TrackDataListener {
|
|||||||
getActivity().runOnUiThread(new Runnable() {
|
getActivity().runOnUiThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if (isResumed()) {
|
if (isResumed()) {
|
||||||
lastTripStatistics = track != null ? track.getTripStatistics() : null;
|
lastTripStatistics = track != null ? track.getTripStatistics() : null;
|
||||||
|
category = track != null ? track.getCategory() : "";
|
||||||
updateUi(getActivity());
|
updateUi(getActivity());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -260,9 +291,10 @@ public class StatsFragment extends Fragment implements TrackDataListener {
|
|||||||
* Updates the UI.
|
* Updates the UI.
|
||||||
*/
|
*/
|
||||||
private void updateUi(FragmentActivity activity) {
|
private void updateUi(FragmentActivity activity) {
|
||||||
StatsUtils.setTripStatisticsValues(activity, activity, null, lastTripStatistics,
|
ActivityType activityType = CalorieUtils.getActivityType(activity, category);
|
||||||
trackDataHub == null ? PreferencesUtils.RECORDING_TRACK_ID_DEFAULT
|
String trackIconValue = TrackIconUtils.getIconValue(activity, category);
|
||||||
: trackDataHub.getSelectedTrackId());
|
StatsUtils.setTripStatisticsValues(
|
||||||
|
activity, activity, null, lastTripStatistics, activityType, trackIconValue);
|
||||||
StatsUtils.setLocationValues(
|
StatsUtils.setLocationValues(
|
||||||
activity, activity, null, lastLocation, isSelectedTrackRecording());
|
activity, activity, null, lastLocation, isSelectedTrackRecording());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,6 +59,7 @@ public class PreferenceBackupHelper {
|
|||||||
doNotBackup.add(context.getString(R.string.google_account_key));
|
doNotBackup.add(context.getString(R.string.google_account_key));
|
||||||
doNotBackup.add(context.getString(R.string.recording_track_id_key));
|
doNotBackup.add(context.getString(R.string.recording_track_id_key));
|
||||||
doNotBackup.add(context.getString(R.string.recording_track_paused_key));
|
doNotBackup.add(context.getString(R.string.recording_track_paused_key));
|
||||||
|
doNotBackup.add(context.getString(R.string.weight_key));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+10
-6
@@ -134,16 +134,18 @@ public class FileTrackExporter implements TrackExporter {
|
|||||||
boolean wroteSegment = false;
|
boolean wroteSegment = false;
|
||||||
boolean isLastLocationValid = false;
|
boolean isLastLocationValid = false;
|
||||||
TrackWriterLocationFactory locationFactory = new TrackWriterLocationFactory();
|
TrackWriterLocationFactory locationFactory = new TrackWriterLocationFactory();
|
||||||
LocationIterator iterator = myTracksProviderUtils.getTrackPointLocationIterator(
|
int locationNumber = 0;
|
||||||
track.getId(), -1L, false, locationFactory);
|
LocationIterator locationIterator = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
int locationNumber = 0;
|
locationIterator = myTracksProviderUtils.getTrackPointLocationIterator(
|
||||||
while (iterator.hasNext()) {
|
track.getId(), -1L, false, locationFactory);
|
||||||
|
|
||||||
|
while (locationIterator.hasNext()) {
|
||||||
if (Thread.interrupted()) {
|
if (Thread.interrupted()) {
|
||||||
throw new InterruptedException();
|
throw new InterruptedException();
|
||||||
}
|
}
|
||||||
Location location = iterator.next();
|
Location location = locationIterator.next();
|
||||||
|
|
||||||
setLocationTime(location, offset);
|
setLocationTime(location, offset);
|
||||||
locationNumber++;
|
locationNumber++;
|
||||||
@@ -195,7 +197,9 @@ public class FileTrackExporter implements TrackExporter {
|
|||||||
trackWriter.writeEndTrack(track, null);
|
trackWriter.writeEndTrack(track, null);
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
iterator.close();
|
if (locationIterator != null) {
|
||||||
|
locationIterator.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import com.google.android.apps.mytracks.content.Waypoint;
|
|||||||
import com.google.android.apps.mytracks.io.file.TrackFileFormat;
|
import com.google.android.apps.mytracks.io.file.TrackFileFormat;
|
||||||
import com.google.android.apps.mytracks.util.StringUtils;
|
import com.google.android.apps.mytracks.util.StringUtils;
|
||||||
import com.google.android.apps.mytracks.util.SystemUtils;
|
import com.google.android.apps.mytracks.util.SystemUtils;
|
||||||
|
import com.google.android.apps.mytracks.util.UnitConversions;
|
||||||
import com.google.android.maps.mytracks.R;
|
import com.google.android.maps.mytracks.R;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
@@ -172,7 +173,8 @@ public class TcxTrackWriter implements TrackWriter {
|
|||||||
if (printWriter != null) {
|
if (printWriter != null) {
|
||||||
String startTime = StringUtils.formatDateTimeIso8601(
|
String startTime = StringUtils.formatDateTimeIso8601(
|
||||||
track.getTripStatistics().getStartTime());
|
track.getTripStatistics().getStartTime());
|
||||||
long totalTimeInSeconds = track.getTripStatistics().getTotalTime() / 1000;
|
long totalTimeInSeconds = (long) (track.getTripStatistics().getTotalTime()
|
||||||
|
* UnitConversions.MS_TO_S);
|
||||||
|
|
||||||
printWriter.println("<Activities>");
|
printWriter.println("<Activities>");
|
||||||
printWriter.println("<Activity Sport=\"" + sportType.getName() + "\">");
|
printWriter.println("<Activity Sport=\"" + sportType.getName() + "\">");
|
||||||
|
|||||||
+50
-44
@@ -18,27 +18,30 @@ package com.google.android.apps.mytracks.io.file.importer;
|
|||||||
|
|
||||||
import com.google.android.apps.mytracks.content.DescriptionGeneratorImpl;
|
import com.google.android.apps.mytracks.content.DescriptionGeneratorImpl;
|
||||||
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
|
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
|
||||||
|
import com.google.android.apps.mytracks.content.MyTracksProviderUtils.LocationIterator;
|
||||||
import com.google.android.apps.mytracks.content.Track;
|
import com.google.android.apps.mytracks.content.Track;
|
||||||
import com.google.android.apps.mytracks.content.Waypoint;
|
import com.google.android.apps.mytracks.content.Waypoint;
|
||||||
import com.google.android.apps.mytracks.content.Waypoint.WaypointType;
|
import com.google.android.apps.mytracks.content.Waypoint.WaypointType;
|
||||||
import com.google.android.apps.mytracks.services.TrackRecordingService;
|
import com.google.android.apps.mytracks.services.TrackRecordingService;
|
||||||
import com.google.android.apps.mytracks.stats.TripStatistics;
|
import com.google.android.apps.mytracks.stats.TripStatistics;
|
||||||
import com.google.android.apps.mytracks.stats.TripStatisticsUpdater;
|
import com.google.android.apps.mytracks.stats.TripStatisticsUpdater;
|
||||||
|
import com.google.android.apps.mytracks.util.CalorieUtils;
|
||||||
import com.google.android.apps.mytracks.util.CalorieUtils.ActivityType;
|
import com.google.android.apps.mytracks.util.CalorieUtils.ActivityType;
|
||||||
import com.google.android.apps.mytracks.util.FileUtils;
|
import com.google.android.apps.mytracks.util.FileUtils;
|
||||||
import com.google.android.apps.mytracks.util.LocationUtils;
|
import com.google.android.apps.mytracks.util.LocationUtils;
|
||||||
import com.google.android.apps.mytracks.util.PreferencesUtils;
|
import com.google.android.apps.mytracks.util.PreferencesUtils;
|
||||||
import com.google.android.apps.mytracks.util.StringUtils;
|
import com.google.android.apps.mytracks.util.StringUtils;
|
||||||
import com.google.android.apps.mytracks.util.TrackIconUtils;
|
import com.google.android.apps.mytracks.util.TrackIconUtils;
|
||||||
|
import com.google.android.apps.mytracks.util.UnitConversions;
|
||||||
import com.google.android.maps.mytracks.R;
|
import com.google.android.maps.mytracks.R;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.database.Cursor;
|
|
||||||
import android.location.Location;
|
import android.location.Location;
|
||||||
import android.location.LocationManager;
|
import android.location.LocationManager;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -105,6 +108,7 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track
|
|||||||
private final long importTrackId;
|
private final long importTrackId;
|
||||||
private final MyTracksProviderUtils myTracksProviderUtils;
|
private final MyTracksProviderUtils myTracksProviderUtils;
|
||||||
private final int recordingDistanceInterval;
|
private final int recordingDistanceInterval;
|
||||||
|
private final double weight;
|
||||||
private final List<Long> trackIds;
|
private final List<Long> trackIds;
|
||||||
private final List<Waypoint> waypoints;
|
private final List<Waypoint> waypoints;
|
||||||
|
|
||||||
@@ -142,6 +146,8 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track
|
|||||||
this.recordingDistanceInterval = PreferencesUtils.getInt(context,
|
this.recordingDistanceInterval = PreferencesUtils.getInt(context,
|
||||||
R.string.recording_distance_interval_key,
|
R.string.recording_distance_interval_key,
|
||||||
PreferencesUtils.RECORDING_DISTANCE_INTERVAL_DEFAULT);
|
PreferencesUtils.RECORDING_DISTANCE_INTERVAL_DEFAULT);
|
||||||
|
this.weight = PreferencesUtils.getFloat(
|
||||||
|
context, R.string.weight_key, PreferencesUtils.WEIGHT_DEFAULT);
|
||||||
trackIds = new ArrayList<Long>();
|
trackIds = new ArrayList<Long>();
|
||||||
waypoints = new ArrayList<Waypoint>();
|
waypoints = new ArrayList<Waypoint>();
|
||||||
}
|
}
|
||||||
@@ -209,20 +215,20 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track
|
|||||||
if (track == null) {
|
if (track == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Cursor trackPointCursor = null;
|
|
||||||
|
int waypointPosition = -1;
|
||||||
|
Waypoint waypoint = null;
|
||||||
|
Location location = null;
|
||||||
|
TripStatisticsUpdater trackTripStatisticstrackUpdater = new TripStatisticsUpdater(
|
||||||
|
track.getTripStatistics().getStartTime());
|
||||||
|
TripStatisticsUpdater markerTripStatisticsUpdater = new TripStatisticsUpdater(
|
||||||
|
track.getTripStatistics().getStartTime());
|
||||||
|
LocationIterator locationIterator = null;
|
||||||
|
ActivityType activityType = CalorieUtils.getActivityType(context, track.getCategory());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
trackPointCursor = myTracksProviderUtils.getTrackPointCursor(track.getId(), -1L, -1, false);
|
locationIterator = myTracksProviderUtils.getTrackPointLocationIterator(
|
||||||
if (trackPointCursor == null) {
|
track.getId(), -1L, false, MyTracksProviderUtils.DEFAULT_LOCATION_FACTORY);
|
||||||
return;
|
|
||||||
}
|
|
||||||
int waypointPosition = -1;
|
|
||||||
Waypoint waypoint = null;
|
|
||||||
int trackPointPosition = -1;
|
|
||||||
Location trackPoint = null;
|
|
||||||
TripStatisticsUpdater trackTripStatisticstrackUpdater = new TripStatisticsUpdater(
|
|
||||||
track.getTripStatistics().getStartTime());
|
|
||||||
TripStatisticsUpdater markerTripStatisticsUpdater = new TripStatisticsUpdater(
|
|
||||||
track.getTripStatistics().getStartTime());
|
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
if (waypoint == null) {
|
if (waypoint == null) {
|
||||||
@@ -233,28 +239,25 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (trackPoint == null) {
|
if (location == null) {
|
||||||
trackPointPosition++;
|
if (!locationIterator.hasNext()) {
|
||||||
trackPoint = trackPointCursor.moveToPosition(trackPointPosition) ? myTracksProviderUtils
|
|
||||||
.createTrackPoint(trackPointCursor)
|
|
||||||
: null;
|
|
||||||
if (trackPoint == null) {
|
|
||||||
// No more track points. Ignore the rest of the waypoints.
|
// No more track points. Ignore the rest of the waypoints.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
trackTripStatisticstrackUpdater.addLocation(trackPoint, recordingDistanceInterval, false,
|
location = locationIterator.next();
|
||||||
ActivityType.INVALID, PreferencesUtils.STATS_WEIGHT_DEFAULT);
|
trackTripStatisticstrackUpdater.addLocation(location, recordingDistanceInterval, false,
|
||||||
markerTripStatisticsUpdater.addLocation(trackPoint, recordingDistanceInterval, false,
|
ActivityType.INVALID, PreferencesUtils.WEIGHT_DEFAULT);
|
||||||
ActivityType.INVALID, PreferencesUtils.STATS_WEIGHT_DEFAULT);
|
markerTripStatisticsUpdater.addLocation(
|
||||||
|
location, recordingDistanceInterval, true, activityType, weight);
|
||||||
}
|
}
|
||||||
if (waypoint.getLocation().getTime() > trackPoint.getTime()) {
|
if (waypoint.getLocation().getTime() > location.getTime()) {
|
||||||
trackPoint = null;
|
location = null;
|
||||||
} else if (waypoint.getLocation().getTime() < trackPoint.getTime()) {
|
} else if (waypoint.getLocation().getTime() < location.getTime()) {
|
||||||
waypoint = null;
|
waypoint = null;
|
||||||
} else {
|
} else {
|
||||||
// The waypoint location time matches the track point time
|
// The waypoint location time matches the track point time
|
||||||
if (trackPoint.getLatitude() == waypoint.getLocation().getLatitude()
|
if (location.getLatitude() == waypoint.getLocation().getLatitude()
|
||||||
&& trackPoint.getLongitude() == waypoint.getLocation().getLongitude()) {
|
&& location.getLongitude() == waypoint.getLocation().getLongitude()) {
|
||||||
|
|
||||||
// Get tripStatistics, description, and icon
|
// Get tripStatistics, description, and icon
|
||||||
TripStatistics tripStatistics;
|
TripStatistics tripStatistics;
|
||||||
@@ -262,7 +265,7 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track
|
|||||||
String icon;
|
String icon;
|
||||||
if (waypoint.getType() == WaypointType.STATISTICS) {
|
if (waypoint.getType() == WaypointType.STATISTICS) {
|
||||||
tripStatistics = markerTripStatisticsUpdater.getTripStatistics();
|
tripStatistics = markerTripStatisticsUpdater.getTripStatistics();
|
||||||
markerTripStatisticsUpdater = new TripStatisticsUpdater(trackPoint.getTime());
|
markerTripStatisticsUpdater = new TripStatisticsUpdater(location.getTime());
|
||||||
waypointDescription = new DescriptionGeneratorImpl(context)
|
waypointDescription = new DescriptionGeneratorImpl(context)
|
||||||
.generateWaypointDescription(tripStatistics);
|
.generateWaypointDescription(tripStatistics);
|
||||||
icon = context.getString(R.string.marker_statistics_icon_url);
|
icon = context.getString(R.string.marker_statistics_icon_url);
|
||||||
@@ -279,15 +282,15 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track
|
|||||||
// Insert waypoint
|
// Insert waypoint
|
||||||
Waypoint newWaypoint = new Waypoint(waypoint.getName(), waypointDescription,
|
Waypoint newWaypoint = new Waypoint(waypoint.getName(), waypointDescription,
|
||||||
waypoint.getCategory(), icon, track.getId(), waypoint.getType(), length, duration,
|
waypoint.getCategory(), icon, track.getId(), waypoint.getType(), length, duration,
|
||||||
-1L, -1L, trackPoint, tripStatistics, waypoint.getPhotoUrl());
|
-1L, -1L, location, tripStatistics, waypoint.getPhotoUrl());
|
||||||
myTracksProviderUtils.insertWaypoint(newWaypoint);
|
myTracksProviderUtils.insertWaypoint(newWaypoint);
|
||||||
}
|
}
|
||||||
waypoint = null;
|
waypoint = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
if (trackPointCursor != null) {
|
if (locationIterator != null) {
|
||||||
trackPointCursor.close();
|
locationIterator.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -412,10 +415,10 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track
|
|||||||
* last two points. GPS points tend to have some inherent imprecision,
|
* last two points. GPS points tend to have some inherent imprecision,
|
||||||
* speed and bearing will likely be off, so the statistics for things
|
* speed and bearing will likely be off, so the statistics for things
|
||||||
* like max speed will also be off.
|
* like max speed will also be off.
|
||||||
*/
|
*/
|
||||||
float speed = trackData.lastLocationInCurrentSegment.distanceTo(location) * 1000.0f
|
double duration = timeDifference * UnitConversions.MS_TO_S;
|
||||||
/ timeDifference;
|
double speed = trackData.lastLocationInCurrentSegment.distanceTo(location) / duration;
|
||||||
location.setSpeed(speed);
|
location.setSpeed((float) speed);
|
||||||
}
|
}
|
||||||
location.setBearing(trackData.lastLocationInCurrentSegment.bearingTo(location));
|
location.setBearing(trackData.lastLocationInCurrentSegment.bearingTo(location));
|
||||||
}
|
}
|
||||||
@@ -469,8 +472,9 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track
|
|||||||
if (importTrackId == -1L) {
|
if (importTrackId == -1L) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return FileUtils.getPath(
|
String path = FileUtils.getPath(
|
||||||
FileUtils.PICTURES_DIR, Long.toString(importTrackId), fileName);
|
FileUtils.PICTURES_DIR, Long.toString(importTrackId), fileName);
|
||||||
|
return Uri.fromFile(new File(path)).toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -486,8 +490,8 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track
|
|||||||
latitudeValue = Double.parseDouble(latitude);
|
latitudeValue = Double.parseDouble(latitude);
|
||||||
longitudeValue = Double.parseDouble(longitude);
|
longitudeValue = Double.parseDouble(longitude);
|
||||||
} catch (NumberFormatException e) {
|
} catch (NumberFormatException e) {
|
||||||
throw new SAXException(createErrorMessage(
|
throw new SAXException(createErrorMessage(String.format(
|
||||||
String.format("Unable to parse latitude longitude: %s %s", latitude, longitude)), e);
|
Locale.US, "Unable to parse latitude longitude: %s %s", latitude, longitude)), e);
|
||||||
}
|
}
|
||||||
Double altitudeValue = null;
|
Double altitudeValue = null;
|
||||||
if (altitude != null) {
|
if (altitude != null) {
|
||||||
@@ -495,7 +499,8 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track
|
|||||||
altitudeValue = Double.parseDouble(altitude);
|
altitudeValue = Double.parseDouble(altitude);
|
||||||
} catch (NumberFormatException e) {
|
} catch (NumberFormatException e) {
|
||||||
throw new SAXException(
|
throw new SAXException(
|
||||||
createErrorMessage(String.format("Unable to parse altitude: %s", altitude)), e);
|
createErrorMessage(String.format(Locale.US, "Unable to parse altitude: %s", altitude)),
|
||||||
|
e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -507,7 +512,7 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track
|
|||||||
timeValue = StringUtils.getTime(time);
|
timeValue = StringUtils.getTime(time);
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
throw new SAXException(
|
throw new SAXException(
|
||||||
createErrorMessage(String.format("Unable to parse time: %s", time)), e);
|
createErrorMessage(String.format(Locale.US, "Unable to parse time: %s", time)), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return createLocation(latitudeValue, longitudeValue, altitudeValue, timeValue);
|
return createLocation(latitudeValue, longitudeValue, altitudeValue, timeValue);
|
||||||
@@ -548,8 +553,9 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track
|
|||||||
trackData.tripStatisticsUpdater = new TripStatisticsUpdater(
|
trackData.tripStatisticsUpdater = new TripStatisticsUpdater(
|
||||||
location.getTime() != -1L ? location.getTime() : trackData.importTime);
|
location.getTime() != -1L ? location.getTime() : trackData.importTime);
|
||||||
}
|
}
|
||||||
trackData.tripStatisticsUpdater.addLocation(location, recordingDistanceInterval, false,
|
ActivityType activityType = CalorieUtils.getActivityType(context, category);
|
||||||
ActivityType.INVALID, PreferencesUtils.STATS_WEIGHT_DEFAULT);
|
trackData.tripStatisticsUpdater.addLocation(
|
||||||
|
location, recordingDistanceInterval, true, activityType, weight);
|
||||||
|
|
||||||
trackData.bufferedLocations[trackData.numBufferedLocations] = location;
|
trackData.bufferedLocations[trackData.numBufferedLocations] = location;
|
||||||
trackData.numBufferedLocations++;
|
trackData.numBufferedLocations++;
|
||||||
|
|||||||
+1
@@ -156,6 +156,7 @@ public class GpxFileTrackImporter extends AbstractFileTrackImporter {
|
|||||||
name = null;
|
name = null;
|
||||||
description = null;
|
description = null;
|
||||||
category = null;
|
category = null;
|
||||||
|
photoUrl = null;
|
||||||
latitude = attributes.getValue(ATTRIBUTE_LAT);
|
latitude = attributes.getValue(ATTRIBUTE_LAT);
|
||||||
longitude = attributes.getValue(ATTRIBUTE_LON);
|
longitude = attributes.getValue(ATTRIBUTE_LON);
|
||||||
altitude = null;
|
altitude = null;
|
||||||
|
|||||||
+10
-1
@@ -91,6 +91,11 @@ public class KmlFileTrackImporter extends AbstractFileTrackImporter {
|
|||||||
public void startElement(String uri, String localName, String tag, Attributes attributes)
|
public void startElement(String uri, String localName, String tag, Attributes attributes)
|
||||||
throws SAXException {
|
throws SAXException {
|
||||||
if (tag.equals(TAG_PLACEMARK) || tag.equals(TAG_PHOTO_OVERLAY)) {
|
if (tag.equals(TAG_PLACEMARK) || tag.equals(TAG_PHOTO_OVERLAY)) {
|
||||||
|
/*
|
||||||
|
* Note that a track is contained in a Placemark, calling onWaypointStart
|
||||||
|
* will clear various track variables like name, category, and
|
||||||
|
* description.
|
||||||
|
*/
|
||||||
onWaypointStart();
|
onWaypointStart();
|
||||||
} else if (tag.equals(TAG_GX_MULTI_TRACK)) {
|
} else if (tag.equals(TAG_GX_MULTI_TRACK)) {
|
||||||
trackStarted = true;
|
trackStarted = true;
|
||||||
@@ -110,6 +115,10 @@ public class KmlFileTrackImporter extends AbstractFileTrackImporter {
|
|||||||
if (tag.equals(TAG_KML)) {
|
if (tag.equals(TAG_KML)) {
|
||||||
onFileEnd();
|
onFileEnd();
|
||||||
} else if (tag.equals(TAG_PLACEMARK) || tag.equals(TAG_PHOTO_OVERLAY)) {
|
} else if (tag.equals(TAG_PLACEMARK) || tag.equals(TAG_PHOTO_OVERLAY)) {
|
||||||
|
/*
|
||||||
|
* Note that a track is contained in a Placemark, calling onWaypointend is
|
||||||
|
* save since waypointType is not set for a track.
|
||||||
|
*/
|
||||||
onWaypointEnd();
|
onWaypointEnd();
|
||||||
} else if (localName.equals(TAG_COORDINATES)) {
|
} else if (localName.equals(TAG_COORDINATES)) {
|
||||||
onWaypointLocationEnd();
|
onWaypointLocationEnd();
|
||||||
@@ -159,12 +168,12 @@ public class KmlFileTrackImporter extends AbstractFileTrackImporter {
|
|||||||
name = null;
|
name = null;
|
||||||
description = null;
|
description = null;
|
||||||
category = null;
|
category = null;
|
||||||
|
photoUrl = null;
|
||||||
latitude = null;
|
latitude = null;
|
||||||
longitude = null;
|
longitude = null;
|
||||||
altitude = null;
|
altitude = null;
|
||||||
time = null;
|
time = null;
|
||||||
waypointType = null;
|
waypointType = null;
|
||||||
photoUrl = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+16
-19
@@ -6,6 +6,7 @@ import com.google.android.apps.mytracks.Constants;
|
|||||||
import com.google.android.apps.mytracks.content.DescriptionGenerator;
|
import com.google.android.apps.mytracks.content.DescriptionGenerator;
|
||||||
import com.google.android.apps.mytracks.content.DescriptionGeneratorImpl;
|
import com.google.android.apps.mytracks.content.DescriptionGeneratorImpl;
|
||||||
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
|
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
|
||||||
|
import com.google.android.apps.mytracks.content.MyTracksProviderUtils.LocationIterator;
|
||||||
import com.google.android.apps.mytracks.content.Track;
|
import com.google.android.apps.mytracks.content.Track;
|
||||||
import com.google.android.apps.mytracks.content.Waypoint;
|
import com.google.android.apps.mytracks.content.Waypoint;
|
||||||
import com.google.android.apps.mytracks.content.Waypoint.WaypointType;
|
import com.google.android.apps.mytracks.content.Waypoint.WaypointType;
|
||||||
@@ -227,23 +228,19 @@ public class SendFusionTablesAsyncTask extends AbstractSendAsyncTask {
|
|||||||
*/
|
*/
|
||||||
private boolean uploadAllTrackPoints(Fusiontables fusiontables, String tableId, Track track)
|
private boolean uploadAllTrackPoints(Fusiontables fusiontables, String tableId, Track track)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
Cursor cursor = null;
|
int numberOfPoints = track.getNumberOfPoints();
|
||||||
|
List<Location> locations = new ArrayList<Location>(MAX_POINTS_PER_UPLOAD);
|
||||||
|
Location lastValidLocation = null;
|
||||||
|
boolean sentStartMarker = false;
|
||||||
|
int readCount = 0;
|
||||||
|
|
||||||
|
LocationIterator locationIterator = null;
|
||||||
try {
|
try {
|
||||||
cursor = myTracksProviderUtils.getTrackPointCursor(trackId, -1L, -1, false);
|
locationIterator = myTracksProviderUtils.getTrackPointLocationIterator(
|
||||||
if (cursor == null) {
|
trackId, -1L, false, MyTracksProviderUtils.DEFAULT_LOCATION_FACTORY);
|
||||||
Log.d(TAG, "Location cursor is null");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int count = cursor.getCount();
|
while (locationIterator.hasNext()) {
|
||||||
List<Location> locations = new ArrayList<Location>(MAX_POINTS_PER_UPLOAD);
|
Location location = locationIterator.next();
|
||||||
Location lastValidLocation = null;
|
|
||||||
boolean sentStartMarker = false;
|
|
||||||
|
|
||||||
for (int i = 0; i < count; i++) {
|
|
||||||
cursor.moveToPosition(i);
|
|
||||||
|
|
||||||
Location location = myTracksProviderUtils.createTrackPoint(cursor);
|
|
||||||
locations.add(location);
|
locations.add(location);
|
||||||
|
|
||||||
if (LocationUtils.isValidLocation(location)) {
|
if (LocationUtils.isValidLocation(location)) {
|
||||||
@@ -258,13 +255,13 @@ public class SendFusionTablesAsyncTask extends AbstractSendAsyncTask {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Upload periodically
|
// Upload periodically
|
||||||
int readCount = i + 1;
|
readCount++;
|
||||||
if (readCount % MAX_POINTS_PER_UPLOAD == 0) {
|
if (readCount % MAX_POINTS_PER_UPLOAD == 0) {
|
||||||
if (!prepareAndUploadPoints(fusiontables, tableId, track, locations, false)) {
|
if (!prepareAndUploadPoints(fusiontables, tableId, track, locations, false)) {
|
||||||
Log.d(TAG, "Unable to upload points");
|
Log.d(TAG, "Unable to upload points");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
updateProgress(readCount, count);
|
updateProgress(readCount, numberOfPoints);
|
||||||
locations.clear();
|
locations.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -285,8 +282,8 @@ public class SendFusionTablesAsyncTask extends AbstractSendAsyncTask {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
} finally {
|
} finally {
|
||||||
if (cursor != null) {
|
if (locationIterator != null) {
|
||||||
cursor.close();
|
locationIterator.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import com.google.android.apps.mytracks.Constants;
|
|||||||
import com.google.android.apps.mytracks.content.DescriptionGenerator;
|
import com.google.android.apps.mytracks.content.DescriptionGenerator;
|
||||||
import com.google.android.apps.mytracks.content.DescriptionGeneratorImpl;
|
import com.google.android.apps.mytracks.content.DescriptionGeneratorImpl;
|
||||||
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
|
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
|
||||||
|
import com.google.android.apps.mytracks.content.MyTracksProviderUtils.LocationIterator;
|
||||||
import com.google.android.apps.mytracks.content.Track;
|
import com.google.android.apps.mytracks.content.Track;
|
||||||
import com.google.android.apps.mytracks.content.Waypoint;
|
import com.google.android.apps.mytracks.content.Waypoint;
|
||||||
import com.google.android.apps.mytracks.io.gdata.GDataClientFactory;
|
import com.google.android.apps.mytracks.io.gdata.GDataClientFactory;
|
||||||
@@ -235,33 +236,29 @@ public class SendMapsAsyncTask extends AbstractSendAsyncTask {
|
|||||||
*/
|
*/
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
boolean uploadAllTrackPoints(Track track) {
|
boolean uploadAllTrackPoints(Track track) {
|
||||||
Cursor cursor = null;
|
int numberOfPoints = track.getNumberOfPoints();
|
||||||
|
List<Location> locations = new ArrayList<Location>(MAX_POINTS_PER_UPLOAD);
|
||||||
|
Location lastValidLocation = null;
|
||||||
|
boolean sentStartMarker = false;
|
||||||
|
|
||||||
|
// For chart server, limit the number of elevation readings to 250.
|
||||||
|
int elevationSamplingFrequency = Math.max(1, (int) (numberOfPoints / 250.0));
|
||||||
|
Vector<Double> distances = new Vector<Double>();
|
||||||
|
Vector<Double> elevations = new Vector<Double>();
|
||||||
|
TripStatisticsUpdater tripStatisticsUpdater = new TripStatisticsUpdater(
|
||||||
|
track.getTripStatistics().getStartTime());
|
||||||
|
int recordingDistanceInterval = PreferencesUtils.getInt(context,
|
||||||
|
R.string.recording_distance_interval_key,
|
||||||
|
PreferencesUtils.RECORDING_DISTANCE_INTERVAL_DEFAULT);
|
||||||
|
int readCount = 0;
|
||||||
|
LocationIterator locationIterator = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
cursor = myTracksProviderUtils.getTrackPointCursor(trackId, -1L, -1, false);
|
locationIterator = myTracksProviderUtils.getTrackPointLocationIterator(
|
||||||
if (cursor == null) {
|
trackId, -1L, false, MyTracksProviderUtils.DEFAULT_LOCATION_FACTORY);
|
||||||
Log.d(TAG, "Location cursor is null");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int count = cursor.getCount();
|
while (locationIterator.hasNext()) {
|
||||||
List<Location> locations = new ArrayList<Location>(MAX_POINTS_PER_UPLOAD);
|
Location location = locationIterator.next();
|
||||||
Location lastValidLocation = null;
|
|
||||||
boolean sentStartMarker = false;
|
|
||||||
|
|
||||||
// For chart server, limit the number of elevation readings to 250.
|
|
||||||
int elevationSamplingFrequency = Math.max(1, (int) (count / 250.0));
|
|
||||||
Vector<Double> distances = new Vector<Double>();
|
|
||||||
Vector<Double> elevations = new Vector<Double>();
|
|
||||||
TripStatisticsUpdater tripStatisticsUpdater = new TripStatisticsUpdater(
|
|
||||||
track.getTripStatistics().getStartTime());
|
|
||||||
int recordingDistanceInterval = PreferencesUtils.getInt(context,
|
|
||||||
R.string.recording_distance_interval_key,
|
|
||||||
PreferencesUtils.RECORDING_DISTANCE_INTERVAL_DEFAULT);
|
|
||||||
|
|
||||||
for (int i = 0; i < count; i++) {
|
|
||||||
cursor.moveToPosition(i);
|
|
||||||
|
|
||||||
Location location = myTracksProviderUtils.createTrackPoint(cursor);
|
|
||||||
locations.add(location);
|
locations.add(location);
|
||||||
|
|
||||||
if (LocationUtils.isValidLocation(location)) {
|
if (LocationUtils.isValidLocation(location)) {
|
||||||
@@ -279,20 +276,20 @@ public class SendMapsAsyncTask extends AbstractSendAsyncTask {
|
|||||||
}
|
}
|
||||||
|
|
||||||
tripStatisticsUpdater.addLocation(location, recordingDistanceInterval, false,
|
tripStatisticsUpdater.addLocation(location, recordingDistanceInterval, false,
|
||||||
ActivityType.INVALID, PreferencesUtils.STATS_WEIGHT_DEFAULT);
|
ActivityType.INVALID, PreferencesUtils.WEIGHT_DEFAULT);
|
||||||
if (i % elevationSamplingFrequency == 0) {
|
if (readCount % elevationSamplingFrequency == 0) {
|
||||||
distances.add(tripStatisticsUpdater.getTripStatistics().getTotalDistance());
|
distances.add(tripStatisticsUpdater.getTripStatistics().getTotalDistance());
|
||||||
elevations.add(tripStatisticsUpdater.getSmoothedElevation());
|
elevations.add(tripStatisticsUpdater.getSmoothedElevation());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Upload periodically
|
// Upload periodically
|
||||||
int readCount = i + 1;
|
readCount++;
|
||||||
if (readCount % MAX_POINTS_PER_UPLOAD == 0) {
|
if (readCount % MAX_POINTS_PER_UPLOAD == 0) {
|
||||||
if (!prepareAndUploadPoints(track, locations, false)) {
|
if (!prepareAndUploadPoints(track, locations, false)) {
|
||||||
Log.d(TAG, "Unable to upload points");
|
Log.d(TAG, "Unable to upload points");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
updateProgress(readCount, count);
|
updateProgress(readCount, numberOfPoints);
|
||||||
locations.clear();
|
locations.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -318,8 +315,8 @@ public class SendMapsAsyncTask extends AbstractSendAsyncTask {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
} finally {
|
} finally {
|
||||||
if (cursor != null) {
|
if (locationIterator != null) {
|
||||||
cursor.close();
|
locationIterator.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import com.google.android.apps.mytracks.content.DescriptionGeneratorImpl;
|
|||||||
import com.google.android.apps.mytracks.content.MyTracksLocation;
|
import com.google.android.apps.mytracks.content.MyTracksLocation;
|
||||||
import com.google.android.apps.mytracks.content.MyTracksProvider;
|
import com.google.android.apps.mytracks.content.MyTracksProvider;
|
||||||
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
|
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
|
||||||
|
import com.google.android.apps.mytracks.content.MyTracksProviderUtils.LocationIterator;
|
||||||
import com.google.android.apps.mytracks.content.Sensor;
|
import com.google.android.apps.mytracks.content.Sensor;
|
||||||
import com.google.android.apps.mytracks.content.Sensor.SensorDataSet;
|
import com.google.android.apps.mytracks.content.Sensor.SensorDataSet;
|
||||||
import com.google.android.apps.mytracks.content.Track;
|
import com.google.android.apps.mytracks.content.Track;
|
||||||
@@ -44,6 +45,7 @@ import com.google.android.apps.mytracks.util.PreferencesUtils;
|
|||||||
import com.google.android.apps.mytracks.util.SystemUtils;
|
import com.google.android.apps.mytracks.util.SystemUtils;
|
||||||
import com.google.android.apps.mytracks.util.TrackIconUtils;
|
import com.google.android.apps.mytracks.util.TrackIconUtils;
|
||||||
import com.google.android.apps.mytracks.util.TrackNameUtils;
|
import com.google.android.apps.mytracks.util.TrackNameUtils;
|
||||||
|
import com.google.android.apps.mytracks.util.UnitConversions;
|
||||||
import com.google.android.gms.common.ConnectionResult;
|
import com.google.android.gms.common.ConnectionResult;
|
||||||
import com.google.android.gms.common.GooglePlayServicesClient.ConnectionCallbacks;
|
import com.google.android.gms.common.GooglePlayServicesClient.ConnectionCallbacks;
|
||||||
import com.google.android.gms.common.GooglePlayServicesClient.OnConnectionFailedListener;
|
import com.google.android.gms.common.GooglePlayServicesClient.OnConnectionFailedListener;
|
||||||
@@ -59,7 +61,6 @@ 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.content.SharedPreferences.OnSharedPreferenceChangeListener;
|
||||||
import android.database.Cursor;
|
|
||||||
import android.database.sqlite.SQLiteException;
|
import android.database.sqlite.SQLiteException;
|
||||||
import android.location.Location;
|
import android.location.Location;
|
||||||
import android.location.LocationManager;
|
import android.location.LocationManager;
|
||||||
@@ -101,9 +102,14 @@ public class TrackRecordingService extends Service {
|
|||||||
public static final double MAX_NO_MOVEMENT_SPEED = 0.224;
|
public static final double MAX_NO_MOVEMENT_SPEED = 0.224;
|
||||||
|
|
||||||
private static final String TAG = TrackRecordingService.class.getSimpleName();
|
private static final String TAG = TrackRecordingService.class.getSimpleName();
|
||||||
private static final long ONE_SECOND = 1000; // in milliseconds
|
|
||||||
private static final long ONE_MINUTE = 60 * ONE_SECOND; // in milliseconds
|
|
||||||
|
|
||||||
|
// 1 second in milliseconds
|
||||||
|
private static final long ONE_SECOND = (long) UnitConversions.S_TO_MS;
|
||||||
|
|
||||||
|
// 1 minute in milliseconds
|
||||||
|
private static final long ONE_MINUTE = (long) (UnitConversions.MIN_TO_S
|
||||||
|
* UnitConversions.S_TO_MS);
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
static final int MAX_AUTO_RESUME_TRACK_RETRY_ATTEMPTS = 3;
|
static final int MAX_AUTO_RESUME_TRACK_RETRY_ATTEMPTS = 3;
|
||||||
|
|
||||||
@@ -126,7 +132,8 @@ public class TrackRecordingService extends Service {
|
|||||||
private int recordingGpsAccuracy;
|
private int recordingGpsAccuracy;
|
||||||
private int autoResumeTrackTimeout;
|
private int autoResumeTrackTimeout;
|
||||||
private long currentRecordingInterval;
|
private long currentRecordingInterval;
|
||||||
|
private double weight;
|
||||||
|
|
||||||
// The following variables are set when recording:
|
// The following variables are set when recording:
|
||||||
private TripStatisticsUpdater trackTripStatisticsUpdater;
|
private TripStatisticsUpdater trackTripStatisticsUpdater;
|
||||||
private TripStatisticsUpdater markerTripStatisticsUpdater;
|
private TripStatisticsUpdater markerTripStatisticsUpdater;
|
||||||
@@ -224,6 +231,10 @@ public class TrackRecordingService extends Service {
|
|||||||
R.string.auto_resume_track_timeout_key,
|
R.string.auto_resume_track_timeout_key,
|
||||||
PreferencesUtils.AUTO_RESUME_TRACK_TIMEOUT_DEFAULT);
|
PreferencesUtils.AUTO_RESUME_TRACK_TIMEOUT_DEFAULT);
|
||||||
}
|
}
|
||||||
|
if (key == null || key.equals(PreferencesUtils.getKey(context, R.string.weight_key))) {
|
||||||
|
weight = PreferencesUtils.getFloat(
|
||||||
|
context, R.string.weight_key, PreferencesUtils.WEIGHT_DEFAULT);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -650,31 +661,27 @@ public class TrackRecordingService extends Service {
|
|||||||
}
|
}
|
||||||
markerTripStatisticsUpdater = new TripStatisticsUpdater(markerStartTime);
|
markerTripStatisticsUpdater = new TripStatisticsUpdater(markerStartTime);
|
||||||
|
|
||||||
Cursor cursor = null;
|
ActivityType activityType = CalorieUtils.getActivityType(context, track.getCategory());
|
||||||
|
|
||||||
|
LocationIterator locationIterator = null;
|
||||||
try {
|
try {
|
||||||
// TODO: how to handle very long track.
|
locationIterator = myTracksProviderUtils.getTrackPointLocationIterator(
|
||||||
cursor = myTracksProviderUtils.getTrackPointCursor(
|
track.getId(), -1L, false, MyTracksProviderUtils.DEFAULT_LOCATION_FACTORY);
|
||||||
recordingTrackId, -1L, Constants.MAX_LOADED_TRACK_POINTS, true);
|
|
||||||
if (cursor == null) {
|
while (locationIterator.hasNext()) {
|
||||||
Log.e(TAG, "Cursor is null.");
|
Location location = locationIterator.next();
|
||||||
} else {
|
trackTripStatisticsUpdater.addLocation(
|
||||||
if (cursor.moveToLast()) {
|
location, recordingDistanceInterval, true, activityType, weight);
|
||||||
do {
|
if (location.getTime() > markerStartTime) {
|
||||||
Location location = myTracksProviderUtils.createTrackPoint(cursor);
|
markerTripStatisticsUpdater.addLocation(
|
||||||
trackTripStatisticsUpdater.addLocation(location, recordingDistanceInterval, false,
|
location, recordingDistanceInterval, true, activityType, weight);
|
||||||
ActivityType.INVALID, PreferencesUtils.STATS_WEIGHT_DEFAULT);
|
|
||||||
if (location.getTime() > markerStartTime) {
|
|
||||||
markerTripStatisticsUpdater.addLocation(location, recordingDistanceInterval, false,
|
|
||||||
ActivityType.INVALID, PreferencesUtils.STATS_WEIGHT_DEFAULT);
|
|
||||||
}
|
|
||||||
} while (cursor.moveToPrevious());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (RuntimeException e) {
|
} catch (RuntimeException e) {
|
||||||
Log.e(TAG, "RuntimeException", e);
|
Log.e(TAG, "RuntimeException", e);
|
||||||
} finally {
|
} finally {
|
||||||
if (cursor != null) {
|
if (locationIterator != null) {
|
||||||
cursor.close();
|
locationIterator.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
startRecording(true);
|
startRecording(true);
|
||||||
@@ -1010,11 +1017,11 @@ public class TrackRecordingService extends Service {
|
|||||||
try {
|
try {
|
||||||
Uri uri = myTracksProviderUtils.insertTrackPoint(location, track.getId());
|
Uri uri = myTracksProviderUtils.insertTrackPoint(location, track.getId());
|
||||||
long trackPointId = Long.parseLong(uri.getLastPathSegment());
|
long trackPointId = Long.parseLong(uri.getLastPathSegment());
|
||||||
trackTripStatisticsUpdater.addLocation(location, recordingDistanceInterval, true,
|
ActivityType activityType = CalorieUtils.getActivityType(context, track.getCategory());
|
||||||
CalorieUtils.getActivityType(context, track.getCategory()), PreferencesUtils.getInt(context,
|
trackTripStatisticsUpdater.addLocation(
|
||||||
R.string.stats_weight_key, PreferencesUtils.STATS_WEIGHT_DEFAULT));
|
location, recordingDistanceInterval, true, activityType, weight);
|
||||||
markerTripStatisticsUpdater.addLocation(location, recordingDistanceInterval, false,
|
markerTripStatisticsUpdater.addLocation(
|
||||||
ActivityType.INVALID, PreferencesUtils.STATS_WEIGHT_DEFAULT);
|
location, recordingDistanceInterval, true, activityType, weight);
|
||||||
updateRecordingTrack(track, trackPointId, LocationUtils.isValidLocation(location));
|
updateRecordingTrack(track, trackPointId, LocationUtils.isValidLocation(location));
|
||||||
} catch (SQLiteException e) {
|
} catch (SQLiteException e) {
|
||||||
/*
|
/*
|
||||||
@@ -1377,23 +1384,14 @@ public class TrackRecordingService extends Service {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
double calorie = CalorieUtils.getTrackCalorie(context, track, -1L);
|
|
||||||
|
double[] calories = CalorieUtils.updateTrackCalorie(context, track);
|
||||||
// Update to database
|
|
||||||
track.getTripStatistics().setCalorie(calorie);
|
|
||||||
myTracksProviderUtils.updateTrack(track);
|
|
||||||
|
|
||||||
// Update track statistics
|
// Update track statistics
|
||||||
trackTripStatisticsUpdater.updateCalorie(calorie);
|
trackTripStatisticsUpdater.updateCalorie(calories[0]);
|
||||||
|
|
||||||
// Update marker statistics
|
// Update marker statistics
|
||||||
Waypoint wayPoint = myTracksProviderUtils.getLastWaypoint(
|
markerTripStatisticsUpdater.updateCalorie(calories[1]);
|
||||||
recordingTrackId, WaypointType.STATISTICS);
|
|
||||||
long trackPointId = wayPoint != null ? myTracksProviderUtils.getTrackPointId(
|
|
||||||
recordingTrackId, wayPoint.getLocation())
|
|
||||||
: -1L;
|
|
||||||
calorie = CalorieUtils.getTrackCalorie(context, track, trackPointId);
|
|
||||||
markerTripStatisticsUpdater.updateCalorie(calorie);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-1
@@ -19,6 +19,7 @@ package com.google.android.apps.mytracks.services.sensors;
|
|||||||
import com.google.android.apps.mytracks.content.Sensor.SensorDataSet;
|
import com.google.android.apps.mytracks.content.Sensor.SensorDataSet;
|
||||||
import com.google.android.apps.mytracks.content.Sensor.SensorState;
|
import com.google.android.apps.mytracks.content.Sensor.SensorState;
|
||||||
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.maps.mytracks.R;
|
import com.google.android.maps.mytracks.R;
|
||||||
|
|
||||||
import android.bluetooth.BluetoothAdapter;
|
import android.bluetooth.BluetoothAdapter;
|
||||||
@@ -39,6 +40,8 @@ import java.util.ArrayList;
|
|||||||
*/
|
*/
|
||||||
public class BluetoothSensorManager extends SensorManager {
|
public class BluetoothSensorManager extends SensorManager {
|
||||||
|
|
||||||
|
// 1 second in milliseconds
|
||||||
|
private static final long ONE_SECOND = (long) UnitConversions.S_TO_MS;
|
||||||
private static final BluetoothAdapter bluetoothAdapter = getDefaultBluetoothAdapter();
|
private static final BluetoothAdapter bluetoothAdapter = getDefaultBluetoothAdapter();
|
||||||
private static final String TAG = BluetoothConnectionManager.class.getSimpleName();
|
private static final String TAG = BluetoothConnectionManager.class.getSimpleName();
|
||||||
|
|
||||||
@@ -69,7 +72,7 @@ public class BluetoothSensorManager extends SensorManager {
|
|||||||
while (adapters.isEmpty()) {
|
while (adapters.isEmpty()) {
|
||||||
synchronized (mutex) {
|
synchronized (mutex) {
|
||||||
try {
|
try {
|
||||||
mutex.wait(1000L);
|
mutex.wait(ONE_SECOND);
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
Log.e(TAG, "Interrupted while waiting for default bluetooth adapter", e);
|
Log.e(TAG, "Interrupted while waiting for default bluetooth adapter", e);
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-1
@@ -38,6 +38,7 @@ import android.util.Log;
|
|||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ant Sensor Manager.
|
* Ant Sensor Manager.
|
||||||
@@ -396,7 +397,8 @@ public class AntSensorManager extends SensorManager {
|
|||||||
if (channelConfig[channel].isInitializing()) {
|
if (channelConfig[channel].isInitializing()) {
|
||||||
if (message[AntMesg.MESG_DATA_OFFSET + 2] != 0) {
|
if (message[AntMesg.MESG_DATA_OFFSET + 2] != 0) {
|
||||||
// Error response
|
// Error response
|
||||||
Log.e(TAG, String.format("Error code(%#02x) on message ID(%#02x) on channel %d",
|
Log.e(TAG, String.format(Locale.US,
|
||||||
|
"Error code(%#02x) on message ID(%#02x) on channel %d",
|
||||||
message[AntMesg.MESG_DATA_OFFSET + 2], message[AntMesg.MESG_DATA_OFFSET + 1],
|
message[AntMesg.MESG_DATA_OFFSET + 2], message[AntMesg.MESG_DATA_OFFSET + 1],
|
||||||
channel));
|
channel));
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
+4
-3
@@ -50,8 +50,7 @@ public class AnnouncementPeriodicTask implements PeriodicTask {
|
|||||||
static final float TTS_SPEECH_RATE = 0.9f;
|
static final float TTS_SPEECH_RATE = 0.9f;
|
||||||
|
|
||||||
private static final String TAG = AnnouncementPeriodicTask.class.getSimpleName();
|
private static final String TAG = AnnouncementPeriodicTask.class.getSimpleName();
|
||||||
private static final long HOUR_TO_MILLISECOND = 60 * 60 * 1000;
|
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
static final HashMap<String, String> SPEECH_PARAMS = new HashMap<String, String>();
|
static final HashMap<String, String> SPEECH_PARAMS = new HashMap<String, String>();
|
||||||
static {
|
static {
|
||||||
@@ -249,7 +248,9 @@ public class AnnouncementPeriodicTask implements PeriodicTask {
|
|||||||
} else {
|
} else {
|
||||||
speed = speed == 0 ? 0.0 : 1 / speed;
|
speed = speed == 0 ? 0.0 : 1 / speed;
|
||||||
int paceId = metricUnits ? R.string.voice_pace_per_kilometer : R.string.voice_pace_per_mile;
|
int paceId = metricUnits ? R.string.voice_pace_per_kilometer : R.string.voice_pace_per_mile;
|
||||||
rate = context.getString(paceId, getAnnounceTime((long) (speed * HOUR_TO_MILLISECOND)));
|
long time = (long) (speed * UnitConversions.HR_TO_MIN * UnitConversions.MIN_TO_S
|
||||||
|
* UnitConversions.S_TO_MS);
|
||||||
|
rate = context.getString(paceId, getAnnounceTime(time));
|
||||||
}
|
}
|
||||||
|
|
||||||
int totalDistanceId = metricUnits ? R.plurals.voiceTotalDistanceKilometers
|
int totalDistanceId = metricUnits ? R.plurals.voiceTotalDistanceKilometers
|
||||||
|
|||||||
+12
-169
@@ -17,22 +17,12 @@
|
|||||||
package com.google.android.apps.mytracks.settings;
|
package com.google.android.apps.mytracks.settings;
|
||||||
|
|
||||||
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.maps.mytracks.R;
|
import com.google.android.maps.mytracks.R;
|
||||||
|
|
||||||
import android.app.AlertDialog;
|
|
||||||
import android.app.Dialog;
|
|
||||||
import android.content.DialogInterface;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.preference.CheckBoxPreference;
|
|
||||||
import android.preference.EditTextPreference;
|
|
||||||
import android.preference.ListPreference;
|
import android.preference.ListPreference;
|
||||||
import android.preference.Preference;
|
import android.preference.Preference;
|
||||||
import android.preference.Preference.OnPreferenceChangeListener;
|
import android.preference.Preference.OnPreferenceChangeListener;
|
||||||
import android.preference.Preference.OnPreferenceClickListener;
|
|
||||||
import android.text.InputType;
|
|
||||||
import android.util.Log;
|
|
||||||
import android.widget.EditText;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An activity for accessing stats settings.
|
* An activity for accessing stats settings.
|
||||||
@@ -41,25 +31,12 @@ import android.widget.EditText;
|
|||||||
*/
|
*/
|
||||||
public class StatsSettingsActivity extends AbstractSettingsActivity {
|
public class StatsSettingsActivity extends AbstractSettingsActivity {
|
||||||
|
|
||||||
private static final String TAG = MapSettingsActivity.class.getSimpleName();
|
|
||||||
|
|
||||||
private CheckBoxPreference caloriePreference;
|
|
||||||
private EditTextPreference weightPreference;
|
|
||||||
|
|
||||||
private static final int WEIGHT_INPUT_DIALOG = 1;
|
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle bundle) {
|
protected void onCreate(Bundle bundle) {
|
||||||
super.onCreate(bundle);
|
super.onCreate(bundle);
|
||||||
addPreferencesFromResource(R.xml.stats_settings);
|
addPreferencesFromResource(R.xml.stats_settings);
|
||||||
|
|
||||||
caloriePreference = (CheckBoxPreference) findPreference(getString(R.string.stats_show_calorie_key));
|
|
||||||
weightPreference = (EditTextPreference) findPreference(getString(R.string.stats_weight_key));
|
|
||||||
|
|
||||||
configCaloriePreference();
|
|
||||||
configWeightPreference();
|
|
||||||
updateWeightSummary();
|
|
||||||
/*
|
/*
|
||||||
* Note configureUnitsListPreference will trigger
|
* Note configureUnitsListPreference will trigger
|
||||||
* configureRateListPreference
|
* configureRateListPreference
|
||||||
@@ -72,27 +49,19 @@ public class StatsSettingsActivity extends AbstractSettingsActivity {
|
|||||||
*/
|
*/
|
||||||
private void configUnitsListPreference() {
|
private void configUnitsListPreference() {
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
ListPreference listPreference = (ListPreference) findPreference(getString(R.string.stats_units_key));
|
ListPreference listPreference = (ListPreference) findPreference(
|
||||||
|
getString(R.string.stats_units_key));
|
||||||
OnPreferenceChangeListener listener = new OnPreferenceChangeListener() {
|
OnPreferenceChangeListener listener = new OnPreferenceChangeListener() {
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onPreferenceChange(Preference pref, Object newValue) {
|
|
||||||
configRateListPreference(PreferencesUtils.STATS_UNITS_DEFAULT.equals((String) newValue));
|
|
||||||
|
|
||||||
/*
|
@Override
|
||||||
* It is necessary to change the weight summary as they are in the same
|
public boolean onPreferenceChange(Preference pref, Object newValue) {
|
||||||
* activity.
|
boolean metricUnits = PreferencesUtils.STATS_UNITS_DEFAULT.equals((String) newValue);
|
||||||
*/
|
configRateListPreference(metricUnits);
|
||||||
updateWeightSummary(PreferencesUtils.STATS_UNITS_DEFAULT.equals((String) newValue));
|
|
||||||
// Recreate weight value dialog.
|
|
||||||
removeDialog(WEIGHT_INPUT_DIALOG);
|
|
||||||
onCreateDialog(WEIGHT_INPUT_DIALOG);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
String value = PreferencesUtils.getString(this, R.string.stats_units_key,
|
String value = PreferencesUtils.getString(
|
||||||
PreferencesUtils.STATS_UNITS_DEFAULT);
|
this, R.string.stats_units_key, PreferencesUtils.STATS_UNITS_DEFAULT);
|
||||||
String[] values = getResources().getStringArray(R.array.stats_units_values);
|
String[] values = getResources().getStringArray(R.array.stats_units_values);
|
||||||
String[] options = getResources().getStringArray(R.array.stats_units_options);
|
String[] options = getResources().getStringArray(R.array.stats_units_options);
|
||||||
configureListPreference(listPreference, options, options, values, value, listener);
|
configureListPreference(listPreference, options, options, values, value, listener);
|
||||||
@@ -105,139 +74,13 @@ public class StatsSettingsActivity extends AbstractSettingsActivity {
|
|||||||
*/
|
*/
|
||||||
private void configRateListPreference(boolean metricUnits) {
|
private void configRateListPreference(boolean metricUnits) {
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
ListPreference listPreference = (ListPreference) findPreference(getString(R.string.stats_rate_key));
|
ListPreference listPreference = (ListPreference) findPreference(
|
||||||
String value = PreferencesUtils.getString(this, R.string.stats_rate_key,
|
getString(R.string.stats_rate_key));
|
||||||
PreferencesUtils.STATS_RATE_DEFAULT);
|
String value = PreferencesUtils.getString(
|
||||||
|
this, R.string.stats_rate_key, PreferencesUtils.STATS_RATE_DEFAULT);
|
||||||
String[] values = getResources().getStringArray(R.array.stats_rate_values);
|
String[] values = getResources().getStringArray(R.array.stats_rate_values);
|
||||||
String[] options = getResources().getStringArray(
|
String[] options = getResources().getStringArray(
|
||||||
metricUnits ? R.array.stats_rate_metric_options : R.array.stats_rate_imperial_options);
|
metricUnits ? R.array.stats_rate_metric_options : R.array.stats_rate_imperial_options);
|
||||||
configureListPreference(listPreference, options, options, values, value, null);
|
configureListPreference(listPreference, options, options, values, value, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Configures the calorie preference.
|
|
||||||
*/
|
|
||||||
private void configCaloriePreference() {
|
|
||||||
caloriePreference.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
@Override
|
|
||||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
|
||||||
boolean value = (Boolean) newValue;
|
|
||||||
if (value) {
|
|
||||||
showDialog(WEIGHT_INPUT_DIALOG);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Deprecated
|
|
||||||
protected Dialog onCreateDialog(int id) {
|
|
||||||
Dialog dialog = null;
|
|
||||||
switch (id) {
|
|
||||||
case WEIGHT_INPUT_DIALOG:
|
|
||||||
final EditText weightInput = new EditText(this);
|
|
||||||
weightInput.setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_DECIMAL);
|
|
||||||
weightInput.setText(Integer.toString(getWeightDisplayValue(PreferencesUtils
|
|
||||||
.isMetricUnits(getApplicationContext()))));
|
|
||||||
weightInput.setSelectAllOnFocus(true);
|
|
||||||
dialog = (new AlertDialog.Builder(this))
|
|
||||||
.setMessage(R.string.settings_stats_calorie_weight_description)
|
|
||||||
.setNegativeButton(R.string.generic_cancel, null)
|
|
||||||
.setPositiveButton(R.string.generic_ok,
|
|
||||||
new DialogInterface.OnClickListener() {
|
|
||||||
public void onClick(DialogInterface dialogInterface, int number) {
|
|
||||||
storeWeightValue(weightInput.getText().toString());
|
|
||||||
updateWeightSummary();
|
|
||||||
dialogInterface.cancel();
|
|
||||||
}
|
|
||||||
}).setTitle(R.string.settings_stats_calorie_weight).setView(weightInput).create();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return dialog;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Configures the weight preference.
|
|
||||||
*/
|
|
||||||
private void configWeightPreference() {
|
|
||||||
weightPreference.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
|
|
||||||
@Override
|
|
||||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
|
||||||
storeWeightValue((String) newValue);
|
|
||||||
updateWeightSummary();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
weightPreference.setOnPreferenceClickListener(new OnPreferenceClickListener() {
|
|
||||||
@Override
|
|
||||||
public boolean onPreferenceClick(Preference pref) {
|
|
||||||
int value = getWeightDisplayValue(PreferencesUtils.isMetricUnits(getApplicationContext()));
|
|
||||||
((EditTextPreference) pref).getEditText().setText(String.valueOf(value));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the weight summary.
|
|
||||||
*/
|
|
||||||
private void updateWeightSummary() {
|
|
||||||
boolean metricUnits = PreferencesUtils.isMetricUnits(this);
|
|
||||||
updateWeightSummary(metricUnits);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the weight summary.
|
|
||||||
*
|
|
||||||
* @param metricUnits true if metric units
|
|
||||||
*/
|
|
||||||
private void updateWeightSummary(boolean metricUnits) {
|
|
||||||
int displayValue = getWeightDisplayValue(metricUnits);
|
|
||||||
weightPreference.setSummary(getString(metricUnits ? R.string.value_integer_kilogram
|
|
||||||
: R.string.value_integer_pound, displayValue));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the weight display value in metric or imperial depending on the
|
|
||||||
* preferred units.
|
|
||||||
*
|
|
||||||
* @param metricUnits true if metric units
|
|
||||||
*/
|
|
||||||
private int getWeightDisplayValue(boolean metricUnits) {
|
|
||||||
int value = PreferencesUtils.getInt(this, R.string.stats_weight_key,
|
|
||||||
PreferencesUtils.STATS_WEIGHT_DEFAULT);
|
|
||||||
if (!metricUnits) {
|
|
||||||
value = (int) Math.round(value * UnitConversions.KG_TO_LB);
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stores the weight value, always in metric units.
|
|
||||||
*
|
|
||||||
* @param displayValue the display value
|
|
||||||
*/
|
|
||||||
private void storeWeightValue(String displayValue) {
|
|
||||||
/*
|
|
||||||
* TODO add a method to an abstract class or an utility class to avoid
|
|
||||||
* duplicating store preference logic in MapSettingsActivity.java.
|
|
||||||
*/
|
|
||||||
int value;
|
|
||||||
try {
|
|
||||||
value = Integer.parseInt(displayValue);
|
|
||||||
if (!PreferencesUtils.isMetricUnits(this)) {
|
|
||||||
value = (int) (value * UnitConversions.LB_TO_KG);
|
|
||||||
}
|
|
||||||
} catch (NumberFormatException e) {
|
|
||||||
Log.e(TAG, "invalid value " + displayValue);
|
|
||||||
value = PreferencesUtils.STATS_WEIGHT_DEFAULT;
|
|
||||||
}
|
|
||||||
|
|
||||||
PreferencesUtils.setInt(this, R.string.stats_weight_key, value);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -131,7 +131,7 @@ public class TripStatisticsUpdater {
|
|||||||
* calorie
|
* calorie
|
||||||
*/
|
*/
|
||||||
public void addLocation(Location location, int minRecordingDistance,
|
public void addLocation(Location location, int minRecordingDistance,
|
||||||
boolean calculateCalorie, ActivityType activityType, int weight) {
|
boolean calculateCalorie, ActivityType activityType, double weight) {
|
||||||
// Always update time
|
// Always update time
|
||||||
updateTime(location.getTime());
|
updateTime(location.getTime());
|
||||||
if (!LocationUtils.isValidLocation(location)) {
|
if (!LocationUtils.isValidLocation(location)) {
|
||||||
|
|||||||
@@ -18,11 +18,13 @@ package com.google.android.apps.mytracks.util;
|
|||||||
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
|
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
|
||||||
import com.google.android.apps.mytracks.content.MyTracksProviderUtils.LocationIterator;
|
import com.google.android.apps.mytracks.content.MyTracksProviderUtils.LocationIterator;
|
||||||
import com.google.android.apps.mytracks.content.Track;
|
import com.google.android.apps.mytracks.content.Track;
|
||||||
|
import com.google.android.apps.mytracks.content.Waypoint;
|
||||||
|
import com.google.android.apps.mytracks.content.Waypoint.WaypointType;
|
||||||
import com.google.android.apps.mytracks.stats.TripStatisticsUpdater;
|
import com.google.android.apps.mytracks.stats.TripStatisticsUpdater;
|
||||||
import com.google.android.maps.mytracks.R;
|
import com.google.android.maps.mytracks.R;
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.database.Cursor;
|
||||||
import android.location.Location;
|
import android.location.Location;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -36,7 +38,7 @@ public class CalorieUtils {
|
|||||||
* Activity types.
|
* Activity types.
|
||||||
*/
|
*/
|
||||||
public enum ActivityType {
|
public enum ActivityType {
|
||||||
CYCLING, FOOT, INVALID
|
CYCLING, RUNNING, WALKING, INVALID
|
||||||
}
|
}
|
||||||
|
|
||||||
private CalorieUtils() {}
|
private CalorieUtils() {}
|
||||||
@@ -47,15 +49,10 @@ public class CalorieUtils {
|
|||||||
*/
|
*/
|
||||||
private static final double RESTING_VO2 = 3.5;
|
private static final double RESTING_VO2 = 3.5;
|
||||||
|
|
||||||
/**
|
|
||||||
* Ratio to convert liter to kcal.
|
|
||||||
*/
|
|
||||||
private static final double L_TO_KCAL = 5.0;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Standard gravity in meters per second squared (m/s^2).
|
* Standard gravity in meters per second squared (m/s^2).
|
||||||
*/
|
*/
|
||||||
private static final double EARTH_GRAVITY = 9.80665;
|
private static final double EARTH_GRAVITY = 9.81;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Lumped constant for all frictional losses (tires, bearings, chain).
|
* Lumped constant for all frictional losses (tires, bearings, chain).
|
||||||
@@ -63,22 +60,10 @@ public class CalorieUtils {
|
|||||||
private static final double K1 = 0.0053;
|
private static final double K1 = 0.0053;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Lumped constant for aerodynamic drag.
|
* Lumped constant for aerodynamic drag (kg/m)
|
||||||
*/
|
*/
|
||||||
private static final double K2 = 0.185;
|
private static final double K2 = 0.185;
|
||||||
|
|
||||||
/**
|
|
||||||
* Critical speed running in meters per minute. Converts 4.5 miles per hour to
|
|
||||||
* meters per minute. 4 miles per hour is regarded as the max speed of walking
|
|
||||||
* and 5 miles per hour is regarded as the minimal speed of running, so we use
|
|
||||||
* 4.5 miles per hour as the critical speed. <a href=
|
|
||||||
* "http://www.ideafit.com/fitness-library/calculating-caloric-expenditure-0"
|
|
||||||
* >Reference</a>
|
|
||||||
*/
|
|
||||||
@VisibleForTesting
|
|
||||||
static final double CRTICAL_SPEED_RUNNING = 4.5 * UnitConversions.MI_TO_KM
|
|
||||||
* UnitConversions.KM_TO_M / UnitConversions.HR_TO_MIN;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the activity type.
|
* Gets the activity type.
|
||||||
*
|
*
|
||||||
@@ -86,9 +71,13 @@ public class CalorieUtils {
|
|||||||
* @param activityType the activity type
|
* @param activityType the activity type
|
||||||
*/
|
*/
|
||||||
public static ActivityType getActivityType(Context context, String activityType) {
|
public static ActivityType getActivityType(Context context, String activityType) {
|
||||||
if (TrackIconUtils.getIconValue(context, activityType).equals(TrackIconUtils.WALK)
|
if (activityType == null || activityType.equals("")) {
|
||||||
|| TrackIconUtils.getIconValue(context, activityType).equals(TrackIconUtils.RUN)) {
|
return ActivityType.INVALID;
|
||||||
return ActivityType.FOOT;
|
}
|
||||||
|
if (TrackIconUtils.getIconValue(context, activityType).equals(TrackIconUtils.WALK)) {
|
||||||
|
return ActivityType.WALKING;
|
||||||
|
} else if (TrackIconUtils.getIconValue(context, activityType).equals(TrackIconUtils.RUN)) {
|
||||||
|
return ActivityType.RUNNING;
|
||||||
} else if (TrackIconUtils.getIconValue(context, activityType).equals(TrackIconUtils.BIKE)) {
|
} else if (TrackIconUtils.getIconValue(context, activityType).equals(TrackIconUtils.BIKE)) {
|
||||||
return ActivityType.CYCLING;
|
return ActivityType.CYCLING;
|
||||||
}
|
}
|
||||||
@@ -96,34 +85,79 @@ public class CalorieUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculates the track calorie in kcal.
|
* Updates calories for a track and its waypoints.
|
||||||
*
|
*
|
||||||
* @param context the context
|
* @param context the context
|
||||||
* @param track the track
|
* @param track the track
|
||||||
* @param startTrackPointId the starting track point id. -1L to calculate the
|
* @return an array of two doubles, first is the track calorie, second is the
|
||||||
* entire track
|
* last statistics waypoint calorie
|
||||||
*/
|
*/
|
||||||
public static double getTrackCalorie(Context context, Track track, long startTrackPointId) {
|
public static double[] updateTrackCalorie(Context context, Track track) {
|
||||||
|
MyTracksProviderUtils myTracksProviderUtils = MyTracksProviderUtils.Factory.get(context);
|
||||||
ActivityType activityType = getActivityType(context, track.getCategory());
|
ActivityType activityType = getActivityType(context, track.getCategory());
|
||||||
|
|
||||||
if (activityType == ActivityType.INVALID) {
|
if (activityType == ActivityType.INVALID) {
|
||||||
return 0.0;
|
clearCalorie(myTracksProviderUtils, track);
|
||||||
|
return new double[] { 0.0, 0.0 };
|
||||||
}
|
}
|
||||||
|
|
||||||
MyTracksProviderUtils myTracksProviderUtils = MyTracksProviderUtils.Factory.get(context);
|
TripStatisticsUpdater trackTripStatisticsUpdater = new TripStatisticsUpdater(
|
||||||
LocationIterator iterator = myTracksProviderUtils.getTrackPointLocationIterator(
|
track.getTripStatistics().getStartTime());
|
||||||
track.getId(), startTrackPointId, false, MyTracksProviderUtils.DEFAULT_LOCATION_FACTORY);
|
TripStatisticsUpdater markerTripStatisticsUpdater = new TripStatisticsUpdater(
|
||||||
TripStatisticsUpdater tripStatisticsUpdater = new TripStatisticsUpdater(
|
|
||||||
track.getTripStatistics().getStartTime());
|
track.getTripStatistics().getStartTime());
|
||||||
int recordingDistanceInterval = PreferencesUtils.getInt(context,
|
int recordingDistanceInterval = PreferencesUtils.getInt(context,
|
||||||
R.string.recording_distance_interval_key,
|
R.string.recording_distance_interval_key,
|
||||||
PreferencesUtils.RECORDING_DISTANCE_INTERVAL_DEFAULT);
|
PreferencesUtils.RECORDING_DISTANCE_INTERVAL_DEFAULT);
|
||||||
int statsWeight = PreferencesUtils.getInt(
|
double weight = PreferencesUtils.getFloat(
|
||||||
context, R.string.stats_weight_key, PreferencesUtils.STATS_WEIGHT_DEFAULT);
|
context, R.string.weight_key, PreferencesUtils.WEIGHT_DEFAULT);
|
||||||
while (iterator.hasNext()) {
|
LocationIterator locationIterator = null;
|
||||||
tripStatisticsUpdater.addLocation(
|
Cursor cursor = null;
|
||||||
iterator.next(), recordingDistanceInterval, true, activityType, statsWeight);
|
|
||||||
|
try {
|
||||||
|
Waypoint waypoint = null;
|
||||||
|
|
||||||
|
locationIterator = myTracksProviderUtils.getTrackPointLocationIterator(
|
||||||
|
track.getId(), -1L, false, MyTracksProviderUtils.DEFAULT_LOCATION_FACTORY);
|
||||||
|
cursor = myTracksProviderUtils.getWaypointCursor(track.getId(), -1L, -1);
|
||||||
|
|
||||||
|
if (cursor != null && cursor.moveToFirst()) {
|
||||||
|
/*
|
||||||
|
* Yes, this will skip the first waypoint and that is intentional as the
|
||||||
|
* first waypoint holds the stats for the track.
|
||||||
|
*/
|
||||||
|
waypoint = getNextStatisticsWaypoint(myTracksProviderUtils, cursor);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (locationIterator.hasNext()) {
|
||||||
|
Location location = locationIterator.next();
|
||||||
|
trackTripStatisticsUpdater.addLocation(
|
||||||
|
location, recordingDistanceInterval, true, activityType, weight);
|
||||||
|
markerTripStatisticsUpdater.addLocation(
|
||||||
|
location, recordingDistanceInterval, true, activityType, weight);
|
||||||
|
|
||||||
|
if (waypoint != null && waypoint.getLocation().getTime() == location.getTime()
|
||||||
|
&& waypoint.getLocation().getLatitude() == location.getLatitude()
|
||||||
|
&& waypoint.getLocation().getLongitude() == location.getLongitude()) {
|
||||||
|
waypoint.getTripStatistics()
|
||||||
|
.setCalorie(markerTripStatisticsUpdater.getTripStatistics().getCalorie());
|
||||||
|
myTracksProviderUtils.updateWaypoint(waypoint);
|
||||||
|
markerTripStatisticsUpdater = new TripStatisticsUpdater(location.getTime());
|
||||||
|
waypoint = getNextStatisticsWaypoint(myTracksProviderUtils, cursor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
if (locationIterator != null) {
|
||||||
|
locationIterator.close();
|
||||||
|
}
|
||||||
|
if (cursor != null) {
|
||||||
|
cursor.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return tripStatisticsUpdater.getTripStatistics().getCalorie();
|
double trackCalorie = trackTripStatisticsUpdater.getTripStatistics().getCalorie();
|
||||||
|
track.getTripStatistics().setCalorie(trackCalorie);
|
||||||
|
myTracksProviderUtils.updateTrack(track);
|
||||||
|
return new double[] {
|
||||||
|
trackCalorie, markerTripStatisticsUpdater.getTripStatistics().getCalorie() };
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -137,141 +171,137 @@ public class CalorieUtils {
|
|||||||
* @param activityType the activity type
|
* @param activityType the activity type
|
||||||
*/
|
*/
|
||||||
public static double getCalorie(
|
public static double getCalorie(
|
||||||
Location start, Location stop, double grade, int weight, ActivityType activityType) {
|
Location start, Location stop, double grade, double weight, ActivityType activityType) {
|
||||||
if (activityType == ActivityType.INVALID) {
|
if (activityType == ActivityType.INVALID) {
|
||||||
return 0.0;
|
return 0.0;
|
||||||
}
|
}
|
||||||
return ActivityType.CYCLING == activityType ? getCyclingCalorie(start, stop, grade, weight)
|
|
||||||
: getFootCalorie(start, stop, grade, weight);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the cycling calorie in kcal between two locations.
|
|
||||||
*
|
|
||||||
* @param start the start location
|
|
||||||
* @param stop the stop location
|
|
||||||
* @param grade the grade
|
|
||||||
* @param weight the weight in kilogram of the rider plus bike
|
|
||||||
*/
|
|
||||||
@VisibleForTesting
|
|
||||||
static double getCyclingCalorie(Location start, Location stop, double grade, int weight) {
|
|
||||||
// Gets duration in seconds
|
|
||||||
double duration = (double) (stop.getTime() - start.getTime()) * UnitConversions.MS_TO_S;
|
|
||||||
// Get speed in meters per second
|
|
||||||
double speed = (start.getSpeed() + stop.getSpeed()) / 2.0;
|
|
||||||
|
|
||||||
if (grade < 0) {
|
if (grade < 0) {
|
||||||
grade = 0.0;
|
grade = 0.0;
|
||||||
}
|
}
|
||||||
return getCyclingCalorie(speed, grade, weight, duration);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
// Speed in m/s
|
||||||
* Gets the cycling calorie in kcal using the following equation: <br>
|
double speed = (start.getSpeed() + stop.getSpeed()) / 2.0;
|
||||||
* P = g * m * Vg * (K1 + s) + K2 * (Va)^2 * Vg
|
// Duration in min
|
||||||
* <ul>
|
|
||||||
* <li>P - Power in watt (Joule/second)</li>
|
|
||||||
* <li>g - gravity, using 9.80665 meter/second^2</li>
|
|
||||||
* <li>m - mass of the rider plus bike in kilogram</li>
|
|
||||||
* <li>s - surface grade</li>
|
|
||||||
* <li>Vg - ground relative speed in meter/second</li>
|
|
||||||
* <li>Va - air relative speed. We assume the air speed is zero, so Va is
|
|
||||||
* equal to Vg.</li>
|
|
||||||
* <li>K1 - a constant which represents frictional losses, using 0.0053.</li>
|
|
||||||
* <li>K2 - a constant representing aerodynamic drag, using 0.185.</li>
|
|
||||||
* <li></li>
|
|
||||||
* </ul>
|
|
||||||
*
|
|
||||||
* @param speed the speed in meters per second
|
|
||||||
* @param grade the grade
|
|
||||||
* @param weight weight in kilogram of the rider plus bike
|
|
||||||
* @param duration the duration in seconds
|
|
||||||
*/
|
|
||||||
@VisibleForTesting
|
|
||||||
static double getCyclingCalorie(double speed, double grade, int weight, double duration) {
|
|
||||||
// Get the power in watt (Joule/second)
|
|
||||||
double power = EARTH_GRAVITY * weight * speed * (K1 + grade) + K2 * (speed * speed * speed);
|
|
||||||
|
|
||||||
// Get the calories in kcal
|
|
||||||
return power * duration * UnitConversions.J_TO_KCAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the foot calorie in kcal between two locations.
|
|
||||||
*
|
|
||||||
* @param start the start location
|
|
||||||
* @param stop the stop location
|
|
||||||
* @param grade the grade
|
|
||||||
* @param weight the weight of the user in kilogram
|
|
||||||
*/
|
|
||||||
@VisibleForTesting
|
|
||||||
static double getFootCalorie(Location start, Location stop, double grade, int weight) {
|
|
||||||
// Get speed in meters per second
|
|
||||||
double averageSpeed = (start.getSpeed() + stop.getSpeed()) / 2.0;
|
|
||||||
// Get VO2 in mL/kg/min
|
|
||||||
double vo2 = getFootVo2(averageSpeed, grade);
|
|
||||||
// Duration in minutes
|
|
||||||
double duration = (double) (stop.getTime() - start.getTime()) * UnitConversions.MS_TO_S
|
double duration = (double) (stop.getTime() - start.getTime()) * UnitConversions.MS_TO_S
|
||||||
* UnitConversions.S_TO_MIN;
|
* UnitConversions.S_TO_MIN;
|
||||||
/*
|
|
||||||
* Get the calorie. The unit of calorie is kcal which is came from
|
|
||||||
* (mL/kg/min * min * kg * L/mL * kcal/L)
|
|
||||||
*/
|
|
||||||
return vo2 * duration * weight * UnitConversions.ML_TO_L * L_TO_KCAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
if (activityType == ActivityType.CYCLING) {
|
||||||
* Gets the foot VO2 value in ml/kg/min.
|
/*
|
||||||
*
|
* Power in watt (Joule/second). See
|
||||||
* @param speed the speed in meters per second
|
* http://en.wikipedia.org/wiki/Bicycle_performance.
|
||||||
* @param grade the grade
|
*/
|
||||||
*/
|
double power = EARTH_GRAVITY * weight * speed * (K1 + grade) + K2 * (speed * speed * speed);
|
||||||
@VisibleForTesting
|
|
||||||
static double getFootVo2(double speed, double grade) {
|
// WorkRate in kgm/min
|
||||||
if (grade < 0) {
|
double workRate = power * UnitConversions.W_TO_KGM;
|
||||||
grade = 0.0;
|
|
||||||
|
/*
|
||||||
|
* VO2 in kgm/min/kg 1.8 = oxygen cost of producing 1 kgm/min of power
|
||||||
|
* output. 7 = oxygen cost of unloaded cycling plus resting oxygen
|
||||||
|
* consumption
|
||||||
|
*/
|
||||||
|
double vo2 = (1.8 * workRate / weight) + 7;
|
||||||
|
|
||||||
|
// Calorie in kcal
|
||||||
|
return vo2 * duration * weight * UnitConversions.KGM_TO_KCAL;
|
||||||
|
} else {
|
||||||
|
double vo2 = activityType == ActivityType.RUNNING ? getRunningVo2(speed, grade)
|
||||||
|
: getWalkingVo2(speed, grade);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Calorie in kcal (mL/kg/min * min * kg * L/mL * kcal/L)
|
||||||
|
*/
|
||||||
|
return vo2 * duration * weight * UnitConversions.ML_TO_L * UnitConversions.L_TO_KCAL;
|
||||||
}
|
}
|
||||||
return speed > CRTICAL_SPEED_RUNNING ? getHighSpeedFootVo2(speed, grade)
|
|
||||||
: getLowSpeedFootVo2(speed, grade);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the high speed foot VO2 in ml/kg/min. This equation is appropriate for
|
* Clears calorie in the track and its waypoints.
|
||||||
* speeds greater than 4.5 mph like running.
|
|
||||||
*
|
*
|
||||||
* @param speed the speed in meters per second
|
* @param myTracksProviderUtils the my tracks provider utils
|
||||||
* @param grade the grade
|
* @param track the track
|
||||||
*/
|
*/
|
||||||
@VisibleForTesting
|
private static void clearCalorie(MyTracksProviderUtils myTracksProviderUtils, Track track) {
|
||||||
static double getHighSpeedFootVo2(double speed, double grade) {
|
track.getTripStatistics().setCalorie(0);
|
||||||
// Change from meters per second to meters per minute
|
myTracksProviderUtils.updateTrack(track);
|
||||||
speed = speed / UnitConversions.S_TO_MIN;
|
Cursor cursor = null;
|
||||||
|
try {
|
||||||
/*
|
cursor = myTracksProviderUtils.getWaypointCursor(track.getId(), -1L, -1);
|
||||||
* 0.2 means oxygen cost per meter of moving each kilogram (kg) of body
|
if (cursor != null && cursor.moveToFirst()) {
|
||||||
* weight while running (horizontally). 0.9 means oxygen cost per meter of
|
/*
|
||||||
* moving total body mass against gravity (vertically).
|
* Yes, this will skip the first waypoint and that is intentional as the
|
||||||
*/
|
* first waypoint holds the stats for the track.
|
||||||
return 0.2 * speed + 0.9 * speed * Math.abs(grade) + RESTING_VO2;
|
*/
|
||||||
|
while (cursor.moveToNext()) {
|
||||||
|
Waypoint waypoint = myTracksProviderUtils.createWaypoint(cursor);
|
||||||
|
waypoint.getTripStatistics().setCalorie(0);
|
||||||
|
myTracksProviderUtils.updateWaypoint(waypoint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
if (cursor != null) {
|
||||||
|
cursor.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the low speed foot VO2 in ml/kg/min. This equation is appropriate for
|
* Gets the next statistics waypoint from a cursor.
|
||||||
* speed less than 4.5 mph like walking.
|
|
||||||
*
|
*
|
||||||
* @param speed the speed in meters per second
|
* @param myTracksProviderUtils the my tracks provider utils
|
||||||
|
* @param cursor the cursor
|
||||||
|
*/
|
||||||
|
private static Waypoint getNextStatisticsWaypoint(
|
||||||
|
MyTracksProviderUtils myTracksProviderUtils, Cursor cursor) {
|
||||||
|
if (cursor == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
while (cursor.moveToNext()) {
|
||||||
|
Waypoint waypoint = myTracksProviderUtils.createWaypoint(cursor);
|
||||||
|
if (waypoint.getType() == WaypointType.STATISTICS) {
|
||||||
|
return waypoint;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the running VO2 in ml/kg/min. This equation is appropriate for speeds
|
||||||
|
* greater than 5 mi/hr (or 3 mi/hr or greater if the subject is truly
|
||||||
|
* jogging).
|
||||||
|
*
|
||||||
|
* @param speed the speed in m/s
|
||||||
* @param grade the grade
|
* @param grade the grade
|
||||||
*/
|
*/
|
||||||
@VisibleForTesting
|
private static double getRunningVo2(double speed, double grade) {
|
||||||
static double getLowSpeedFootVo2(double speed, double grade) {
|
// Change from m/s to m/min
|
||||||
// Change from meters per second to meters per minute
|
|
||||||
speed = speed / UnitConversions.S_TO_MIN;
|
speed = speed / UnitConversions.S_TO_MIN;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 0.1 means oxygen cost per meter of moving each kilogram (kg) of body
|
* 0.2 = oxygen cost per meter of moving each kg of body weight while
|
||||||
* weight while walking (horizontally). 1.8 means oxygen cost per meter of
|
* running (horizontally). 0.9 = oxygen cost per meter of moving total body
|
||||||
* moving total body mass against gravity (vertically).
|
* mass against gravity (vertically).
|
||||||
*/
|
*/
|
||||||
return 0.1 * speed + 1.8 * speed * Math.abs(grade) + RESTING_VO2;
|
return 0.2 * speed + 0.9 * speed * grade + RESTING_VO2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the walking VO2 in ml/kg/min. This equation is appropriate for speed
|
||||||
|
* from 1.9 to 4 mi/hr.
|
||||||
|
*
|
||||||
|
* @param speed the speed in m/s
|
||||||
|
* @param grade the grade
|
||||||
|
*/
|
||||||
|
private static double getWalkingVo2(double speed, double grade) {
|
||||||
|
// Change from m/s to m/min
|
||||||
|
speed = speed / UnitConversions.S_TO_MIN;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 0.1 = oxygen cost per meter of moving each kilogram (kg) of body weight
|
||||||
|
* while walking (horizontally). 1.8 = oxygen cost per meter of moving total
|
||||||
|
* body mass against gravity (vertically).
|
||||||
|
*/
|
||||||
|
return 0.1 * speed + 1.8 * speed * grade + RESTING_VO2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -32,7 +32,9 @@ public class LocationUtils {
|
|||||||
|
|
||||||
private static final String TAG = LocationUtils.class.getSimpleName();
|
private static final String TAG = LocationUtils.class.getSimpleName();
|
||||||
|
|
||||||
private static final long MAX_LOCATION_AGE_MS = 60 * 1000; // 1 minute
|
// 1 minute in milliseconds
|
||||||
|
private static final long MAX_LOCATION_AGE_MS = (long) (UnitConversions.MIN_TO_S
|
||||||
|
* UnitConversions.S_TO_MS);
|
||||||
|
|
||||||
private LocationUtils() {}
|
private LocationUtils() {}
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import android.content.Context;
|
|||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.content.SharedPreferences.Editor;
|
import android.content.SharedPreferences.Editor;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utilities to access preferences stored in {@link SharedPreferences}.
|
* Utilities to access preferences stored in {@link SharedPreferences}.
|
||||||
@@ -106,8 +107,6 @@ public class PreferencesUtils {
|
|||||||
public static final boolean STATS_SHOW_COORDINATE_DEFAULT = false;
|
public static final boolean STATS_SHOW_COORDINATE_DEFAULT = false;
|
||||||
public static final boolean STATS_SHOW_GRADE_ELEVATION_DEFAULT = false;
|
public static final boolean STATS_SHOW_GRADE_ELEVATION_DEFAULT = false;
|
||||||
public static final String STATS_UNITS_DEFAULT = "METRIC";
|
public static final String STATS_UNITS_DEFAULT = "METRIC";
|
||||||
public static final boolean STATS_SHOW_CALORIE_DEFAULT = false;
|
|
||||||
public static final int STATS_WEIGHT_DEFAULT = 65; // in kilogram
|
|
||||||
|
|
||||||
// Track color
|
// Track color
|
||||||
public static final String TRACK_COLOR_MODE_DEFAULT = "SINGLE";
|
public static final String TRACK_COLOR_MODE_DEFAULT = "SINGLE";
|
||||||
@@ -124,6 +123,10 @@ public class PreferencesUtils {
|
|||||||
public static final int TRACK_WIDGET_ITEM4_DEFAULT = 2; // average speed
|
public static final int TRACK_WIDGET_ITEM4_DEFAULT = 2; // average speed
|
||||||
public static final int VOICE_FREQUENCY_DEFAULT = 0;
|
public static final int VOICE_FREQUENCY_DEFAULT = 0;
|
||||||
|
|
||||||
|
public static final float WEIGHT_DEFAULT = 65.0f; // in kilogram
|
||||||
|
|
||||||
|
private static final String TAG = PreferencesUtils.class.getSimpleName();
|
||||||
|
|
||||||
private PreferencesUtils() {}
|
private PreferencesUtils() {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -194,6 +197,35 @@ public class PreferencesUtils {
|
|||||||
ApiAdapterFactory.getApiAdapter().applyPreferenceChanges(editor);
|
ApiAdapterFactory.getApiAdapter().applyPreferenceChanges(editor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a float preference value.
|
||||||
|
*
|
||||||
|
* @param context the context
|
||||||
|
* @param keyId the key id
|
||||||
|
* @param defaultValue the default value
|
||||||
|
*/
|
||||||
|
public static float getFloat(Context context, int keyId, float defaultValue) {
|
||||||
|
SharedPreferences sharedPreferences = context.getSharedPreferences(
|
||||||
|
Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
|
||||||
|
return sharedPreferences.getFloat(getKey(context, keyId), defaultValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a float preference value.
|
||||||
|
*
|
||||||
|
* @param context the context
|
||||||
|
* @param keyId the key id
|
||||||
|
* @param value the value
|
||||||
|
*/
|
||||||
|
@SuppressLint("CommitPrefEdits")
|
||||||
|
public static void setFloat(Context context, int keyId, float value) {
|
||||||
|
SharedPreferences sharedPreferences = context.getSharedPreferences(
|
||||||
|
Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
|
||||||
|
Editor editor = sharedPreferences.edit();
|
||||||
|
editor.putFloat(getKey(context, keyId), value);
|
||||||
|
ApiAdapterFactory.getApiAdapter().applyPreferenceChanges(editor);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a long preference value.
|
* Gets a long preference value.
|
||||||
*
|
*
|
||||||
@@ -304,4 +336,37 @@ public class PreferencesUtils {
|
|||||||
}
|
}
|
||||||
setString(context, keyId, list + ";" + value);
|
setString(context, keyId, list + ";" + value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores the weight value, always in metric units.
|
||||||
|
*
|
||||||
|
* @param displayValue the display value
|
||||||
|
*/
|
||||||
|
public static void storeWeightValue(Context context, String displayValue) {
|
||||||
|
double value;
|
||||||
|
try {
|
||||||
|
value = Double.parseDouble(displayValue);
|
||||||
|
if (!PreferencesUtils.isMetricUnits(context)) {
|
||||||
|
value = value * UnitConversions.LB_TO_KG;
|
||||||
|
}
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
Log.e(TAG, "invalid value " + displayValue);
|
||||||
|
value = PreferencesUtils.WEIGHT_DEFAULT;
|
||||||
|
}
|
||||||
|
PreferencesUtils.setFloat(context, R.string.weight_key, (float) value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the weight display value.
|
||||||
|
*
|
||||||
|
* @param context the context
|
||||||
|
*/
|
||||||
|
public static double getWeightDisplayValue(Context context) {
|
||||||
|
double value = PreferencesUtils.getFloat(
|
||||||
|
context, R.string.weight_key, PreferencesUtils.WEIGHT_DEFAULT);
|
||||||
|
if (!PreferencesUtils.isMetricUnits(context)) {
|
||||||
|
value = value * UnitConversions.KG_TO_LB;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,8 +16,6 @@
|
|||||||
|
|
||||||
package com.google.android.apps.mytracks.util;
|
package com.google.android.apps.mytracks.util;
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
|
|
||||||
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.CalorieUtils.ActivityType;
|
import com.google.android.apps.mytracks.util.CalorieUtils.ActivityType;
|
||||||
import com.google.android.maps.mytracks.R;
|
import com.google.android.maps.mytracks.R;
|
||||||
@@ -26,6 +24,7 @@ import android.app.Activity;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.location.Location;
|
import android.location.Location;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
import android.widget.Spinner;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
@@ -40,9 +39,8 @@ public class StatsUtils {
|
|||||||
private static final String COORDINATE_DEGREE = "\u00B0";
|
private static final String COORDINATE_DEGREE = "\u00B0";
|
||||||
private static final String GRADE_PERCENTAGE = "%";
|
private static final String GRADE_PERCENTAGE = "%";
|
||||||
|
|
||||||
private static final String ELEVATION_FORMAT = "%1$.2f";
|
|
||||||
private static final String GRADE_FORMAT = "%1$d";
|
private static final String GRADE_FORMAT = "%1$d";
|
||||||
private static final String CALORIES_FORMAT = "%1$.0f";
|
private static final String CALORIES_FORMAT = "%1$,.0f";
|
||||||
|
|
||||||
private StatsUtils() {}
|
private StatsUtils() {}
|
||||||
|
|
||||||
@@ -63,44 +61,48 @@ public class StatsUtils {
|
|||||||
boolean reportSpeed = PreferencesUtils.isReportSpeed(context);
|
boolean reportSpeed = PreferencesUtils.isReportSpeed(context);
|
||||||
|
|
||||||
// Set speed/pace
|
// Set speed/pace
|
||||||
double speed = isRecording && location != null && location.hasSpeed() ? location.getSpeed()
|
View speed = getView(activity, view, R.id.stats_speed);
|
||||||
: Double.NaN;
|
speed.setVisibility(isRecording ? View.VISIBLE : View.INVISIBLE);
|
||||||
setSpeed(context, getView(activity, view, R.id.stats_speed), R.string.stats_speed,
|
|
||||||
R.string.stats_pace, speed, metricUnits, reportSpeed);
|
if (isRecording) {
|
||||||
|
double value = isRecording && location != null && location.hasSpeed() ? location.getSpeed()
|
||||||
|
: Double.NaN;
|
||||||
|
setSpeed(context, speed, R.string.stats_speed, R.string.stats_pace, value, metricUnits,
|
||||||
|
reportSpeed);
|
||||||
|
}
|
||||||
|
|
||||||
// Set elevation
|
// Set elevation
|
||||||
boolean showGradeElevation = PreferencesUtils.getBoolean(context,
|
boolean showGradeElevation = PreferencesUtils.getBoolean(
|
||||||
R.string.stats_show_grade_elevation_key,
|
context, R.string.stats_show_grade_elevation_key,
|
||||||
PreferencesUtils.STATS_SHOW_GRADE_ELEVATION_DEFAULT);
|
PreferencesUtils.STATS_SHOW_GRADE_ELEVATION_DEFAULT) && isRecording;
|
||||||
View elevation = getView(activity, view, R.id.stats_elevation);
|
View elevation = getView(activity, view, R.id.stats_elevation);
|
||||||
|
elevation.setVisibility(showGradeElevation ? View.VISIBLE : View.GONE);
|
||||||
|
|
||||||
if (showGradeElevation && isRecording) {
|
if (showGradeElevation) {
|
||||||
double altitude = location != null && location.hasAltitude() ? location.getAltitude()
|
double altitude = location != null && location.hasAltitude() ? location.getAltitude()
|
||||||
: Double.NaN;
|
: Double.NaN;
|
||||||
elevation.setVisibility(View.VISIBLE);
|
|
||||||
setElevationValue(context, elevation, -1, altitude, metricUnits);
|
setElevationValue(context, elevation, -1, altitude, metricUnits);
|
||||||
} else {
|
|
||||||
elevation.setVisibility(View.GONE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set coordinate
|
// Set coordinate
|
||||||
boolean showCoordinate = PreferencesUtils.getBoolean(context,
|
boolean showCoordinate = PreferencesUtils.getBoolean(
|
||||||
R.string.stats_show_coordinate_key, PreferencesUtils.STATS_SHOW_COORDINATE_DEFAULT);
|
context, R.string.stats_show_coordinate_key, PreferencesUtils.STATS_SHOW_COORDINATE_DEFAULT)
|
||||||
View coordinateHorizontalLine = getView(activity, view, R.id.stats_coordinate_horizontal_line);
|
&& isRecording;
|
||||||
|
View coordinateSeparator = getView(activity, view, R.id.stats_coordinate_separator);
|
||||||
View coordinateContainer = getView(activity, view, R.id.stats_coordinate_container);
|
View coordinateContainer = getView(activity, view, R.id.stats_coordinate_container);
|
||||||
|
|
||||||
if (showCoordinate && isRecording) {
|
if (coordinateSeparator != null) {
|
||||||
|
coordinateSeparator.setVisibility(showCoordinate ? View.VISIBLE : View.GONE);
|
||||||
|
}
|
||||||
|
coordinateContainer.setVisibility(showCoordinate ? View.VISIBLE : View.GONE);
|
||||||
|
|
||||||
|
if (showCoordinate) {
|
||||||
double latitude = location != null ? location.getLatitude() : Double.NaN;
|
double latitude = location != null ? location.getLatitude() : Double.NaN;
|
||||||
double longitude = location != null ? location.getLongitude() : Double.NaN;
|
double longitude = location != null ? location.getLongitude() : Double.NaN;
|
||||||
coordinateHorizontalLine.setVisibility(View.VISIBLE);
|
|
||||||
coordinateContainer.setVisibility(View.VISIBLE);
|
|
||||||
setCoordinateValue(
|
setCoordinateValue(
|
||||||
context, getView(activity, view, R.id.stats_latitude), R.string.stats_latitude, latitude);
|
context, getView(activity, view, R.id.stats_latitude), R.string.stats_latitude, latitude);
|
||||||
setCoordinateValue(context, getView(activity, view, R.id.stats_longitude),
|
setCoordinateValue(context, getView(activity, view, R.id.stats_longitude),
|
||||||
R.string.stats_longitude, longitude);
|
R.string.stats_longitude, longitude);
|
||||||
} else {
|
|
||||||
coordinateHorizontalLine.setVisibility(View.GONE);
|
|
||||||
coordinateContainer.setVisibility(View.GONE);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,12 +126,12 @@ public class StatsUtils {
|
|||||||
* @param view the containing view for finding views. If null, the activity
|
* @param view the containing view for finding views. If null, the activity
|
||||||
* cannot be null
|
* cannot be null
|
||||||
* @param tripStatistics the trip statistics
|
* @param tripStatistics the trip statistics
|
||||||
* @param trackId the id of track, which is used to set calorie value. Does
|
* @param activityType the activity type
|
||||||
* not handle the calorie If the value is
|
* @param trackIconValue the track icon value or null to hide the track icon
|
||||||
* {@link PreferencesUtils#RECORDING_TRACK_ID_DEFAULT}
|
* spinner
|
||||||
*/
|
*/
|
||||||
public static void setTripStatisticsValues(
|
public static void setTripStatisticsValues(Context context, Activity activity, View view,
|
||||||
Context context, Activity activity, View view, TripStatistics tripStatistics, long trackId) {
|
TripStatistics tripStatistics, ActivityType activityType, String trackIconValue) {
|
||||||
boolean metricUnits = PreferencesUtils.isMetricUnits(context);
|
boolean metricUnits = PreferencesUtils.isMetricUnits(context);
|
||||||
boolean reportSpeed = PreferencesUtils.isReportSpeed(context);
|
boolean reportSpeed = PreferencesUtils.isReportSpeed(context);
|
||||||
|
|
||||||
@@ -138,43 +140,54 @@ public class StatsUtils {
|
|||||||
setDistanceValue(
|
setDistanceValue(
|
||||||
context, getView(activity, view, R.id.stats_distance), totalDistance, metricUnits);
|
context, getView(activity, view, R.id.stats_distance), totalDistance, metricUnits);
|
||||||
|
|
||||||
|
// Set calorie
|
||||||
|
double calorie = tripStatistics == null || activityType == ActivityType.INVALID ? Double.NaN
|
||||||
|
: tripStatistics.getCalorie();
|
||||||
|
setCalorie(context, getView(activity, view, R.id.stats_calorie), calorie);
|
||||||
|
|
||||||
|
Spinner spinner = (Spinner) getView(activity, view, R.id.stats_activity_type_icon);
|
||||||
|
spinner.setVisibility(trackIconValue != null ? View.VISIBLE : View.GONE);
|
||||||
|
if (trackIconValue != null) {
|
||||||
|
TrackIconUtils.setIconSpinner(spinner, trackIconValue);
|
||||||
|
}
|
||||||
|
|
||||||
// Set total time
|
// Set total time
|
||||||
setTimeValue(context, getView(activity, view, R.id.stats_total_time), R.string.stats_total_time,
|
setTimeValue(context, getView(activity, view, R.id.stats_total_time), R.string.stats_total_time,
|
||||||
tripStatistics != null ? tripStatistics.getTotalTime() : -1L);
|
tripStatistics != null ? tripStatistics.getTotalTime() : -1L);
|
||||||
|
|
||||||
|
// Set moving time
|
||||||
|
setTimeValue(context, getView(activity, view, R.id.stats_moving_time),
|
||||||
|
R.string.stats_moving_time, tripStatistics != null ? tripStatistics.getMovingTime() : -1L);
|
||||||
|
|
||||||
// Set average speed/pace
|
// Set average speed/pace
|
||||||
double averageSpeed = tripStatistics != null ? tripStatistics.getAverageSpeed() : Double.NaN;
|
double averageSpeed = tripStatistics != null ? tripStatistics.getAverageSpeed() : Double.NaN;
|
||||||
setSpeed(context, getView(activity, view, R.id.stats_average_speed),
|
setSpeed(context, getView(activity, view, R.id.stats_average_speed),
|
||||||
R.string.stats_average_speed, R.string.stats_average_pace, averageSpeed, metricUnits,
|
R.string.stats_average_speed, R.string.stats_average_pace, averageSpeed, metricUnits,
|
||||||
reportSpeed);
|
reportSpeed);
|
||||||
|
|
||||||
// Set moving time
|
|
||||||
setTimeValue(context, getView(activity, view, R.id.stats_moving_time),
|
|
||||||
R.string.stats_moving_time, tripStatistics != null ? tripStatistics.getMovingTime() : -1L);
|
|
||||||
|
|
||||||
// Set average moving speed/pace
|
|
||||||
double averageMovingSpeed = tripStatistics != null ? tripStatistics.getAverageMovingSpeed()
|
|
||||||
: Double.NaN;
|
|
||||||
setSpeed(context, getView(activity, view, R.id.stats_average_moving_time),
|
|
||||||
R.string.stats_average_moving_speed, R.string.stats_average_moving_pace, averageMovingSpeed,
|
|
||||||
metricUnits, reportSpeed);
|
|
||||||
|
|
||||||
// Set max speed/pace
|
// Set max speed/pace
|
||||||
double maxSpeed = tripStatistics == null ? Double.NaN : tripStatistics.getMaxSpeed();
|
double maxSpeed = tripStatistics == null ? Double.NaN : tripStatistics.getMaxSpeed();
|
||||||
setSpeed(context, getView(activity, view, R.id.stats_max_speed), R.string.stats_max_speed,
|
setSpeed(context, getView(activity, view, R.id.stats_max_speed), R.string.stats_max_speed,
|
||||||
R.string.stats_fastest_pace, maxSpeed, metricUnits, reportSpeed);
|
R.string.stats_fastest_pace, maxSpeed, metricUnits, reportSpeed);
|
||||||
|
|
||||||
|
// Set average moving speed/pace
|
||||||
|
double averageMovingSpeed = tripStatistics != null ? tripStatistics.getAverageMovingSpeed()
|
||||||
|
: Double.NaN;
|
||||||
|
setSpeed(context, getView(activity, view, R.id.stats_average_moving_speed),
|
||||||
|
R.string.stats_average_moving_speed, R.string.stats_average_moving_pace, averageMovingSpeed,
|
||||||
|
metricUnits, reportSpeed);
|
||||||
|
|
||||||
// Set grade/elevation
|
// Set grade/elevation
|
||||||
boolean showGradeElevation = PreferencesUtils.getBoolean(context,
|
boolean showGradeElevation = PreferencesUtils.getBoolean(context,
|
||||||
R.string.stats_show_grade_elevation_key,
|
R.string.stats_show_grade_elevation_key,
|
||||||
PreferencesUtils.STATS_SHOW_GRADE_ELEVATION_DEFAULT);
|
PreferencesUtils.STATS_SHOW_GRADE_ELEVATION_DEFAULT);
|
||||||
View gradeElevationHorizontalLine = getView(
|
View gradeElevationSeparator = getView(activity, view, R.id.stats_grade_elevation_separator);
|
||||||
activity, view, R.id.stats_grade_elevation_horizontal_line);
|
|
||||||
View gradeElevationContainer = getView(activity, view, R.id.stats_grade_elevation_container);
|
View gradeElevationContainer = getView(activity, view, R.id.stats_grade_elevation_container);
|
||||||
|
|
||||||
|
gradeElevationSeparator.setVisibility(showGradeElevation ? View.VISIBLE : View.GONE);
|
||||||
|
gradeElevationContainer.setVisibility(showGradeElevation ? View.VISIBLE : View.GONE);
|
||||||
|
|
||||||
if (showGradeElevation) {
|
if (showGradeElevation) {
|
||||||
gradeElevationHorizontalLine.setVisibility(View.VISIBLE);
|
|
||||||
gradeElevationContainer.setVisibility(View.VISIBLE);
|
|
||||||
// Set grade
|
// Set grade
|
||||||
double minGrade = tripStatistics == null ? Double.NaN : tripStatistics.getMinGrade();
|
double minGrade = tripStatistics == null ? Double.NaN : tripStatistics.getMinGrade();
|
||||||
double maxGrade = tripStatistics == null ? Double.NaN : tripStatistics.getMaxGrade();
|
double maxGrade = tripStatistics == null ? Double.NaN : tripStatistics.getMaxGrade();
|
||||||
@@ -194,33 +207,6 @@ public class StatsUtils {
|
|||||||
R.string.stats_min, minElevation, metricUnits);
|
R.string.stats_min, minElevation, metricUnits);
|
||||||
setElevationValue(context, getView(activity, view, R.id.stats_elevation_max),
|
setElevationValue(context, getView(activity, view, R.id.stats_elevation_max),
|
||||||
R.string.stats_max, maxElevation, metricUnits);
|
R.string.stats_max, maxElevation, metricUnits);
|
||||||
} else {
|
|
||||||
gradeElevationHorizontalLine.setVisibility(View.GONE);
|
|
||||||
gradeElevationContainer.setVisibility(View.GONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (trackId != PreferencesUtils.RECORDING_TRACK_ID_DEFAULT) {
|
|
||||||
// Set calories
|
|
||||||
boolean showCalorie = PreferencesUtils.getBoolean(
|
|
||||||
context, R.string.stats_show_calorie_key, PreferencesUtils.STATS_SHOW_CALORIE_DEFAULT);
|
|
||||||
View calorieHorizontalLine = getView(activity, view, R.id.stats_calorie_horizontal_line);
|
|
||||||
View calorieContainer = getView(activity, view, R.id.stats_calorie_container);
|
|
||||||
if (showCalorie) {
|
|
||||||
calorieHorizontalLine.setVisibility(View.VISIBLE);
|
|
||||||
calorieContainer.setVisibility(View.VISIBLE);
|
|
||||||
double calories = Double.NaN;
|
|
||||||
if (tripStatistics != null) {
|
|
||||||
calories = tripStatistics.getCalorie();
|
|
||||||
}
|
|
||||||
MyTracksProviderUtils myTracksProviderUtils = MyTracksProviderUtils.Factory.get(context);
|
|
||||||
Track track = myTracksProviderUtils.getTrack(trackId);
|
|
||||||
ActivityType activityType = track == null ? ActivityType.INVALID
|
|
||||||
: CalorieUtils.getActivityType(context, track.getCategory());
|
|
||||||
setCalorie(context, getView(activity, view, R.id.stats_calorie), activityType, calories);
|
|
||||||
} else {
|
|
||||||
calorieHorizontalLine.setVisibility(View.GONE);
|
|
||||||
calorieContainer.setVisibility(View.GONE);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -241,6 +227,19 @@ public class StatsUtils {
|
|||||||
setItem(context, view, reportSpeed ? speedLabelId : paceLabelId, parts[0], parts[1]);
|
setItem(context, view, reportSpeed ? speedLabelId : paceLabelId, parts[0], parts[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets calorie.
|
||||||
|
*
|
||||||
|
* @param context the context
|
||||||
|
* @param view the containing view
|
||||||
|
* @param calorie the value of calorie
|
||||||
|
*/
|
||||||
|
private static void setCalorie(Context context, View view, double calorie) {
|
||||||
|
String value = Double.isNaN(calorie) ? null
|
||||||
|
: String.format(Locale.getDefault(), CALORIES_FORMAT, calorie);
|
||||||
|
setItem(context, view, R.string.stats_calorie, value, context.getString(R.string.unit_calorie));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets distance value.
|
* Sets distance value.
|
||||||
*
|
*
|
||||||
@@ -286,11 +285,11 @@ public class StatsUtils {
|
|||||||
unit = null;
|
unit = null;
|
||||||
} else {
|
} else {
|
||||||
if (metricUnits) {
|
if (metricUnits) {
|
||||||
value = String.format(Locale.getDefault(), ELEVATION_FORMAT, elevation);
|
value = StringUtils.formatDecimal(elevation);
|
||||||
unit = context.getString(R.string.unit_meter);
|
unit = context.getString(R.string.unit_meter);
|
||||||
} else {
|
} else {
|
||||||
elevation *= UnitConversions.M_TO_FT;
|
elevation *= UnitConversions.M_TO_FT;
|
||||||
value = String.format(Locale.getDefault(), ELEVATION_FORMAT, elevation);
|
value = StringUtils.formatDecimal(elevation);
|
||||||
unit = context.getString(R.string.unit_feet);
|
unit = context.getString(R.string.unit_feet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -322,28 +321,8 @@ public class StatsUtils {
|
|||||||
private static void setCoordinateValue(
|
private static void setCoordinateValue(
|
||||||
Context context, View view, int labelId, double coordinate) {
|
Context context, View view, int labelId, double coordinate) {
|
||||||
String value = Double.isNaN(coordinate) || Double.isInfinite(coordinate) ? null
|
String value = Double.isNaN(coordinate) || Double.isInfinite(coordinate) ? null
|
||||||
: Location.convert(coordinate, Location.FORMAT_DEGREES);
|
: Location.convert(coordinate, Location.FORMAT_DEGREES) + COORDINATE_DEGREE;
|
||||||
setItem(context, view, labelId, value, COORDINATE_DEGREE);
|
setItem(context, view, labelId, value, null);
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets calorie.
|
|
||||||
*
|
|
||||||
* @param context the context
|
|
||||||
* @param view the containing view
|
|
||||||
* @param activityType the activity type
|
|
||||||
* @param calorie the value of calorie
|
|
||||||
*/
|
|
||||||
private static void setCalorie(
|
|
||||||
Context context, View view, ActivityType activityType, double calorie) {
|
|
||||||
if (activityType == ActivityType.INVALID) {
|
|
||||||
view.setVisibility(View.GONE);
|
|
||||||
} else {
|
|
||||||
view.setVisibility(View.VISIBLE);
|
|
||||||
setItem(context, view, R.string.stats_calorie,
|
|
||||||
String.format(Locale.getDefault(), CALORIES_FORMAT, calorie),
|
|
||||||
context.getString(R.string.unit_calorie));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -355,7 +334,8 @@ public class StatsUtils {
|
|||||||
* @param value the value, can be null
|
* @param value the value, can be null
|
||||||
* @param unit the unit. Null to hide the unit
|
* @param unit the unit. Null to hide the unit
|
||||||
*/
|
*/
|
||||||
private static void setItem(Context context, View view, int labelId, String value, String unit) {
|
private static void setItem(
|
||||||
|
Context context, View view, int labelId, CharSequence value, CharSequence unit) {
|
||||||
TextView labelTextView = (TextView) view.findViewById(R.id.stats_label);
|
TextView labelTextView = (TextView) view.findViewById(R.id.stats_label);
|
||||||
TextView valueTextView = (TextView) view.findViewById(R.id.stats_value);
|
TextView valueTextView = (TextView) view.findViewById(R.id.stats_value);
|
||||||
TextView unitTextView = (TextView) view.findViewById(R.id.stats_unit);
|
TextView unitTextView = (TextView) view.findViewById(R.id.stats_unit);
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ public class StringUtils {
|
|||||||
*/
|
*/
|
||||||
public static String formatElapsedTime(long time) {
|
public static String formatElapsedTime(long time) {
|
||||||
/*
|
/*
|
||||||
* Temporary workaround for DateUtils.formatElapsedTime(time / 1000). In API
|
* Temporary workaround for DateUtils.formatElapsedTime(time * MS_TO_S). In API
|
||||||
* level 17, it returns strings like "1:0:00" instead of "1:00:00", which
|
* level 17, it returns strings like "1:0:00" instead of "1:00:00", which
|
||||||
* breaks several unit tests.
|
* breaks several unit tests.
|
||||||
*/
|
*/
|
||||||
@@ -91,7 +91,7 @@ public class StringUtils {
|
|||||||
long hours = 0;
|
long hours = 0;
|
||||||
long minutes = 0;
|
long minutes = 0;
|
||||||
long seconds = 0;
|
long seconds = 0;
|
||||||
long elapsedSeconds = time / 1000;
|
long elapsedSeconds = (long) (time * UnitConversions.MS_TO_S);
|
||||||
|
|
||||||
if (elapsedSeconds >= 3600) {
|
if (elapsedSeconds >= 3600) {
|
||||||
hours = elapsedSeconds / 3600;
|
hours = elapsedSeconds / 3600;
|
||||||
@@ -149,6 +149,19 @@ public class StringUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String formatWeight(double value) {
|
||||||
|
return formatDecimal(value, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String formatDecimal(double value) {
|
||||||
|
return formatDecimal(value, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String formatDecimal(double value, int precision) {
|
||||||
|
String result = String.format(Locale.getDefault(), "%1$,." + precision + "f", value);
|
||||||
|
return result.replaceAll("[0]*$", "").replaceAll("\\.$", "");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the distance in an array of two strings. The first string is the
|
* Gets the distance in an array of two strings. The first string is the
|
||||||
* distance. The second string is the unit. The first string is null if the
|
* distance. The second string is the unit. The first string is null if the
|
||||||
@@ -183,7 +196,7 @@ public class StringUtils {
|
|||||||
unitId = R.string.unit_feet;
|
unitId = R.string.unit_feet;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
result[0] = String.format("%.2f", distance);
|
result[0] = formatDecimal(distance);
|
||||||
result[1] = context.getString(unitId);
|
result[1] = context.getString(unitId);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -217,13 +230,13 @@ public class StringUtils {
|
|||||||
speed *= UnitConversions.KM_TO_MI;
|
speed *= UnitConversions.KM_TO_MI;
|
||||||
}
|
}
|
||||||
if (reportSpeed) {
|
if (reportSpeed) {
|
||||||
result[0] = String.format("%.2f", speed);
|
result[0] = StringUtils.formatDecimal(speed);
|
||||||
} else {
|
} else {
|
||||||
// convert from hours to minutes
|
// convert from hours to minutes
|
||||||
double pace = speed == 0 ? 0.0 : 60.0 / speed;
|
double pace = speed == 0 ? 0.0 : 60.0 / speed;
|
||||||
int minutes = (int) pace;
|
int minutes = (int) pace;
|
||||||
int seconds = (int) Math.round((pace - minutes) * 60.0);
|
int seconds = (int) Math.round((pace - minutes) * 60.0);
|
||||||
result[0] = String.format("%d:%02d", minutes, seconds);
|
result[0] = String.format(Locale.US, "%d:%02d", minutes, seconds);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -301,7 +314,7 @@ public class StringUtils {
|
|||||||
if (fractional != null) {
|
if (fractional != null) {
|
||||||
// Regex ensures fractional part is in (0,1)
|
// Regex ensures fractional part is in (0,1)
|
||||||
float fractionalSeconds = Float.parseFloat(fractional);
|
float fractionalSeconds = Float.parseFloat(fractional);
|
||||||
long fractionalMillis = (long) (fractionalSeconds * 1000.0f);
|
long fractionalMillis = (long) (fractionalSeconds * UnitConversions.S_TO_MS);
|
||||||
time += fractionalMillis;
|
time += fractionalMillis;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -350,7 +363,7 @@ public class StringUtils {
|
|||||||
}
|
}
|
||||||
int[] parts = new int[3];
|
int[] parts = new int[3];
|
||||||
|
|
||||||
long seconds = time / 1000;
|
long seconds = (long) (time * UnitConversions.MS_TO_S);
|
||||||
parts[0] = (int) (seconds % 60);
|
parts[0] = (int) (seconds % 60);
|
||||||
int minutes = (int) (seconds / 60);
|
int minutes = (int) (seconds / 60);
|
||||||
parts[1] = minutes % 60;
|
parts[1] = minutes % 60;
|
||||||
|
|||||||
@@ -21,8 +21,13 @@ import com.google.android.maps.mytracks.R;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.Bitmap.Config;
|
import android.graphics.Bitmap.Config;
|
||||||
|
import android.graphics.BitmapFactory;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.ArrayAdapter;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
import android.widget.Spinner;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
@@ -100,10 +105,10 @@ public class TrackIconUtils {
|
|||||||
*/
|
*/
|
||||||
public static int getIconDrawable(String iconValue) {
|
public static int getIconDrawable(String iconValue) {
|
||||||
if (iconValue == null || iconValue.equals("")) {
|
if (iconValue == null || iconValue.equals("")) {
|
||||||
return R.drawable.ic_track_walk;
|
return R.drawable.ic_track_generic;
|
||||||
}
|
}
|
||||||
Pair<Integer, Integer> pair = map.get(iconValue);
|
Pair<Integer, Integer> pair = map.get(iconValue);
|
||||||
return pair == null ? R.drawable.ic_track_walk : pair.second;
|
return pair == null ? R.drawable.ic_track_generic : pair.second;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -137,6 +142,9 @@ public class TrackIconUtils {
|
|||||||
* @param activityType the activity type
|
* @param activityType the activity type
|
||||||
*/
|
*/
|
||||||
public static String getIconValue(Context context, String activityType) {
|
public static String getIconValue(Context context, String activityType) {
|
||||||
|
if (activityType == null || activityType.equals("")) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
if (inList(context, activityType, airplane)) {
|
if (inList(context, activityType, airplane)) {
|
||||||
return AIRPLANE;
|
return AIRPLANE;
|
||||||
}
|
}
|
||||||
@@ -196,6 +204,35 @@ public class TrackIconUtils {
|
|||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void setIconSpinner(Spinner spinner, String iconValue) {
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
ArrayAdapter<StringBuilder> adapter = (ArrayAdapter<StringBuilder>) spinner.getAdapter();
|
||||||
|
StringBuilder stringBuilder = adapter.getItem(0);
|
||||||
|
stringBuilder.delete(0, stringBuilder.length());
|
||||||
|
stringBuilder.append(iconValue);
|
||||||
|
adapter.notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ArrayAdapter<StringBuilder> getIconSpinnerAdapter(
|
||||||
|
final Context context, String iconValue) {
|
||||||
|
return new ArrayAdapter<StringBuilder>(context, android.R.layout.simple_spinner_item,
|
||||||
|
new StringBuilder[] { new StringBuilder(iconValue) }) {
|
||||||
|
@Override
|
||||||
|
public View getView(int position, View convertView, android.view.ViewGroup parent) {
|
||||||
|
ImageView imageView = convertView != null ? (ImageView) convertView
|
||||||
|
: new ImageView(getContext());
|
||||||
|
Bitmap source = BitmapFactory.decodeResource(
|
||||||
|
context.getResources(), TrackIconUtils.getIconDrawable(getItem(position).toString()));
|
||||||
|
if (ApiAdapterFactory.getApiAdapter().isSpinnerBackgroundLight()) {
|
||||||
|
source = TrackIconUtils.invertBitmap(source);
|
||||||
|
}
|
||||||
|
imageView.setImageBitmap(source);
|
||||||
|
imageView.setPadding(4, 4, -4, -4);
|
||||||
|
return imageView;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the activity type is in the list.
|
* Returns true if the activity type is in the list.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 Google Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
* use this file except in compliance with the License. You may obtain a copy of
|
||||||
|
* the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations under
|
||||||
|
* the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.google.android.apps.mytracks.util;
|
||||||
|
|
||||||
|
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
|
||||||
|
import com.google.android.apps.mytracks.content.Track;
|
||||||
|
import com.google.android.apps.mytracks.services.TrackRecordingServiceConnection;
|
||||||
|
import com.google.android.maps.mytracks.R;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utilities for updating track.
|
||||||
|
*
|
||||||
|
* @author Jimmy Shih
|
||||||
|
*/
|
||||||
|
public class TrackUtils {
|
||||||
|
|
||||||
|
private TrackUtils() {}
|
||||||
|
|
||||||
|
public static void updateTrack(Context context, Track track, String name, String category,
|
||||||
|
String description, MyTracksProviderUtils myTracksProviderUtils,
|
||||||
|
TrackRecordingServiceConnection trackRecordingServiceConnection, boolean newWeight) {
|
||||||
|
if (name != null) {
|
||||||
|
track.setName(name);
|
||||||
|
}
|
||||||
|
boolean updateCalorie = false;
|
||||||
|
if (category != null) {
|
||||||
|
updateCalorie = !category.equals(track.getCategory()) || newWeight;
|
||||||
|
track.setCategory(category);
|
||||||
|
track.setIcon(TrackIconUtils.getIconValue(context, category));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (description != null) {
|
||||||
|
track.setDescription(description);
|
||||||
|
}
|
||||||
|
track.setModifiedTime(System.currentTimeMillis());
|
||||||
|
myTracksProviderUtils.updateTrack(track);
|
||||||
|
|
||||||
|
if (updateCalorie) {
|
||||||
|
if (track.getId() == PreferencesUtils.getLong(context, R.string.recording_track_id_key)) {
|
||||||
|
// Update calorie through track recording service
|
||||||
|
TrackRecordingServiceConnectionUtils.updateCalorie(trackRecordingServiceConnection);
|
||||||
|
} else {
|
||||||
|
CalorieUtils.updateTrackCalorie(context, track);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean driveSync = PreferencesUtils.getBoolean(
|
||||||
|
context, R.string.drive_sync_key, PreferencesUtils.DRIVE_SYNC_DEFAULT);
|
||||||
|
if (driveSync) {
|
||||||
|
PreferencesUtils.addToList(context, R.string.drive_edited_list_key,
|
||||||
|
PreferencesUtils.DRIVE_EDITED_LIST_DEFAULT, String.valueOf(track.getId()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -24,11 +24,13 @@ public class UnitConversions {
|
|||||||
|
|
||||||
private UnitConversions() {}
|
private UnitConversions() {}
|
||||||
|
|
||||||
// multiplication factor to convert milliliters to liters
|
// Time
|
||||||
public static final double ML_TO_L = 1 / 1000.0;
|
|
||||||
|
// multiplication factor to convert seconds to milliseconds
|
||||||
|
public static final double S_TO_MS = 1000.0;
|
||||||
|
|
||||||
// multiplication factor to convert milliseconds to seconds
|
// multiplication factor to convert milliseconds to seconds
|
||||||
public static final double MS_TO_S = 1 / 1000.0;
|
public static final double MS_TO_S = 1 / S_TO_MS;
|
||||||
|
|
||||||
// multiplication factor to convert minutes to seconds
|
// multiplication factor to convert minutes to seconds
|
||||||
public static final double MIN_TO_S = 60.0;
|
public static final double MIN_TO_S = 60.0;
|
||||||
@@ -42,15 +44,11 @@ public class UnitConversions {
|
|||||||
// multiplication factor to convert minutes to hours
|
// multiplication factor to convert minutes to hours
|
||||||
public static final double MIN_TO_HR = 1 / HR_TO_MIN;
|
public static final double MIN_TO_HR = 1 / HR_TO_MIN;
|
||||||
|
|
||||||
|
// Distance
|
||||||
|
|
||||||
// multiplication factor to convert kilometers to miles
|
// multiplication factor to convert kilometers to miles
|
||||||
public static final double KM_TO_MI = 0.621371192;
|
public static final double KM_TO_MI = 0.621371192;
|
||||||
|
|
||||||
// multiplication factor to convert kilograms to pounds
|
|
||||||
public static final double KG_TO_LB = 2.2046;
|
|
||||||
|
|
||||||
// multiplication factor to convert pounds to kilograms
|
|
||||||
public static final double LB_TO_KG = 1 / KG_TO_LB;
|
|
||||||
|
|
||||||
// multiplication factor to convert miles to kilometers
|
// multiplication factor to convert miles to kilometers
|
||||||
public static final double MI_TO_KM = 1 / KM_TO_MI;
|
public static final double MI_TO_KM = 1 / KM_TO_MI;
|
||||||
|
|
||||||
@@ -60,13 +58,11 @@ public class UnitConversions {
|
|||||||
// multiplication factor to convert feet to miles
|
// multiplication factor to convert feet to miles
|
||||||
public static final double FT_TO_MI = 1 / MI_TO_FT;
|
public static final double FT_TO_MI = 1 / MI_TO_FT;
|
||||||
|
|
||||||
|
// multiplication factor to covert kilometers to meters
|
||||||
|
public static final double KM_TO_M = 1000.0;
|
||||||
|
|
||||||
// multiplication factor to convert meters to kilometers
|
// multiplication factor to convert meters to kilometers
|
||||||
public static final double M_TO_KM = 1 / 1000.0;
|
public static final double M_TO_KM = 1 / KM_TO_M;
|
||||||
|
|
||||||
public static final double KM_TO_M = 1 / M_TO_KM;
|
|
||||||
|
|
||||||
// multiplication factor to convert meters per second to kilometers per hour
|
|
||||||
public static final double MS_TO_KMH = 3.6;
|
|
||||||
|
|
||||||
// multiplication factor to convert meters to miles
|
// multiplication factor to convert meters to miles
|
||||||
public static final double M_TO_MI = M_TO_KM * KM_TO_MI;
|
public static final double M_TO_MI = M_TO_KM * KM_TO_MI;
|
||||||
@@ -74,12 +70,33 @@ public class UnitConversions {
|
|||||||
// multiplication factor to convert meters to feet
|
// multiplication factor to convert meters to feet
|
||||||
public static final double M_TO_FT = M_TO_MI * MI_TO_FT;
|
public static final double M_TO_FT = M_TO_MI * MI_TO_FT;
|
||||||
|
|
||||||
|
// Weight
|
||||||
|
|
||||||
|
// multiplication factor to convert kilograms to pounds
|
||||||
|
public static final double KG_TO_LB = 2.2046;
|
||||||
|
|
||||||
|
// multiplication factor to convert pounds to kilograms
|
||||||
|
public static final double LB_TO_KG = 1 / KG_TO_LB;
|
||||||
|
|
||||||
|
// Calories
|
||||||
|
|
||||||
|
// multiplication factor to convert milliliters to liters
|
||||||
|
public static final double ML_TO_L = 1 / 1000.0;
|
||||||
|
|
||||||
|
// multiplication factor to convert liter to kcal
|
||||||
|
public static final double L_TO_KCAL = 5.0;
|
||||||
|
|
||||||
|
// multiplication factor to convert watt to kgm/min
|
||||||
|
public static final double W_TO_KGM = 6.12;
|
||||||
|
|
||||||
|
// multiplication factor to convert kgm to kcal
|
||||||
|
public static final double KGM_TO_KCAL = 1 / 427.0;
|
||||||
|
|
||||||
|
// Others
|
||||||
|
|
||||||
|
// multiplication factor to convert meters per second to kilometers per hour
|
||||||
|
public static final double MS_TO_KMH = M_TO_KM / (S_TO_MIN * MIN_TO_HR);
|
||||||
|
|
||||||
// multiplication factor to convert degrees to radians
|
// multiplication factor to convert degrees to radians
|
||||||
public static final double DEG_TO_RAD = Math.PI / 180.0;
|
public static final double DEG_TO_RAD = Math.PI / 180.0;
|
||||||
|
|
||||||
// multiplication factor to convert Kcal to joules.
|
|
||||||
public static final double KCAL_TO_J = 4184;
|
|
||||||
|
|
||||||
// multiplication factor to convert joules to Kcal.
|
|
||||||
public static final double J_TO_KCAL = 1 / KCAL_TO_J;
|
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-1
@@ -394,6 +394,7 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
|
|||||||
int elevationGainIndex = cursor.getColumnIndexOrThrow(WaypointsColumns.ELEVATIONGAIN);
|
int elevationGainIndex = cursor.getColumnIndexOrThrow(WaypointsColumns.ELEVATIONGAIN);
|
||||||
int minGradeIndex = cursor.getColumnIndexOrThrow(WaypointsColumns.MINGRADE);
|
int minGradeIndex = cursor.getColumnIndexOrThrow(WaypointsColumns.MINGRADE);
|
||||||
int maxGradeIndex = cursor.getColumnIndexOrThrow(WaypointsColumns.MAXGRADE);
|
int maxGradeIndex = cursor.getColumnIndexOrThrow(WaypointsColumns.MAXGRADE);
|
||||||
|
int calorieIndex = cursor.getColumnIndexOrThrow(WaypointsColumns.CALORIE);
|
||||||
int photoUrlIndex = cursor.getColumnIndexOrThrow(WaypointsColumns.PHOTOURL);
|
int photoUrlIndex = cursor.getColumnIndexOrThrow(WaypointsColumns.PHOTOURL);
|
||||||
|
|
||||||
Waypoint waypoint = new Waypoint();
|
Waypoint waypoint = new Waypoint();
|
||||||
@@ -496,7 +497,10 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
|
|||||||
tripStatistics.setMaxGrade(cursor.getFloat(maxGradeIndex));
|
tripStatistics.setMaxGrade(cursor.getFloat(maxGradeIndex));
|
||||||
hasTripStatistics = true;
|
hasTripStatistics = true;
|
||||||
}
|
}
|
||||||
|
if (!cursor.isNull(calorieIndex)) {
|
||||||
|
tripStatistics.setCalorie(cursor.getFloat(calorieIndex));
|
||||||
|
hasTripStatistics = true;
|
||||||
|
}
|
||||||
if (hasTripStatistics) {
|
if (hasTripStatistics) {
|
||||||
waypoint.setTripStatistics(tripStatistics);
|
waypoint.setTripStatistics(tripStatistics);
|
||||||
}
|
}
|
||||||
@@ -739,6 +743,7 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
|
|||||||
values.put(WaypointsColumns.ELEVATIONGAIN, tripStatistics.getTotalElevationGain());
|
values.put(WaypointsColumns.ELEVATIONGAIN, tripStatistics.getTotalElevationGain());
|
||||||
values.put(WaypointsColumns.MINGRADE, tripStatistics.getMinGrade());
|
values.put(WaypointsColumns.MINGRADE, tripStatistics.getMinGrade());
|
||||||
values.put(WaypointsColumns.MAXGRADE, tripStatistics.getMaxGrade());
|
values.put(WaypointsColumns.MAXGRADE, tripStatistics.getMaxGrade());
|
||||||
|
values.put(WaypointsColumns.CALORIE, tripStatistics.getCalorie());
|
||||||
}
|
}
|
||||||
|
|
||||||
values.put(WaypointsColumns.PHOTOURL, waypoint.getPhotoUrl());
|
values.put(WaypointsColumns.PHOTOURL, waypoint.getPhotoUrl());
|
||||||
|
|||||||
@@ -124,7 +124,7 @@ public interface TracksColumns extends BaseColumns {
|
|||||||
+ MODIFIEDTIME + " INTEGER, " // modified time
|
+ MODIFIEDTIME + " INTEGER, " // modified time
|
||||||
+ SHAREDWITHME + " INTEGER, " // shared with me
|
+ SHAREDWITHME + " INTEGER, " // shared with me
|
||||||
+ SHAREDOWNER + " STRING, " // shared owner
|
+ SHAREDOWNER + " STRING, " // shared owner
|
||||||
+ CALORIE + " INTEGER);"; // calorie
|
+ CALORIE + " FLOAT);"; // calorie
|
||||||
|
|
||||||
public static final String[] COLUMNS = { _ID, // id
|
public static final String[] COLUMNS = { _ID, // id
|
||||||
NAME, // name
|
NAME, // name
|
||||||
@@ -190,6 +190,6 @@ public interface TracksColumns extends BaseColumns {
|
|||||||
ContentTypeIds.LONG_TYPE_ID, // modified time
|
ContentTypeIds.LONG_TYPE_ID, // modified time
|
||||||
ContentTypeIds.BOOLEAN_TYPE_ID, // shared with me
|
ContentTypeIds.BOOLEAN_TYPE_ID, // shared with me
|
||||||
ContentTypeIds.STRING_TYPE_ID, // shared owner
|
ContentTypeIds.STRING_TYPE_ID, // shared owner
|
||||||
ContentTypeIds.INT_TYPE_ID // calorie
|
ContentTypeIds.FLOAT_TYPE_ID // calorie
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,7 +70,8 @@ public interface WaypointsColumns extends BaseColumns {
|
|||||||
public static final String ELEVATIONGAIN = "elevationgain"; // elevation gain
|
public static final String ELEVATIONGAIN = "elevationgain"; // elevation gain
|
||||||
public static final String MINGRADE = "mingrade"; // min grade
|
public static final String MINGRADE = "mingrade"; // min grade
|
||||||
public static final String MAXGRADE = "maxgrade"; // max grade
|
public static final String MAXGRADE = "maxgrade"; // max grade
|
||||||
|
public static final String CALORIE = "calorie"; // calorie
|
||||||
|
|
||||||
public static final String PHOTOURL = "photoUrl"; // url for the photo
|
public static final String PHOTOURL = "photoUrl"; // url for the photo
|
||||||
|
|
||||||
public static final String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME + " ("
|
public static final String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME + " ("
|
||||||
@@ -104,6 +105,7 @@ public interface WaypointsColumns extends BaseColumns {
|
|||||||
+ ELEVATIONGAIN + " FLOAT, "
|
+ ELEVATIONGAIN + " FLOAT, "
|
||||||
+ MINGRADE + " FLOAT, "
|
+ MINGRADE + " FLOAT, "
|
||||||
+ MAXGRADE + " FLOAT, "
|
+ MAXGRADE + " FLOAT, "
|
||||||
|
+ CALORIE + " FLOAT, "
|
||||||
+ PHOTOURL + " STRING"
|
+ PHOTOURL + " STRING"
|
||||||
+ ");";
|
+ ");";
|
||||||
|
|
||||||
@@ -138,6 +140,7 @@ public interface WaypointsColumns extends BaseColumns {
|
|||||||
ELEVATIONGAIN,
|
ELEVATIONGAIN,
|
||||||
MINGRADE,
|
MINGRADE,
|
||||||
MAXGRADE,
|
MAXGRADE,
|
||||||
|
CALORIE,
|
||||||
PHOTOURL
|
PHOTOURL
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -172,6 +175,7 @@ public interface WaypointsColumns extends BaseColumns {
|
|||||||
FLOAT_TYPE_ID, // elevation gain
|
FLOAT_TYPE_ID, // elevation gain
|
||||||
FLOAT_TYPE_ID, // min grade
|
FLOAT_TYPE_ID, // min grade
|
||||||
FLOAT_TYPE_ID, // max grade
|
FLOAT_TYPE_ID, // max grade
|
||||||
|
FLOAT_TYPE_ID, // calorie
|
||||||
STRING_TYPE_ID // photo url
|
STRING_TYPE_ID // photo url
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-6
@@ -225,8 +225,8 @@ public class TripStatisticsUpdaterTest extends TestCase {
|
|||||||
Location location = getLocation(i + locationOffset, (i + locationOffset) * .001, MOVING_SPEED,
|
Location location = getLocation(i + locationOffset, (i + locationOffset) * .001, MOVING_SPEED,
|
||||||
startTime + (timeOffset + i) * TEN_SECONDS);
|
startTime + (timeOffset + i) * TEN_SECONDS);
|
||||||
tripStatisticsUpdater.addLocation(location,
|
tripStatisticsUpdater.addLocation(location,
|
||||||
PreferencesUtils.RECORDING_DISTANCE_INTERVAL_DEFAULT, true, ActivityType.FOOT,
|
PreferencesUtils.RECORDING_DISTANCE_INTERVAL_DEFAULT, true, ActivityType.WALKING,
|
||||||
PreferencesUtils.STATS_WEIGHT_DEFAULT);
|
PreferencesUtils.WEIGHT_DEFAULT);
|
||||||
tripStatistics = tripStatisticsUpdater.getTripStatistics();
|
tripStatistics = tripStatisticsUpdater.getTripStatistics();
|
||||||
|
|
||||||
assertEquals((timeOffset + i) * TEN_SECONDS, tripStatistics.getTotalTime());
|
assertEquals((timeOffset + i) * TEN_SECONDS, tripStatistics.getTotalTime());
|
||||||
@@ -272,8 +272,8 @@ public class TripStatisticsUpdaterTest extends TestCase {
|
|||||||
Location location = getLocation(
|
Location location = getLocation(
|
||||||
locationOffset, locationOffset * .001, 0, startTime + (i + timeOffset) * TEN_SECONDS);
|
locationOffset, locationOffset * .001, 0, startTime + (i + timeOffset) * TEN_SECONDS);
|
||||||
tripStatisticsUpdater.addLocation(location,
|
tripStatisticsUpdater.addLocation(location,
|
||||||
PreferencesUtils.RECORDING_DISTANCE_INTERVAL_DEFAULT, false, ActivityType.FOOT,
|
PreferencesUtils.RECORDING_DISTANCE_INTERVAL_DEFAULT, false, ActivityType.WALKING,
|
||||||
PreferencesUtils.STATS_WEIGHT_DEFAULT);
|
PreferencesUtils.WEIGHT_DEFAULT);
|
||||||
|
|
||||||
tripStatistics = tripStatisticsUpdater.getTripStatistics();
|
tripStatistics = tripStatisticsUpdater.getTripStatistics();
|
||||||
assertEquals((i + timeOffset) * TEN_SECONDS, tripStatistics.getTotalTime());
|
assertEquals((i + timeOffset) * TEN_SECONDS, tripStatistics.getTotalTime());
|
||||||
@@ -310,8 +310,8 @@ public class TripStatisticsUpdaterTest extends TestCase {
|
|||||||
Location location = getLocation(i + locationOffset, (i + locationOffset) * .001, 99999,
|
Location location = getLocation(i + locationOffset, (i + locationOffset) * .001, 99999,
|
||||||
startTime + (timeOffset + i) * TEN_SECONDS);
|
startTime + (timeOffset + i) * TEN_SECONDS);
|
||||||
tripStatisticsUpdater.addLocation(location,
|
tripStatisticsUpdater.addLocation(location,
|
||||||
PreferencesUtils.RECORDING_DISTANCE_INTERVAL_DEFAULT, true, ActivityType.FOOT,
|
PreferencesUtils.RECORDING_DISTANCE_INTERVAL_DEFAULT, true, ActivityType.WALKING,
|
||||||
PreferencesUtils.STATS_WEIGHT_DEFAULT);
|
PreferencesUtils.WEIGHT_DEFAULT);
|
||||||
tripStatistics = tripStatisticsUpdater.getTripStatistics();
|
tripStatistics = tripStatisticsUpdater.getTripStatistics();
|
||||||
|
|
||||||
assertTrue(tripStatistics.getMovingTime() <= tripStatistics.getTotalTime());
|
assertTrue(tripStatistics.getMovingTime() <= tripStatistics.getTotalTime());
|
||||||
|
|||||||
@@ -1,112 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2013 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
|
||||||
* use this file except in compliance with the License. You may obtain a copy of
|
|
||||||
* the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
* License for the specific language governing permissions and limitations under
|
|
||||||
* the License.
|
|
||||||
*/
|
|
||||||
package com.google.android.apps.mytracks.util;
|
|
||||||
|
|
||||||
import android.location.Location;
|
|
||||||
import android.location.LocationManager;
|
|
||||||
|
|
||||||
import junit.framework.TestCase;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A unit test for {@link CalorieUtils}.
|
|
||||||
*
|
|
||||||
* @author youtaol
|
|
||||||
*/
|
|
||||||
public class CalorieUtilsTest extends TestCase {
|
|
||||||
|
|
||||||
Location start = new Location(LocationManager.GPS_PROVIDER);
|
|
||||||
Location stop = new Location(LocationManager.GPS_PROVIDER);
|
|
||||||
private double grade = 0.07;
|
|
||||||
private int weight = 80;
|
|
||||||
private final long TIME_INTERVAL = 1000l;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void setUp() throws Exception {
|
|
||||||
super.setUp();
|
|
||||||
// Make the time interval is not 0
|
|
||||||
stop.setTime(start.getTime() + TIME_INTERVAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks using foot calculation equation.
|
|
||||||
*/
|
|
||||||
public void testGetCalories_foot() {
|
|
||||||
double actual = CalorieUtils.getCalorie(start, stop, grade, weight,
|
|
||||||
CalorieUtils.ActivityType.FOOT);
|
|
||||||
double expected = CalorieUtils.getFootCalorie(start, stop, grade, weight);
|
|
||||||
assertEquals(expected, actual);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks whether using foot calculation equation while grade is negative.
|
|
||||||
*/
|
|
||||||
public void testGetCalories_footNegativeGrade() {
|
|
||||||
double actualGrade = -5;
|
|
||||||
double expectGrade = 0;
|
|
||||||
double actual = CalorieUtils.getCalorie(start, stop, actualGrade, weight,
|
|
||||||
CalorieUtils.ActivityType.FOOT);
|
|
||||||
double expected = CalorieUtils.getFootCalorie(start, stop, expectGrade, weight);
|
|
||||||
assertEquals(expected, actual);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks using cycling calculation equation.
|
|
||||||
*/
|
|
||||||
public void testGetCalories_cycling() {
|
|
||||||
double actual = CalorieUtils.getCalorie(start, stop, grade, weight,
|
|
||||||
CalorieUtils.ActivityType.CYCLING);
|
|
||||||
double expected = CalorieUtils.getCyclingCalorie(start, stop, grade, weight);
|
|
||||||
assertEquals(expected, actual);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks using running VO2 equation.
|
|
||||||
*/
|
|
||||||
public void testGetVO2_running() {
|
|
||||||
double actual = CalorieUtils.getFootVo2(CalorieUtils.CRTICAL_SPEED_RUNNING * 2, grade);
|
|
||||||
double expected = CalorieUtils.getHighSpeedFootVo2(CalorieUtils.CRTICAL_SPEED_RUNNING * 2,
|
|
||||||
grade);
|
|
||||||
assertEquals(expected, actual);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks using walking VO2 equation.
|
|
||||||
*/
|
|
||||||
public void testGetVO2_walking() {
|
|
||||||
// Test at half the critical speed
|
|
||||||
double footSpeed = CalorieUtils.CRTICAL_SPEED_RUNNING / 2.0;
|
|
||||||
|
|
||||||
double actual = CalorieUtils.getFootVo2(footSpeed, grade);
|
|
||||||
double expected = CalorieUtils.getLowSpeedFootVo2(footSpeed, grade);
|
|
||||||
assertEquals(expected, actual);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks calculating cycling calorie. 175 is the watt usage for a 90 kg bike
|
|
||||||
* + rider to go 9 m/s (20 mph or 32 km/h) on the flat. <a href=
|
|
||||||
* "http://www.ideafit.com/fitness-library/calculating-caloric-expenditure-0"
|
|
||||||
* >Reference</a>
|
|
||||||
*/
|
|
||||||
public void testCalculateCalorieCycling() {
|
|
||||||
grade = 0;
|
|
||||||
weight = 90;
|
|
||||||
start.setSpeed(9);
|
|
||||||
stop.setSpeed(9);
|
|
||||||
double expected = 175.0 * (TIME_INTERVAL / 1000) * UnitConversions.J_TO_KCAL;
|
|
||||||
double actual = CalorieUtils.getCyclingCalorie(start, stop, grade, weight);
|
|
||||||
assertTrue((actual - expected) / expected < 0.02);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user