mirror of
https://codeberg.org/OpenTracksApp/OpenTracks.git
synced 2026-10-02 09:33:06 +02:00
Merging gingerbread changes to head.
This commit is contained in:
@@ -6,5 +6,7 @@
|
||||
<classpathentry kind="lib" path="libs/accounts.jar"/>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="src" path="gen"/>
|
||||
<classpathentry kind="src" path="MyTracksLib_src"/>
|
||||
<classpathentry exported="true" kind="lib" path="/MyTracksLib/libs/protobuf-java-2.3.0-lite.jar"/>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
</classpath>
|
||||
|
||||
@@ -30,4 +30,11 @@
|
||||
<nature>com.android.ide.eclipse.adt.AndroidNature</nature>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
</natures>
|
||||
<linkedResources>
|
||||
<link>
|
||||
<name>MyTracksLib_src</name>
|
||||
<type>2</type>
|
||||
<locationURI>_android_MyTracksLib_e2802071/src</locationURI>
|
||||
</link>
|
||||
</linkedResources>
|
||||
</projectDescription>
|
||||
|
||||
@@ -1,9 +1,24 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright 2010 Google Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.google.android.maps.mytracks"
|
||||
android:installLocation="auto"
|
||||
android:versionCode="20"
|
||||
android:versionName="1.0.19">
|
||||
android:versionCode="22"
|
||||
android:versionName="1.0.21">
|
||||
<application android:icon="@drawable/arrow_icon"
|
||||
android:label="@string/app_name"
|
||||
android:backupAgent="com.google.android.apps.mytracks.io.backup.MyTracksBackupAgent">
|
||||
@@ -13,7 +28,10 @@
|
||||
android:value="AEdPqrEAAAAIi-_QiwoRSc9_bAC9cmuNXTQyU8ajJmGtKdhskQ" />
|
||||
|
||||
<provider android:name="com.google.android.apps.mytracks.content.MyTracksProvider"
|
||||
android:authorities="com.google.android.maps.mytracks" />
|
||||
android:authorities="com.google.android.maps.mytracks"
|
||||
android:exported="true"
|
||||
android:readPermission="com.google.android.apps.mytracks.READ_TRACK_DATA"
|
||||
android:writePermission="com.google.android.apps.mytracks.WRITE_TRACK_DATA" />
|
||||
|
||||
<activity android:name="com.google.android.apps.mytracks.MyTracks"
|
||||
android:label="My Tracks"
|
||||
@@ -35,11 +53,13 @@
|
||||
</activity>
|
||||
|
||||
<activity android:name="com.google.android.apps.mytracks.MyTracksMap"
|
||||
android:label="MyTracks" />
|
||||
android:label="MyTracks"
|
||||
android:exported="false" />
|
||||
|
||||
<activity android:name="com.google.android.apps.mymaps.MyMapsList"
|
||||
android:label="@string/map_list_title"
|
||||
android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|fontScale" />
|
||||
android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|fontScale"
|
||||
android:exported="false" />
|
||||
|
||||
<activity android:name="com.google.android.apps.mytracks.MyTracksList"
|
||||
android:label="Recorded Tracks" />
|
||||
@@ -60,19 +80,26 @@
|
||||
android:label="@string/aggregated_stats" />
|
||||
|
||||
<activity android:name="com.google.android.apps.mytracks.StatsActivity"
|
||||
android:label="@string/statistics" />
|
||||
android:label="@string/statistics"
|
||||
android:exported="false" />
|
||||
|
||||
<activity android:name="com.google.android.apps.mytracks.SensorStateActivity"
|
||||
android:label="@string/sensor_state" />
|
||||
|
||||
<activity android:name="com.google.android.apps.mytracks.ChartActivity"
|
||||
android:label="@string/elevation_label"/>
|
||||
android:label="@string/elevation_label"
|
||||
android:exported="false" />
|
||||
|
||||
<activity android:name="com.google.android.apps.mytracks.WelcomeActivity"
|
||||
android:label="@string/welcome"/>
|
||||
android:label="@string/welcome"
|
||||
android:exported="false" />
|
||||
|
||||
<service android:name="com.google.android.apps.mytracks.services.TrackRecordingService"
|
||||
android:label="Track Recording Service"
|
||||
android:icon="@drawable/arrow_320"
|
||||
android:enabled="true"
|
||||
android:exported="true" />
|
||||
android:exported="true"
|
||||
android:permission="com.google.android.apps.mytracks.WRITE_TRACK_DATA" />
|
||||
|
||||
<receiver android:name="com.google.android.apps.mytracks.MyTracksReceiver">
|
||||
<intent-filter>
|
||||
@@ -89,6 +116,8 @@
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
|
||||
|
||||
<!-- Permissions for uploading tracks -->
|
||||
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
|
||||
@@ -102,7 +131,32 @@
|
||||
|
||||
<!-- Permissions for misc services -->
|
||||
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
|
||||
|
||||
|
||||
<!-- Exported permissions (for other apps to use our features) -->
|
||||
<!-- Permission to get track start/end broadcasts -->
|
||||
<permission android:name="com.google.android.apps.mytracks.TRACK_NOTIFICATIONS"
|
||||
android:permissionGroup="android.permission-group.LOCATION"
|
||||
android:label="@string/notification_permission_label"
|
||||
android:description="@string/notification_permission_description"
|
||||
android:protectionLevel="normal" />
|
||||
<!-- Permission to read raw track data (points, etc.) -->
|
||||
<permission android:name="com.google.android.apps.mytracks.READ_TRACK_DATA"
|
||||
android:permissionGroup="android.permission-group.LOCATION"
|
||||
android:label="@string/read_tracks_permission_label"
|
||||
android:description="@string/read_tracks_permission_description"
|
||||
android:protectionLevel="dangerous" />
|
||||
<!-- Permission to write track data, either raw or by making service calls -->
|
||||
<permission android:name="com.google.android.apps.mytracks.WRITE_TRACK_DATA"
|
||||
android:permissionGroup="android.permission-group.LOCATION"
|
||||
android:label="@string/write_tracks_permission_label"
|
||||
android:description="@string/write_tracks_permission_description"
|
||||
android:protectionLevel="dangerous" />
|
||||
|
||||
<!-- We read and write raw track data, obviously. -->
|
||||
<uses-permission android:name="com.google.android.apps.mytracks.READ_TRACK_DATA" />
|
||||
<uses-permission android:name="com.google.android.apps.mytracks.WRITE_TRACK_DATA" />
|
||||
<uses-permission android:name="com.google.android.apps.mytracks.TRACK_NOTIFICATIONS" />
|
||||
|
||||
<!-- Features required -->
|
||||
<uses-feature android:name="android.hardware.location" android:required="true"/>
|
||||
<uses-feature android:name="android.hardware.location.gps" android:required="true"/>
|
||||
|
||||
@@ -11,3 +11,4 @@
|
||||
split.density=false
|
||||
# Project target.
|
||||
target=Google Inc.:Google APIs:9
|
||||
android.library.reference.1=../MyTracksLib/
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
-optimizationpasses 5
|
||||
-dontusemixedcaseclassnames
|
||||
-dontskipnonpubliclibraryclasses
|
||||
-dontpreverify
|
||||
-verbose
|
||||
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
|
||||
|
||||
-keep public class * extends android.app.Activity
|
||||
-keep public class * extends android.app.Application
|
||||
-keep public class * extends android.app.Service
|
||||
-keep public class * extends android.content.BroadcastReceiver
|
||||
-keep public class * extends android.content.ContentProvider
|
||||
-keep public class com.android.vending.licensing.ILicensingService
|
||||
|
||||
-keepclasseswithmembernames class * {
|
||||
native <methods>;
|
||||
}
|
||||
|
||||
-keepclasseswithmembernames class * {
|
||||
public <init>(android.content.Context, android.util.AttributeSet);
|
||||
}
|
||||
|
||||
-keepclasseswithmembernames class * {
|
||||
public <init>(android.content.Context, android.util.AttributeSet, int);
|
||||
}
|
||||
|
||||
-keepclassmembers enum * {
|
||||
public static **[] values();
|
||||
public static ** valueOf(java.lang.String);
|
||||
}
|
||||
|
||||
-keep class * implements android.os.Parcelable {
|
||||
public static final android.os.Parcelable$Creator *;
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 358 B After Width: | Height: | Size: 1.8 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.9 KiB |
@@ -103,6 +103,21 @@ limitations under the License.
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/speed"/>
|
||||
<CheckBox android:id="@+id/chart_settings_power"
|
||||
android:checked="true"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/power"/>
|
||||
<CheckBox android:id="@+id/chart_settings_cadence"
|
||||
android:checked="true"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/cadence"/>
|
||||
<CheckBox android:id="@+id/chart_settings_heart_rate"
|
||||
android:checked="true"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/heart_rate"/>
|
||||
</LinearLayout>
|
||||
</TableRow>
|
||||
</TableLayout>
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright 2010 Google Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<RelativeLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="fill_parent">
|
||||
|
||||
<ScrollView
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="fill_parent">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="fill_parent">
|
||||
|
||||
<TableLayout
|
||||
android:layout_height="wrap_content"
|
||||
android:stretchColumns="1,4"
|
||||
android:layout_width="fill_parent">
|
||||
|
||||
<!-- Layout the sensor state on one line. -->
|
||||
<TableRow>
|
||||
<TextView
|
||||
android:layout_span="5"
|
||||
android:text="@string/sensor_state" />
|
||||
</TableRow>
|
||||
<TableRow
|
||||
android:background="@color/stat_label_background">
|
||||
<TextView
|
||||
android:id="@+id/sensor_state_register"
|
||||
android:layout_column="1"
|
||||
android:layout_span="5"
|
||||
style="@style/StatsRegister" />
|
||||
</TableRow>
|
||||
|
||||
<!-- Layout the sensor data age on one line. -->
|
||||
<TableRow>
|
||||
<TextView
|
||||
android:layout_span="5"
|
||||
android:text="@string/sensor_data_time" />
|
||||
</TableRow>
|
||||
<TableRow
|
||||
android:background="@color/stat_label_background">
|
||||
<TextView
|
||||
android:id="@+id/sensor_data_time_register"
|
||||
android:layout_column="1"
|
||||
android:layout_span="5"
|
||||
style="@style/StatsRegister" />
|
||||
</TableRow>
|
||||
|
||||
<!-- Power meter -->
|
||||
<TableRow
|
||||
android:padding="1dip">
|
||||
<TextView
|
||||
android:layout_column="1"
|
||||
android:layout_span="3"
|
||||
android:text="@string/power" />
|
||||
</TableRow>
|
||||
<TableRow
|
||||
android:background="@color/stat_label_background">
|
||||
<TextView
|
||||
style="@style/StatsRegister.Big"
|
||||
android:id="@+id/power_state_register"
|
||||
android:layout_column="1"
|
||||
android:layout_span="4" />
|
||||
<TextView
|
||||
style="@style/StatsUnitSolo" />
|
||||
android:layout_column="5"
|
||||
android:text="@string/watts" />
|
||||
</TableRow>
|
||||
|
||||
<!-- Cadence -->
|
||||
<TableRow
|
||||
android:padding="1dip">
|
||||
<TextView
|
||||
android:layout_column="1"
|
||||
android:layout_span="3"
|
||||
android:text="@string/cadence" />
|
||||
</TableRow>
|
||||
<TableRow
|
||||
android:background="@color/stat_label_background">
|
||||
<TextView
|
||||
style="@style/StatsRegister.Big"
|
||||
android:id="@+id/cadence_state_register"
|
||||
android:layout_column="4" />
|
||||
<TextView
|
||||
style="@style/StatsUnitSolo" />
|
||||
android:layout_column="2"
|
||||
android:text="@string/revolutions_per_minute" />
|
||||
</TableRow>
|
||||
|
||||
<!-- Heart Rate -->
|
||||
<TableRow
|
||||
android:padding="1dip">
|
||||
<TextView
|
||||
android:layout_column="1"
|
||||
android:layout_span="3"
|
||||
android:text="@string/heart_rate" />
|
||||
</TableRow>
|
||||
<TableRow
|
||||
android:background="@color/stat_label_background">
|
||||
<TextView
|
||||
style="@style/StatsRegister.Big"
|
||||
android:id="@+id/heart_rate_register"
|
||||
android:layout_column="1"
|
||||
android:layout_span="4" />
|
||||
<TextView
|
||||
style="@style/StatsUnitSolo"
|
||||
android:layout_column="5"
|
||||
android:text="@string/bpm" />
|
||||
</TableRow>
|
||||
|
||||
</TableLayout>
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
</RelativeLayout>
|
||||
+48
-225
@@ -42,15 +42,10 @@ limitations under the License.
|
||||
<TableRow
|
||||
android:background="@color/stat_label_background">
|
||||
<TextView
|
||||
android:gravity="right"
|
||||
style="@style/StatsRegister.Big"
|
||||
android:id="@+id/speed_register"
|
||||
android:layout_column="1"
|
||||
android:layout_marginBottom="-13dip"
|
||||
android:layout_marginTop="-13dip"
|
||||
android:layout_span="4"
|
||||
android:text="@string/unknown"
|
||||
android:textColor="@color/stat_label_text"
|
||||
android:textSize="50sp" />
|
||||
android:layout_span="4"/>
|
||||
<LinearLayout
|
||||
android:gravity="bottom"
|
||||
android:layout_column="5"
|
||||
@@ -62,24 +57,12 @@ limitations under the License.
|
||||
android:layout_width="fill_parent" />
|
||||
<TextView
|
||||
android:id="@+id/speed_unit_label_top"
|
||||
android:gravity="bottom"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="2dip"
|
||||
android:layout_marginTop="2dip"
|
||||
android:layout_width="wrap_content"
|
||||
android:textColor="@color/stat_label_text" />
|
||||
style="@style/StatsUnit" />
|
||||
<TextView
|
||||
android:background="@color/black"
|
||||
android:layout_height="3dip"
|
||||
android:layout_width="fill_parent" />
|
||||
style="@style/StatsDivider" />
|
||||
<TextView
|
||||
android:id="@+id/speed_unit_label_bottom"
|
||||
android:gravity="bottom"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="2dip"
|
||||
android:layout_marginTop="2dip"
|
||||
android:layout_width="wrap_content"
|
||||
android:textColor="@color/stat_label_text" />
|
||||
style="@style/StatsUnit" />
|
||||
</LinearLayout>
|
||||
</TableRow>
|
||||
|
||||
@@ -100,43 +83,25 @@ limitations under the License.
|
||||
<TableRow
|
||||
android:background="@color/stat_label_background">
|
||||
<TextView
|
||||
android:gravity="right"
|
||||
style="@style/StatsRegister"
|
||||
android:id="@+id/total_distance_register"
|
||||
android:layout_column="1"
|
||||
android:layout_marginBottom="-9dip"
|
||||
android:layout_marginTop="-9dip"
|
||||
android:text="@string/unknown"
|
||||
android:textColor="@color/stat_label_text"
|
||||
android:textSize="40sp" />
|
||||
android:layout_column="1" />
|
||||
<TextView
|
||||
android:gravity="left"
|
||||
android:id="@+id/total_distance_unit_label"
|
||||
android:layout_column="2"
|
||||
android:layout_marginBottom="-9dip"
|
||||
android:layout_marginTop="-9dip"
|
||||
android:text="@string/mile"
|
||||
android:textColor="@color/stat_label_text" />
|
||||
style="@style/StatsUnitSolo" />
|
||||
<!-- TODO 4/08/2009
|
||||
The following is a bad hack to get a spacer the same size as the
|
||||
text. Ideally this should just be a View, however I don't know how to
|
||||
set the view height properly. fill_parent on this element causes as
|
||||
NullPointerException. This same filler is repeated on each line.-->
|
||||
<TextView
|
||||
android:background="@color/black"
|
||||
android:layout_column="3"
|
||||
android:layout_marginBottom="-9dip"
|
||||
android:layout_marginTop="-9dip"
|
||||
android:layout_width="5dip"
|
||||
android:textSize="40sp" />
|
||||
style="@style/StatsSpacer"
|
||||
android:layout_column="3"/>
|
||||
<TextView
|
||||
android:gravity="right"
|
||||
android:id="@+id/max_speed_register"
|
||||
android:layout_column="4"
|
||||
android:layout_marginBottom="-9dip"
|
||||
android:layout_marginTop="-9dip"
|
||||
android:text="@string/unknown"
|
||||
android:textColor="@color/stat_label_text"
|
||||
android:textSize="40sp" />
|
||||
style="@style/StatsRegister"
|
||||
android:layout_column="4" />
|
||||
<LinearLayout
|
||||
android:gravity="bottom"
|
||||
android:layout_column="5"
|
||||
@@ -145,24 +110,12 @@ limitations under the License.
|
||||
android:orientation="vertical">
|
||||
<TextView
|
||||
android:id="@+id/max_speed_unit_label_top"
|
||||
android:gravity="bottom"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="-1dip"
|
||||
android:layout_marginTop="-1dip"
|
||||
android:layout_width="wrap_content"
|
||||
android:textColor="@color/stat_label_text" />
|
||||
style="@style/StatsUnit" />
|
||||
<TextView
|
||||
android:background="@color/black"
|
||||
android:layout_height="3dip"
|
||||
android:layout_width="fill_parent" />
|
||||
style="@style/StatsDivider" />
|
||||
<TextView
|
||||
android:id="@+id/max_speed_unit_label_bottom"
|
||||
android:gravity="bottom"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="-1dip"
|
||||
android:layout_marginTop="-1dip"
|
||||
android:layout_width="wrap_content"
|
||||
android:textColor="@color/stat_label_text" />
|
||||
style="@style/StatsUnit" />
|
||||
</LinearLayout>
|
||||
</TableRow>
|
||||
|
||||
@@ -182,33 +135,19 @@ limitations under the License.
|
||||
<TableRow
|
||||
android:background="@color/stat_label_background">
|
||||
<TextView
|
||||
android:gravity="right"
|
||||
android:id="@+id/total_time_register"
|
||||
android:layout_column="1"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="-9dip"
|
||||
android:layout_marginTop="-9dip"
|
||||
android:layout_span="2"
|
||||
android:layout_width="fill_parent"
|
||||
android:text="@string/unknown"
|
||||
android:textColor="@color/stat_label_text"
|
||||
android:textSize="40sp" />
|
||||
style="@style/StatsRegister" />
|
||||
<TextView
|
||||
android:background="@color/black"
|
||||
android:layout_column="3"
|
||||
android:layout_marginBottom="-9dip"
|
||||
android:layout_marginTop="-9dip"
|
||||
android:layout_width="5dip"
|
||||
android:textSize="40sp" />
|
||||
style="@style/StatsSpacer"
|
||||
android:layout_column="3"/>
|
||||
<TextView
|
||||
android:gravity="right"
|
||||
android:id="@+id/average_speed_register"
|
||||
android:layout_column="4"
|
||||
android:layout_marginBottom="-9dip"
|
||||
android:layout_marginTop="-9dip"
|
||||
android:text="@string/unknown"
|
||||
android:textColor="@color/stat_label_text"
|
||||
android:textSize="40sp" />
|
||||
style="@style/StatsRegister" />
|
||||
<LinearLayout
|
||||
android:gravity="bottom"
|
||||
android:layout_column="5"
|
||||
@@ -217,24 +156,12 @@ limitations under the License.
|
||||
android:orientation="vertical">
|
||||
<TextView
|
||||
android:id="@+id/average_speed_unit_label_top"
|
||||
android:gravity="bottom"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="-1dip"
|
||||
android:layout_marginTop="-1dip"
|
||||
android:layout_width="wrap_content"
|
||||
android:textColor="@color/stat_label_text" />
|
||||
style="@style/StatsUnit" />
|
||||
<TextView
|
||||
android:background="@color/black"
|
||||
android:layout_height="3dip"
|
||||
android:layout_width="fill_parent" />
|
||||
style="@style/StatsDivider" />
|
||||
<TextView
|
||||
android:id="@+id/average_speed_unit_label_bottom"
|
||||
android:gravity="bottom"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="-1dip"
|
||||
android:layout_marginTop="-1dip"
|
||||
android:layout_width="wrap_content"
|
||||
android:textColor="@color/stat_label_text" />
|
||||
style="@style/StatsUnit" />
|
||||
</LinearLayout>
|
||||
</TableRow>
|
||||
|
||||
@@ -254,33 +181,18 @@ limitations under the License.
|
||||
<TableRow
|
||||
android:background="@color/stat_label_background">
|
||||
<TextView
|
||||
android:gravity="right"
|
||||
android:id="@+id/moving_time_register"
|
||||
android:layout_column="1"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="-9dip"
|
||||
android:layout_marginTop="-9dip"
|
||||
android:layout_span="2"
|
||||
android:layout_width="fill_parent"
|
||||
android:text="@string/unknown"
|
||||
android:textColor="@color/stat_label_text"
|
||||
android:textSize="40sp" />
|
||||
style="@style/StatsRegister" />
|
||||
<TextView
|
||||
android:background="@color/black"
|
||||
android:layout_column="3"
|
||||
android:layout_marginBottom="-9dip"
|
||||
android:layout_marginTop="-9dip"
|
||||
android:layout_width="5dip"
|
||||
android:textSize="40sp" />
|
||||
style="@style/StatsSpacer"
|
||||
android:layout_column="3"/>
|
||||
<TextView
|
||||
android:gravity="right"
|
||||
android:id="@+id/average_moving_speed_register"
|
||||
android:layout_column="4"
|
||||
android:layout_marginBottom="-9dip"
|
||||
android:layout_marginTop="-9dip"
|
||||
android:text="@string/unknown"
|
||||
android:textColor="@color/stat_label_text"
|
||||
android:textSize="40sp" />
|
||||
style="@style/StatsRegister" />
|
||||
<LinearLayout
|
||||
android:gravity="bottom"
|
||||
android:layout_column="5"
|
||||
@@ -289,24 +201,14 @@ limitations under the License.
|
||||
android:orientation="vertical">
|
||||
<TextView
|
||||
android:id="@+id/average_moving_speed_unit_label_top"
|
||||
android:gravity="bottom"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="-1dip"
|
||||
android:layout_marginTop="-1dip"
|
||||
android:layout_width="wrap_content"
|
||||
android:textColor="@color/stat_label_text" />
|
||||
style="@style/StatsUnit" />
|
||||
<TextView
|
||||
android:background="@color/black"
|
||||
style="@style/StatsDivider" />
|
||||
android:layout_height="3dip"
|
||||
android:layout_width="fill_parent" />
|
||||
<TextView
|
||||
android:id="@+id/average_moving_speed_unit_label_bottom"
|
||||
android:gravity="bottom"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="-1dip"
|
||||
android:layout_marginTop="-1dip"
|
||||
android:layout_width="wrap_content"
|
||||
android:textColor="@color/stat_label_text" />
|
||||
style="@style/StatsUnit" />
|
||||
</LinearLayout>
|
||||
</TableRow>
|
||||
|
||||
@@ -326,46 +228,24 @@ limitations under the License.
|
||||
<TableRow
|
||||
android:background="@color/stat_label_background">
|
||||
<TextView
|
||||
android:gravity="right"
|
||||
android:id="@+id/elevation_register"
|
||||
android:layout_column="1"
|
||||
android:layout_marginBottom="-9dip"
|
||||
android:layout_marginTop="-9dip"
|
||||
android:text="@string/unknown"
|
||||
android:textColor="@color/stat_label_text"
|
||||
android:textSize="40sp" />
|
||||
style="@style/StatsRegister" />
|
||||
<TextView
|
||||
android:gravity="left"
|
||||
android:id="@+id/elevation_unit_label"
|
||||
android:layout_column="2"
|
||||
android:layout_marginBottom="-9dip"
|
||||
android:layout_marginTop="-9dip"
|
||||
android:text="@string/feet"
|
||||
android:textColor="@color/stat_label_text"/>
|
||||
style="@style/StatsUnitSolo" />
|
||||
<TextView
|
||||
android:background="@color/black"
|
||||
android:layout_column="3"
|
||||
android:layout_marginBottom="-9dip"
|
||||
android:layout_marginTop="-9dip"
|
||||
android:layout_width="5dip"
|
||||
android:textSize="40sp" />
|
||||
style="@style/StatsSpacer"
|
||||
android:layout_column="3"/>
|
||||
<TextView
|
||||
android:gravity="right"
|
||||
android:id="@+id/elevation_gain_register"
|
||||
android:layout_column="4"
|
||||
android:layout_marginBottom="-9dip"
|
||||
android:layout_marginTop="-9dip"
|
||||
android:text="@string/unknown"
|
||||
android:textColor="@color/stat_label_text"
|
||||
android:textSize="40sp" />
|
||||
style="@style/StatsRegister" />
|
||||
<TextView
|
||||
android:gravity="right"
|
||||
android:id="@+id/elevation_gain_unit_label"
|
||||
android:layout_column="5"
|
||||
android:layout_marginBottom="-9dip"
|
||||
android:layout_marginTop="-9dip"
|
||||
android:text="@string/feet"
|
||||
android:textColor="@color/stat_label_text" />
|
||||
style="@style/StatsUnitSolo" />
|
||||
</TableRow>
|
||||
|
||||
<!-- Min and max elevation -->
|
||||
@@ -384,46 +264,24 @@ limitations under the License.
|
||||
<TableRow
|
||||
android:background="@color/stat_label_background">
|
||||
<TextView
|
||||
android:gravity="right"
|
||||
android:id="@+id/min_elevation_register"
|
||||
android:layout_column="1"
|
||||
android:layout_marginBottom="-9dip"
|
||||
android:layout_marginTop="-9dip"
|
||||
android:text="@string/unknown"
|
||||
android:textColor="@color/stat_label_text"
|
||||
android:textSize="40sp" />
|
||||
style="@style/StatsRegister" />
|
||||
<TextView
|
||||
android:gravity="left"
|
||||
android:id="@+id/min_elevation_unit_label"
|
||||
android:layout_column="2"
|
||||
android:layout_marginBottom="-9dip"
|
||||
android:layout_marginTop="-9dip"
|
||||
android:text="@string/feet"
|
||||
android:textColor="@color/stat_label_text" />
|
||||
style="@style/StatsUnitSolo" />
|
||||
<TextView
|
||||
android:background="@color/black"
|
||||
android:layout_column="3"
|
||||
android:layout_marginBottom="-9dip"
|
||||
android:layout_marginTop="-9dip"
|
||||
android:layout_width="5dip"
|
||||
android:textSize="40sp" />
|
||||
style="@style/StatsSpacer"
|
||||
android:layout_column="3"/>
|
||||
<TextView
|
||||
android:gravity="right"
|
||||
android:id="@+id/max_elevation_register"
|
||||
android:layout_column="4"
|
||||
android:layout_marginBottom="-9dip"
|
||||
android:layout_marginTop="-9dip"
|
||||
android:text="@string/unknown"
|
||||
android:textColor="@color/stat_label_text"
|
||||
android:textSize="40sp" />
|
||||
style="@style/StatsRegister" />
|
||||
<TextView
|
||||
android:gravity="right"
|
||||
android:id="@+id/max_elevation_unit_label"
|
||||
android:layout_column="5"
|
||||
android:layout_marginBottom="-9dip"
|
||||
android:layout_marginTop="-9dip"
|
||||
android:text="@string/feet"
|
||||
android:textColor="@color/stat_label_text" />
|
||||
style="@style/StatsUnitSolo" />
|
||||
</TableRow>
|
||||
|
||||
<!-- Min and max grade -->
|
||||
@@ -442,36 +300,18 @@ limitations under the License.
|
||||
<TableRow
|
||||
android:background="@color/stat_label_background">
|
||||
<TextView
|
||||
android:gravity="right"
|
||||
android:id="@+id/min_grade_register"
|
||||
android:layout_column="1"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="-9dip"
|
||||
android:layout_marginTop="-9dip"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_span="2"
|
||||
android:text="@string/unknown"
|
||||
android:textColor="@color/stat_label_text"
|
||||
android:textSize="40sp" />
|
||||
style="@style/StatsRegister" />
|
||||
<TextView
|
||||
android:background="@color/black"
|
||||
android:layout_column="3"
|
||||
android:layout_marginBottom="-9dip"
|
||||
android:layout_marginTop="-9dip"
|
||||
android:layout_width="5dip"
|
||||
android:textSize="40sp" />
|
||||
style="@style/StatsSpacer"
|
||||
android:layout_column="3"/>
|
||||
<TextView
|
||||
android:gravity="right"
|
||||
android:id="@+id/max_grade_register"
|
||||
android:layout_column="4"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="-9dip"
|
||||
android:layout_marginTop="-9dip"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_span="2"
|
||||
android:text="@string/unknown"
|
||||
android:textColor="@color/stat_label_text"
|
||||
android:textSize="40sp" />
|
||||
style="@style/StatsRegister" />
|
||||
</TableRow>
|
||||
|
||||
<!-- Latitude and Longitude -->
|
||||
@@ -488,36 +328,19 @@ limitations under the License.
|
||||
<TableRow
|
||||
android:background="@color/stat_label_background">
|
||||
<TextView
|
||||
android:gravity="right"
|
||||
android:id="@+id/latitude_register"
|
||||
android:layout_column="1"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="-5dip"
|
||||
android:layout_marginTop="-5dip"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_span="2"
|
||||
android:text="@string/unknown"
|
||||
android:textColor="@color/stat_label_text"
|
||||
android:textSize="25sp" />
|
||||
style="@style/StatsRegister.Small" />
|
||||
<TextView
|
||||
android:background="@color/black"
|
||||
style="@style/StatsSpacer"
|
||||
android:layout_column="3"
|
||||
android:layout_marginBottom="-9dip"
|
||||
android:layout_marginTop="-9dip"
|
||||
android:layout_width="5dip"
|
||||
android:textSize="25sp" />
|
||||
<TextView
|
||||
android:gravity="right"
|
||||
android:id="@+id/longitude_register"
|
||||
android:layout_column="4"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="-5dip"
|
||||
android:layout_marginTop="-5dip"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_span="2"
|
||||
android:text="@string/unknown"
|
||||
android:textColor="@color/stat_label_text"
|
||||
android:textSize="25sp" />
|
||||
style="@style/StatsRegister.Small" />
|
||||
</TableRow>
|
||||
|
||||
</TableLayout>
|
||||
|
||||
@@ -22,10 +22,14 @@
|
||||
android:title="@string/settings"/>
|
||||
|
||||
<item android:id="@+id/menu_aggregated_stats"
|
||||
android:icon="@android:drawable/ic_menu_info_details"
|
||||
android:orderInCategory="1002"
|
||||
android:title="@string/aggregated_stats"/>
|
||||
|
||||
<item android:id="@+id/menu_sensor_state"
|
||||
android:icon="@drawable/menu_sensor_status"
|
||||
android:orderInCategory="1000"
|
||||
android:title="@string/sensor_state"/>
|
||||
|
||||
<item android:id="@+id/menu_help"
|
||||
android:icon="@android:drawable/ic_menu_info_details"
|
||||
android:orderInCategory="1003"
|
||||
|
||||
@@ -184,9 +184,6 @@ limitations under the License.
|
||||
<string name="settings_share_url_only_summary_on">Beim teilen mit Freunden wird nur die Karten URL gesendet.</string>
|
||||
<string name="settings_share_url_only_summary_off">Beim teilen mit Freunden wird der GPS Track selbst gesendet.</string>
|
||||
|
||||
<string name="settings_signal_sampling_frequency">Empfangsstärke Aufzeichnungsfrequenz</string>
|
||||
<string name="settings_signal_sampling_frequency_summary">Dauer zwischen zwei Aufzeichnungen der Telefonempfangsstärke.</string>
|
||||
|
||||
<string name="settings_split_frequency">Zerteilungs Frequenz</string>
|
||||
<string name="settings_split_frequency_summary">Längste Dauer oder Entfernung nach der automatisch ein Marker eingefügt wird.</string>
|
||||
<string name="pace_label">Tempo</string>
|
||||
|
||||
@@ -187,9 +187,6 @@ limitations under the License.
|
||||
<string name="settings_share_url_only_summary_on">Sólo el URL del mapa será enviado al compartir</string>
|
||||
<string name="settings_share_url_only_summary_off">Los contenidos de la pista también serán incluídos al compartir</string>
|
||||
|
||||
<string name="settings_signal_sampling_frequency">Frecuencia de medición de señal</string>
|
||||
<string name="settings_signal_sampling_frequency_summary">Tiempo entre grabaciones de la intensidad de la señal del teléfono</string>
|
||||
|
||||
<string name="settings_split_frequency">Dividir frecuencia</string>
|
||||
<string name="settings_split_frequency_summary">Tiempo o distancia máxima para insertar una nueva marca de división</string>
|
||||
<string name="pace_label">Paso</string>
|
||||
|
||||
@@ -187,9 +187,6 @@ limitations under the License.
|
||||
<string name="settings_share_url_only_summary_on">Seule l\'adresse URL de la carte sera envoyée lors du partage</string>
|
||||
<string name="settings_share_url_only_summary_off">Le contenu du parcours sera également inclus lors du partage</string>
|
||||
|
||||
<string name="settings_signal_sampling_frequency">Échantillonnage du signal</string>
|
||||
<string name="settings_signal_sampling_frequency_summary">Intervalle de temps entre deux enregistrements de la force du signal</string>
|
||||
|
||||
<string name="settings_split_frequency">Fréquence de séparation</string>
|
||||
<string name="settings_split_frequency_summary">Temps ou distance minimum avant l\'insertion d\'un marqueur de séparation</string>
|
||||
<string name="pace_label">Rythme</string>
|
||||
|
||||
@@ -193,9 +193,6 @@ limitations under the License.
|
||||
<string name="settings_share_url_only_summary_on">Solo l\'URL della mappa sarà inviata quando condividi un percorso</string>
|
||||
<string name="settings_share_url_only_summary_off">Anche il contenuto del percorso sarà inviato quando condividi un persorso</string>
|
||||
|
||||
<string name="settings_signal_sampling_frequency">Frequenza di campionamento</string>
|
||||
<string name="settings_signal_sampling_frequency_summary">Tempo fra due registrazioni della qualità del segnale cellulare</string>
|
||||
|
||||
<string name="settings_split_frequency">Frequenza di divisione</string>
|
||||
<string name="settings_split_frequency_summary">Tempo o distanza massima dopo di cui il percorso verrà diviso</string>
|
||||
<string name="pace_label">Andatura</string>
|
||||
|
||||
@@ -194,9 +194,6 @@ limitations under the License.
|
||||
<string name="settings_share_url_only_summary_on">共有時にマップのURLのみ送信します</string>
|
||||
<string name="settings_share_url_only_summary_off">共有時にトラックのコンテントが含まれます</string>
|
||||
|
||||
<string name="settings_signal_sampling_frequency">信号サンプリング周波数</string>
|
||||
<string name="settings_signal_sampling_frequency_summary">端末の信号強度記録の時間間隔</string>
|
||||
|
||||
<string name="settings_split_frequency">分割頻度</string>
|
||||
<string name="settings_split_frequency_summary">分割マーカを挿入する時間または距離の間隔</string>
|
||||
<string name="pace_label">ペース</string>
|
||||
@@ -384,12 +381,4 @@ limitations under the License.
|
||||
<!-- Check Units -->
|
||||
<string name="check_units_title">計測単位についてのご注意</string>
|
||||
<string name="check_units_message">デフォルトの単位はメートルです.設定を変更しますか?</string>
|
||||
|
||||
<!-- Signal Strength -->
|
||||
<string name="error_rate"> 誤り率: %1$d</string>
|
||||
<string name="signal_to_noise_ratio"> S/N比: %1$d</string>
|
||||
<string name="ecio"> Ec/Io比: %1$.1f dB</string>
|
||||
<string name="gsm_strength">GSM 強度: %1$d</string>
|
||||
<string name="cdma_strength">CDMA 強度: %1$d dBm</string>
|
||||
<string name="evdo_strength">EVDO 強度: %1$d dBm</string>
|
||||
</resources>
|
||||
|
||||
@@ -195,9 +195,6 @@ limitations under the License.
|
||||
<string name="settings_share_url_only_summary_on">Tylko odnośnik do mapy będzie wysyłany podczas dzielenia się</string>
|
||||
<string name="settings_share_url_only_summary_off">Zawartość trasy będzie również przesyłana</string>
|
||||
|
||||
<string name="settings_signal_sampling_frequency">Częstotliowść próbkowania sygnału</string>
|
||||
<string name="settings_signal_sampling_frequency_summary">Czas między dwoma zapisami siły sygnału telefonu</string>
|
||||
|
||||
<string name="settings_split_frequency">Częstotliwość rozdzielania</string>
|
||||
<string name="settings_split_frequency_summary">Maksymalny czas lub odległość po którym wstawiony zostanie znacznik rozdzielenia</string>
|
||||
|
||||
@@ -416,12 +413,4 @@ limitations under the License.
|
||||
<!-- Check Units -->
|
||||
<string name="check_units_title">Jednostki miary</string>
|
||||
<string name="check_units_message">Domyślnie używane są jednostki metryczne. Chcesz to zmienić?</string>
|
||||
|
||||
<!-- Signal Strength -->
|
||||
<string name="error_rate"> Poziom błędów: %1$d</string>
|
||||
<string name="signal_to_noise_ratio"> Stosunek sygnału do szumu: %1$d</string>
|
||||
<string name="ecio"> Ec/lo: %1$.1f dB</string>
|
||||
<string name="gsm_strength">Siła GSM: %1$d</string>
|
||||
<string name="cdma_strength">Siła CDMA: %1$d dBm</string>
|
||||
<string name="evdo_strength">Siła EVDO: %1$d dBm</string>
|
||||
</resources>
|
||||
|
||||
@@ -195,9 +195,6 @@ limitations under the License.
|
||||
<string name="settings_share_url_only_summary_on">Bara länken till kartan kommer att skickas vid delning</string>
|
||||
<string name="settings_share_url_only_summary_off">Innehållet i spåret kommer också att inkluderas vid delning</string>
|
||||
|
||||
<string name="settings_signal_sampling_frequency">Signalprovsfrekvens</string>
|
||||
<string name="settings_signal_sampling_frequency_summary">Tid mellan två inspelningar av telefonens signalstyrka</string>
|
||||
|
||||
<string name="settings_split_frequency">Delningsfrekvens</string>
|
||||
<string name="settings_split_frequency_summary">Maximala tiden eller distansen varefter en ny delningsmarkör kommer infogas</string>
|
||||
<string name="pace_label">Tempo</string>
|
||||
@@ -383,12 +380,4 @@ limitations under the License.
|
||||
<!-- Check Units -->
|
||||
<string name="check_units_title">Mätenheter</string>
|
||||
<string name="check_units_message">Som standard är enheterna metriska. Vill du ändra den inställningen?</string>
|
||||
|
||||
<!-- Signal Strength -->
|
||||
<string name="error_rate"> Felfrekvens: %1$d</string>
|
||||
<string name="signal_to_noise_ratio"> Signal / brus-förhållande: %1$d</string>
|
||||
<string name="ecio"> Ec/lo: %1$.1f dB</string>
|
||||
<string name="gsm_strength">GSM-styrka: %1$d</string>
|
||||
<string name="cdma_strength">CDMA-styrka: %1$d dBm</string>
|
||||
<string name="evdo_strength">EVDO-styrka: %1$d dBm</string>
|
||||
</resources>
|
||||
|
||||
@@ -201,9 +201,6 @@ limitations under the License.
|
||||
<string name="settings_share_url_only_summary_on">在分享时只发送地图的 URL</string>
|
||||
<string name="settings_share_url_only_summary_off">在分享时也包括轨迹的内容</string>
|
||||
|
||||
<string name="settings_signal_sampling_frequency">信号采样频率</string>
|
||||
<string name="settings_signal_sampling_frequency_summary">记录电话信号强度的时间间隔</string>
|
||||
|
||||
<string name="settings_split_frequency">切割频度</string>
|
||||
<string name="settings_split_frequency_summary">插入新切割标记所需要达到的最大时间或距离</string>
|
||||
|
||||
@@ -451,14 +448,6 @@ limitations under the License.
|
||||
<string name="check_units_title">测量单位提示</string>
|
||||
<string name="check_units_message">默认单位均为公制. 你想要修改此设置吗?</string>
|
||||
|
||||
<!-- Signal Strength -->
|
||||
<string name="error_rate"> 错误率: %1$d</string>
|
||||
<string name="signal_to_noise_ratio"> 信噪比: %1$d</string>
|
||||
<string name="ecio"> Ec/lo: %1$.1f dB</string>
|
||||
<string name="gsm_strength">GSM 强度 %1$d</string>
|
||||
<string name="cdma_strength">CDMA 强度 %1$d dBm</string>
|
||||
<string name="evdo_strength">EVDO 强度 %1$d dBm</string>
|
||||
|
||||
<!-- Fake preference keys - never saved, but show options in the preferences screen -->
|
||||
<string name="method_bluetooth">蓝牙</string>
|
||||
<string name="bluetooth_options">蓝牙设置</string>
|
||||
@@ -467,12 +456,6 @@ limitations under the License.
|
||||
|
||||
<string name="sensor_options">感应器选项</string>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- Bluetooth Sensor -->
|
||||
<string name="bluetooth_connected">连接到 %s</string>
|
||||
<string name="bluetooth_connecting">蓝牙感应器连接中 ...</string>
|
||||
|
||||
@@ -390,4 +390,16 @@ limitations under the License.
|
||||
<item>CSV</item>
|
||||
<item>TCX</item>
|
||||
</array>
|
||||
|
||||
<array name="sensor_type_options">
|
||||
<item>None</item>
|
||||
<item>Zephyr Bluetooth</item>
|
||||
</array>
|
||||
|
||||
<!-- DO NOT TRANSLATE -->
|
||||
<array name="sensor_type_values">
|
||||
<item>@string/none</item>
|
||||
<item>@string/zephyr_sensor_type</item>
|
||||
</array>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -15,17 +15,22 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<resources>
|
||||
<color name="gold">#FFffd700</color>
|
||||
<color name="white">#FFFFFFFF</color>
|
||||
<color name="black">#FF000000</color>
|
||||
<color name="lightblue">#FF00FFFF</color>
|
||||
<color name="blue">#FF0000FF</color>
|
||||
<color name="blue_transparent">#400000FF</color>
|
||||
<color name="red">#FFFF0000</color>
|
||||
<color name="green">#FF00AA00</color>
|
||||
<color name="gray">#FFAAAAAA</color>
|
||||
<color name="darkgray">#FF444444</color>
|
||||
<color name="gold">#FFffd700</color>
|
||||
<color name="gray">#FFAAAAAA</color>
|
||||
<color name="green">#FF00AA00</color>
|
||||
<color name="lightblue">#FF00FFFF</color>
|
||||
<color name="opaque_shadow">#70000000</color>
|
||||
<color name="purple">#FF401465</color>
|
||||
<color name="purple_transparent">#40401465</color>
|
||||
<color name="red">#FFFF0000</color>
|
||||
<color name="red_transparent">#40FF0000</color>
|
||||
<color name="stat_label_background">#FFF0F0F0</color>
|
||||
<color name="stat_label_text">#FF0F0F0F</color>
|
||||
<color name="white">#FFFFFFFF</color>
|
||||
<color name="yellow">#FFF8FF00</color>
|
||||
<color name="yellow_transparent">#40F8FF00</color>
|
||||
</resources>
|
||||
|
||||
@@ -33,10 +33,8 @@ limitations under the License.
|
||||
<string name="send_stats_and_points_key">sendStatsAndPoints</string>
|
||||
<string name="send_to_docs_key">sendToDocs</string>
|
||||
<string name="send_to_my_maps_key">sendToMyMaps</string>
|
||||
<string name="sensor_id_key">sensorId</string>
|
||||
<string name="sensor_type_key">sensorType</string>
|
||||
<string name="share_url_only_key">shareUrlOnly</string>
|
||||
<string name="signal_sampling_frequency_key">signalSamplingFrequency</string>
|
||||
<string name="split_frequency_key">splitFrequency</string>
|
||||
<string name="timestamp_track_name_key">timestampTrackName</string>
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ limitations under the License.
|
||||
<string name="choose_track_message">Please select the track to view</string>
|
||||
<string name="current_track">Current track</string>
|
||||
<string name="current_segment">Last segment</string>
|
||||
<string name="sensor_state">Sensor State</string>
|
||||
<string name="aggregated_stats">Aggregated Statistics</string>
|
||||
|
||||
<!-- Error messages -->
|
||||
@@ -201,9 +202,6 @@ limitations under the License.
|
||||
<string name="settings_share_url_only_summary_on">Only the URL of the map will be sent when sharing</string>
|
||||
<string name="settings_share_url_only_summary_off">The contents of the track will also be included when sharing</string>
|
||||
|
||||
<string name="settings_signal_sampling_frequency">Signal sampling frequency</string>
|
||||
<string name="settings_signal_sampling_frequency_summary">Time between two recordings of the phone\'s signal strength</string>
|
||||
|
||||
<string name="settings_split_frequency">Split frequency</string>
|
||||
<string name="settings_split_frequency_summary">Maximum time or distance after which a new split marker will be inserted</string>
|
||||
|
||||
@@ -447,14 +445,6 @@ limitations under the License.
|
||||
<string name="check_units_title">Units of Measure Notice</string>
|
||||
<string name="check_units_message">By default units are metric. Would you like to change that setting?</string>
|
||||
|
||||
<!-- Signal Strength -->
|
||||
<string name="error_rate"> Error Rate: %1$d</string>
|
||||
<string name="signal_to_noise_ratio"> Signal to Noise Ratio: %1$d</string>
|
||||
<string name="ecio"> Ec/lo: %1$.1f dB</string>
|
||||
<string name="gsm_strength">GSM Strength: %1$d</string>
|
||||
<string name="cdma_strength">CDMA Strength: %1$d dBm</string>
|
||||
<string name="evdo_strength">EVDO Strength: %1$d dBm</string>
|
||||
|
||||
<!-- Fake preference keys - never saved, but show options in the preferences screen -->
|
||||
<string name="method_bluetooth">Bluetooth</string>
|
||||
<string name="bluetooth_options">Bluetooth options</string>
|
||||
@@ -465,9 +455,7 @@ limitations under the License.
|
||||
|
||||
<!-- Sensor Types => DO NOT TRANSLATE -->
|
||||
<string name="none">NONE</string>
|
||||
<string name="ant_sensor_type">ANT</string>
|
||||
<string name="srm_sensor_type">SRM</string>
|
||||
<string name="athlosoft_sensor_type">ATHLOSOFT</string>
|
||||
<string name="zephyr_sensor_type">ZEPHYR</string>
|
||||
|
||||
<!-- Bluetooth Sensor -->
|
||||
<string name="bluetooth_connected">Connected to %s</string>
|
||||
@@ -478,5 +466,20 @@ limitations under the License.
|
||||
<string name="sensor_data_time">Sensor Data Time</string>
|
||||
<string name="power_meter_enabled">Power meter enabled</string>
|
||||
<string name="heart_rate_monitor_enabled">Heart rate monitor enabled</string>
|
||||
<string name="no_sensor_manager">No Sensor Manager</string>
|
||||
<string name="enabled">Enabled</string>
|
||||
<string name="connecting">Connecting</string>
|
||||
<string name="connected">Connected</string>
|
||||
<string name="disconnected">Disconnected</string>
|
||||
<string name="no_sensor_service">No Sensor Service</string>
|
||||
<string name="searching">Searching</string>
|
||||
<string name="sending">Sending</string>
|
||||
|
||||
<!-- Manifest description (not seen inside the app) -->
|
||||
<string name="notification_permission_label">receive track recording notifications</string>
|
||||
<string name="read_tracks_permission_label">read recorded track data</string>
|
||||
<string name="write_tracks_permission_label">write recorded track data, start/stop recording tracks</string>
|
||||
<string name="notification_permission_description">Be notified when a track starts or stops being recorded.</string>
|
||||
<string name="read_tracks_permission_description">Be able to read track data, such as points and waypoints.</string>
|
||||
<string name="write_tracks_permission_description">Be able to write track data, such as starting recording or adding waypoints.</string>
|
||||
</resources>
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright 2010 Google Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<resources>
|
||||
<!-- The style for the unit on the statistics activity. -->
|
||||
<style name="StatsUnit" parent="@android:Widget.TextView">
|
||||
<item name="android:gravity">bottom</item>
|
||||
<item name="android:layout_height">wrap_content</item>
|
||||
<item name="android:layout_marginBottom">-2dip</item>
|
||||
<item name="android:layout_marginTop">-2dip</item>
|
||||
<item name="android:layout_width">wrap_content</item>
|
||||
<item name="android:textColor">@color/stat_label_text</item>
|
||||
</style>
|
||||
|
||||
<!-- The style for the unit on the statistics activity where there is only one string. -->
|
||||
<style name="StatsUnitSolo" parent="@android:Widget.TextView">
|
||||
<item name="android:gravity">right</item>
|
||||
<item name="android:layout_marginBottom">-9dip</item>
|
||||
<item name="android:layout_marginTop">-9dip</item>
|
||||
<item name="android:textColor">@color/stat_label_text</item>
|
||||
</style>
|
||||
|
||||
<!-- The style for a text view for displaying a value on the statistics activity. -->
|
||||
<style name="StatsRegister" parent="@android:Widget.TextView">
|
||||
<item name="android:gravity">right</item>
|
||||
<item name="android:layout_marginBottom">-9dip</item>
|
||||
<item name="android:layout_marginTop">-9dip</item>
|
||||
<item name="android:text">@string/unknown</item>
|
||||
<item name="android:textColor">@color/stat_label_text</item>
|
||||
<item name="android:textSize">40sp</item>
|
||||
</style>
|
||||
|
||||
<!-- The style for a text view for displaying a large value on the statistics activity. -->
|
||||
<style name="StatsRegister.Big">
|
||||
<item name="android:layout_marginBottom">-13dip</item>
|
||||
<item name="android:layout_marginTop">-13dip</item>
|
||||
<item name="android:textSize">50sp</item>
|
||||
</style>
|
||||
|
||||
<!-- The style for a text view for displaying a small value on the statistics activity. -->
|
||||
<style name="StatsRegister.Small">
|
||||
<item name="android:layout_height">wrap_content</item>
|
||||
<item name="android:layout_marginBottom">-5dip</item>
|
||||
<item name="android:layout_marginTop">-5dip</item>
|
||||
<item name="android:layout_width">fill_parent</item>
|
||||
<item name="android:textSize">25sp</item>
|
||||
</style>
|
||||
|
||||
<!-- The style for a view which divides two columns in the statistics activity. -->
|
||||
<style name="StatsSpacer" parent="@android:Widget.TextView">
|
||||
<item name="android:background">@color/black</item>
|
||||
<item name="android:layout_marginBottom">-9dip</item>
|
||||
<item name="android:layout_marginTop">-9dip</item>
|
||||
<item name="android:layout_width">5dip</item>
|
||||
<item name="android:textSize">40sp</item>
|
||||
</style>
|
||||
|
||||
<!-- The style for a view which divides the numerator and denominator of the units on the statistics activity. -->
|
||||
<style name="StatsDivider" parent="@android:Widget.TextView">
|
||||
<item name="android:background">@color/black</item>
|
||||
<item name="android:layout_height">3dip</item>
|
||||
<item name="android:layout_width">fill_parent</item>
|
||||
</style>
|
||||
</resources>
|
||||
@@ -84,14 +84,6 @@ limitations under the License.
|
||||
android:entryValues="@array/min_required_accuracy_values"
|
||||
android:defaultValue="200" />
|
||||
|
||||
<com.google.android.apps.mytracks.IntegerListPreference
|
||||
android:key="@string/signal_sampling_frequency_key"
|
||||
android:title="@string/settings_signal_sampling_frequency"
|
||||
android:summary="@string/settings_signal_sampling_frequency_summary"
|
||||
android:entries="@array/task_frequency_options"
|
||||
android:entryValues="@array/task_frequency_values"
|
||||
android:defaultValue="-1" />
|
||||
|
||||
<com.google.android.apps.mytracks.IntegerListPreference
|
||||
android:key="@string/auto_resume_track_timeout_key"
|
||||
android:title="@string/settings_auto_resume_track_timeout"
|
||||
@@ -109,6 +101,29 @@ limitations under the License.
|
||||
|
||||
</PreferenceScreen>
|
||||
|
||||
<!-- Sensors -->
|
||||
<PreferenceScreen android:title="@string/sensor_options">
|
||||
<ListPreference android:key="@string/sensor_type_key"
|
||||
android:title="@string/settings_sensor_type"
|
||||
android:summary="@string/settings_sensor_type_summary"
|
||||
android:entries="@array/sensor_type_options"
|
||||
android:entryValues="@array/sensor_type_values"
|
||||
android:defaultValue="@string/none"/>
|
||||
|
||||
<!-- Bluetooth -->
|
||||
<PreferenceCategory android:title="@string/bluetooth_options">
|
||||
<ListPreference android:key="@string/bluetooth_sensor_key"
|
||||
android:title="@string/bluetooth_sensor_title"
|
||||
android:summary="@string/bluetooth_sensor_summary"
|
||||
android:defaultValue="any" />
|
||||
|
||||
<Preference android:key="@string/bluetooth_pairing_key"
|
||||
android:title="@string/bluetooth_pairing"
|
||||
android:summary="@string/bluetooth_pairing_summary"
|
||||
android:persistent="false" />
|
||||
</PreferenceCategory>
|
||||
</PreferenceScreen>
|
||||
|
||||
<!-- Sharing settings -->
|
||||
<PreferenceScreen android:title="@string/settings_sharing">
|
||||
<CheckBoxPreference
|
||||
|
||||
@@ -16,11 +16,14 @@
|
||||
package com.google.android.apps.mytracks;
|
||||
|
||||
import com.google.android.apps.mytracks.ChartView.Mode;
|
||||
import com.google.android.apps.mytracks.content.MyTracksLocation;
|
||||
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
|
||||
import com.google.android.apps.mytracks.content.Sensor;
|
||||
import com.google.android.apps.mytracks.content.Track;
|
||||
import com.google.android.apps.mytracks.content.TrackPointsColumns;
|
||||
import com.google.android.apps.mytracks.content.Waypoint;
|
||||
import com.google.android.apps.mytracks.content.WaypointsColumns;
|
||||
import com.google.android.apps.mytracks.content.Sensor.SensorDataSet;
|
||||
import com.google.android.apps.mytracks.services.StatusAnnouncerFactory;
|
||||
import com.google.android.apps.mytracks.stats.DoubleBuffer;
|
||||
import com.google.android.apps.mytracks.stats.TripStatisticsBuilder;
|
||||
@@ -178,12 +181,12 @@ public class ChartActivity extends Activity implements
|
||||
cursor.getColumnIndexOrThrow(TrackPointsColumns._ID);
|
||||
ArrayList<double[]> data = new ArrayList<double[]>();
|
||||
// Need two locations so we can keep track of the last location.
|
||||
Location location = new Location("");
|
||||
Location location = new MyTracksLocation("");
|
||||
do {
|
||||
lastSeenLocationId = cursor.getLong(idColumnIdx);
|
||||
providerUtils.fillLocation(cursor, location);
|
||||
if (MyTracksUtils.isValidLocation(location)) {
|
||||
double[] point = new double[3];
|
||||
double[] point = new double[6];
|
||||
location = getDataPoint(location, track, point);
|
||||
data.add(point);
|
||||
}
|
||||
@@ -464,10 +467,14 @@ public class ChartActivity extends Activity implements
|
||||
|
||||
/**
|
||||
* Given a location, creates a new data point for the chart. A data point is
|
||||
* an array double[2], where:
|
||||
* an array double[3 or 6], where:
|
||||
* data[0] = the time or distance
|
||||
* data[1] = the elevation
|
||||
* data[2] = the speed
|
||||
* and possibly:
|
||||
* data[3] = power
|
||||
* data[4] = cadence
|
||||
* data[5] = heart rate
|
||||
*
|
||||
* This must be called in order for each point.
|
||||
*
|
||||
@@ -477,6 +484,35 @@ public class ChartActivity extends Activity implements
|
||||
* @return the previous location, now available for reuse
|
||||
*/
|
||||
private Location getDataPoint(Location location, Track track, double[] result) {
|
||||
if (location instanceof MyTracksLocation &&
|
||||
((MyTracksLocation) location).getSensorDataSet() != null) {
|
||||
SensorDataSet sensorData = ((MyTracksLocation) location).getSensorDataSet();
|
||||
if (sensorData.hasPower()
|
||||
&& sensorData.getPower().getState() == Sensor.SensorState.SENDING
|
||||
&& sensorData.getPower().hasValue()) {
|
||||
result[3] = sensorData.getPower().getValue();
|
||||
} else {
|
||||
result[3] = Double.NaN;
|
||||
}
|
||||
if (sensorData.hasCadence()
|
||||
&& sensorData.getCadence().getState() == Sensor.SensorState.SENDING
|
||||
&& sensorData.getCadence().hasValue()) {
|
||||
result[4] = sensorData.getCadence().getValue();
|
||||
} else {
|
||||
result[4] = Double.NaN;
|
||||
}
|
||||
if (sensorData.hasHeartRate()
|
||||
&& sensorData.getHeartRate().getState() == Sensor.SensorState.SENDING
|
||||
&& sensorData.getHeartRate().hasValue()) {
|
||||
result[5] = sensorData.getHeartRate().getValue();
|
||||
} else {
|
||||
result[5] = Double.NaN;
|
||||
}
|
||||
} else {
|
||||
result[3] = Double.NaN;
|
||||
result[4] = Double.NaN;
|
||||
result[5] = Double.NaN;
|
||||
}
|
||||
switch (mode) {
|
||||
case BY_DISTANCE:
|
||||
result[0] = profileLength;
|
||||
@@ -529,7 +565,7 @@ public class ChartActivity extends Activity implements
|
||||
|
||||
if (oldLastLocation == null) {
|
||||
// No previous location, but return a blank one for reuse
|
||||
return new Location("");
|
||||
return new MyTracksLocation("");
|
||||
}
|
||||
|
||||
return oldLastLocation;
|
||||
@@ -576,7 +612,7 @@ public class ChartActivity extends Activity implements
|
||||
final ArrayList<double[]> theData = new ArrayList<double[]>();
|
||||
int points = 0;
|
||||
// Need two locations so we can keep track of the last location.
|
||||
Location location = new Location("");
|
||||
Location location = new MyTracksLocation("");
|
||||
while (lastLocationRead < track.getStopId()) {
|
||||
cursor = providerUtils.getLocationsCursor(
|
||||
selectedTrackId, lastLocationRead, bufferSize, false);
|
||||
@@ -592,7 +628,8 @@ public class ChartActivity extends Activity implements
|
||||
if (MyTracksUtils.isValidLocation(location)) {
|
||||
lastLocationRead = lastSeenLocationId =
|
||||
cursor.getLong(idColumnIdx);
|
||||
double[] point = new double[3];
|
||||
// TODO Can we be smarter about choosing 3 or 6 entries?
|
||||
double[] point = new double[6];
|
||||
location = getDataPoint(location, track, point);
|
||||
if (points % chartSamplingFrequency == 0) {
|
||||
theData.add(point);
|
||||
|
||||
@@ -35,8 +35,7 @@ import android.widget.RadioGroup;
|
||||
*/
|
||||
public class ChartSettingsDialog extends Dialog {
|
||||
private RadioButton distance;
|
||||
private CheckBox elevation;
|
||||
private CheckBox speed;
|
||||
private CheckBox[] series;
|
||||
|
||||
public ChartSettingsDialog(Context context) {
|
||||
super(context);
|
||||
@@ -61,8 +60,18 @@ public class ChartSettingsDialog extends Dialog {
|
||||
});
|
||||
|
||||
distance = (RadioButton) findViewById(R.id.chart_settings_by_distance);
|
||||
elevation = (CheckBox) findViewById(R.id.chart_settings_elevation);
|
||||
speed = (CheckBox) findViewById(R.id.chart_settings_speed);
|
||||
|
||||
series = new CheckBox[ChartView.NUM_SERIES];
|
||||
series[ChartView.ELEVATION_SERIES] =
|
||||
(CheckBox) findViewById(R.id.chart_settings_elevation);
|
||||
series[ChartView.SPEED_SERIES] =
|
||||
(CheckBox) findViewById(R.id.chart_settings_speed);
|
||||
series[ChartView.POWER_SERIES] =
|
||||
(CheckBox) findViewById(R.id.chart_settings_power);
|
||||
series[ChartView.CADENCE_SERIES] =
|
||||
(CheckBox) findViewById(R.id.chart_settings_cadence);
|
||||
series[ChartView.HEART_RATE_SERIES] =
|
||||
(CheckBox) findViewById(R.id.chart_settings_heart_rate);
|
||||
}
|
||||
|
||||
public void setup(ChartActivity chart) {
|
||||
@@ -74,8 +83,9 @@ public class ChartSettingsDialog extends Dialog {
|
||||
rd.check(chart.getMode() == Mode.BY_DISTANCE
|
||||
? R.id.chart_settings_by_distance
|
||||
: R.id.chart_settings_by_time);
|
||||
elevation.setChecked(chart.isSeriesEnabled(ChartView.ELEVATION_SERIES));
|
||||
speed.setChecked(chart.isSeriesEnabled(ChartView.SPEED_SERIES));
|
||||
for (int i = 0; i < ChartView.NUM_SERIES; i++) {
|
||||
series[i].setChecked(chart.isSeriesEnabled(i));
|
||||
}
|
||||
}
|
||||
|
||||
private void handleOk() {
|
||||
@@ -83,8 +93,9 @@ public class ChartSettingsDialog extends Dialog {
|
||||
chart.setMode(distance.isChecked() ? Mode.BY_DISTANCE : Mode.BY_TIME);
|
||||
|
||||
// TODO: check that something is visible.
|
||||
chart.setSeriesEnabled(ChartView.ELEVATION_SERIES, elevation.isChecked());
|
||||
chart.setSeriesEnabled(ChartView.SPEED_SERIES, speed.isChecked());
|
||||
for (int i = 0; i < ChartView.NUM_SERIES; i++) {
|
||||
chart.setSeriesEnabled(i, series[i].isChecked());
|
||||
}
|
||||
|
||||
dismiss();
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@ public class ChartValueSeries {
|
||||
private double min = 0;
|
||||
private double max = 1;
|
||||
private int effectiveMax = 0;
|
||||
private int absoluteMax = Integer.MIN_VALUE;
|
||||
private int effectiveMin = 0;
|
||||
private double spread = 0;
|
||||
private boolean enabled = true;
|
||||
@@ -131,7 +132,7 @@ public class ChartValueSeries {
|
||||
if (min < 0) {
|
||||
effectiveMin -= rounding;
|
||||
}
|
||||
spread = effectiveMax - effectiveMin;
|
||||
spread = getMax() - effectiveMin;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -139,7 +140,7 @@ public class ChartValueSeries {
|
||||
*/
|
||||
public int getMaxLabelLength() {
|
||||
String minS = format.format(effectiveMin);
|
||||
String maxS = format.format(effectiveMax);
|
||||
String maxS = format.format(getMax());
|
||||
return Math.max(minS.length(), maxS.length());
|
||||
}
|
||||
|
||||
@@ -151,10 +152,16 @@ public class ChartValueSeries {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The rounded up maximum value
|
||||
* @return The minimum of the rounded up max value and the effective max.
|
||||
*/
|
||||
public int getMax() {
|
||||
return effectiveMax;
|
||||
// Return the effective max if no absolute is set
|
||||
// or the effective max is less than the absolute.
|
||||
if ((absoluteMax == Integer.MIN_VALUE) || (effectiveMax < absoluteMax)) {
|
||||
return effectiveMax;
|
||||
} else {
|
||||
return absoluteMax;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -211,4 +218,16 @@ public class ChartValueSeries {
|
||||
public void setEnabled(boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public int getAbsoluteMax() {
|
||||
return absoluteMax;
|
||||
}
|
||||
|
||||
public void setAbsoluteMax(int absoluteMax) {
|
||||
this.absoluteMax = absoluteMax;
|
||||
}
|
||||
|
||||
public boolean hasData() {
|
||||
return monitor.hasData();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,7 +87,10 @@ public class ChartView extends View {
|
||||
*/
|
||||
public static final int ELEVATION_SERIES = 0;
|
||||
public static final int SPEED_SERIES = 1;
|
||||
public static final int NUM_SERIES = 2;
|
||||
public static final int POWER_SERIES = 2;
|
||||
public static final int CADENCE_SERIES = 3;
|
||||
public static final int HEART_RATE_SERIES = 4;
|
||||
public static final int NUM_SERIES = 5;
|
||||
private ChartValueSeries[] series;
|
||||
|
||||
private final ExtremityMonitor xMonitor = new ExtremityMonitor();
|
||||
@@ -172,38 +175,44 @@ public class ChartView extends View {
|
||||
series = new ChartValueSeries[NUM_SERIES];
|
||||
|
||||
// Create the paints
|
||||
Paint fillPaint1 = new Paint();
|
||||
fillPaint1.setStyle(Style.FILL);
|
||||
fillPaint1.setColor(context.getResources().getColor(R.color.green));
|
||||
fillPaint1.setAntiAlias(true);
|
||||
|
||||
Paint fillPaint2 = new Paint();
|
||||
fillPaint2.setStyle(Style.FILL);
|
||||
fillPaint2.setColor(
|
||||
context.getResources().getColor(R.color.blue_transparent));
|
||||
fillPaint2.setAntiAlias(true);
|
||||
|
||||
Paint strokePaint = new Paint();
|
||||
strokePaint.setStyle(Style.STROKE);
|
||||
strokePaint.setColor(context.getResources().getColor(R.color.blue));
|
||||
strokePaint.setAntiAlias(true);
|
||||
Paint fillPaint = new Paint();
|
||||
fillPaint.setStyle(Style.FILL);
|
||||
fillPaint.setColor(context.getResources().getColor(R.color.green));
|
||||
fillPaint.setAntiAlias(true);
|
||||
|
||||
// Create the value series
|
||||
series[ELEVATION_SERIES] =
|
||||
new ChartValueSeries(context,
|
||||
"###,###",
|
||||
fillPaint1,
|
||||
fillPaint,
|
||||
null,
|
||||
100,
|
||||
R.string.elevation);
|
||||
|
||||
series[SPEED_SERIES] =
|
||||
new ChartValueSeries(context,
|
||||
"###,###.0",
|
||||
fillPaint2,
|
||||
strokePaint,
|
||||
5,
|
||||
R.string.speed);
|
||||
series[SPEED_SERIES] = getSeries(context, R.color.blue_transparent,
|
||||
R.color.blue, "###,###.0", R.string.speed);
|
||||
series[POWER_SERIES] = getSeries(context, R.color.red_transparent,
|
||||
R.color.red, "###,###", R.string.power);
|
||||
series[POWER_SERIES].setAbsoluteMax(1500);
|
||||
series[CADENCE_SERIES] = getSeries(context, R.color.purple_transparent,
|
||||
R.color.purple, "###,###", R.string.cadence);
|
||||
series[HEART_RATE_SERIES] = getSeries(context, R.color.yellow_transparent,
|
||||
R.color.yellow, "###,###", R.string.heart_rate);
|
||||
}
|
||||
|
||||
private ChartValueSeries getSeries(Context context,
|
||||
int fillColor, int strokeColor, String format, int seriesName) {
|
||||
Paint fillPaint = new Paint();
|
||||
fillPaint.setStyle(Style.FILL);
|
||||
fillPaint.setColor(context.getResources().getColor(fillColor));
|
||||
fillPaint.setAntiAlias(true);
|
||||
|
||||
Paint strokePaint = new Paint();
|
||||
strokePaint.setStyle(Style.STROKE);
|
||||
strokePaint.setColor(context.getResources().getColor(strokeColor));
|
||||
strokePaint.setAntiAlias(true);
|
||||
return new ChartValueSeries(context, format, fillPaint, strokePaint, 5,
|
||||
seriesName);
|
||||
}
|
||||
|
||||
public void clearWaypoints() {
|
||||
@@ -266,13 +275,25 @@ public class ChartView extends View {
|
||||
*/
|
||||
public synchronized void addDataPoint(double[] theData) {
|
||||
data.add(theData);
|
||||
addDataPointInternal(theData);
|
||||
updateDimensions();
|
||||
setupPath();
|
||||
}
|
||||
|
||||
private void addDataPointInternal(double[] theData) {
|
||||
xMonitor.update(theData[0]);
|
||||
int min = Math.min(series.length, theData.length - 1);
|
||||
for (int i = 0; i < min; i++) {
|
||||
series[i].update(theData[i + 1]);
|
||||
if (!Double.isNaN(theData[i + 1])) {
|
||||
series[i].update(theData[i + 1]);
|
||||
}
|
||||
}
|
||||
// Fill in the extra's if needed.
|
||||
for (int i = theData.length; i < series.length; i++) {
|
||||
if (series[i].hasData()) {
|
||||
series[i].update(0);
|
||||
}
|
||||
}
|
||||
updateDimensions();
|
||||
setupPath();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -284,11 +305,7 @@ public class ChartView extends View {
|
||||
data.addAll(theData);
|
||||
for (int i = 0; i < theData.size(); i++) {
|
||||
double d[] = theData.get(i);
|
||||
xMonitor.update(d[0]);
|
||||
int min = Math.min(series.length, d.length - 1);
|
||||
for (int j = 0; j < min; j++) {
|
||||
series[j].update(d[j + 1]);
|
||||
}
|
||||
addDataPointInternal(d);
|
||||
}
|
||||
updateDimensions();
|
||||
setupPath();
|
||||
@@ -526,7 +543,7 @@ public class ChartView extends View {
|
||||
|
||||
// Draw the data series
|
||||
for (ChartValueSeries cvs : series) {
|
||||
if (cvs.isEnabled()) {
|
||||
if (cvs.isEnabled() && cvs.hasData()) {
|
||||
cvs.drawPath(c);
|
||||
}
|
||||
}
|
||||
@@ -560,7 +577,7 @@ public class ChartView extends View {
|
||||
c.translate(getScrollX(), 0);
|
||||
drawYAxis(c);
|
||||
for (ChartValueSeries cvs : series) {
|
||||
if (cvs.isEnabled()) {
|
||||
if (cvs.isEnabled() && cvs.hasData()) {
|
||||
drawYLabels(cvs, c);
|
||||
}
|
||||
}
|
||||
@@ -576,13 +593,13 @@ public class ChartView extends View {
|
||||
private void drawSeriesTitles(Canvas c) {
|
||||
int sections = 1;
|
||||
for (ChartValueSeries cvs : series) {
|
||||
if (cvs.isEnabled()) {
|
||||
if (cvs.isEnabled() && cvs.hasData()) {
|
||||
sections++;
|
||||
}
|
||||
}
|
||||
int j = 0;
|
||||
for (ChartValueSeries cvs : series) {
|
||||
if (cvs.isEnabled()) {
|
||||
if (cvs.isEnabled() && cvs.hasData()) {
|
||||
int y = (int) (w * zoomLevel * ((double) (++j) / sections));
|
||||
c.drawText(cvs.getTitle(), y, TOP_BORDER, cvs.getPaint());
|
||||
}
|
||||
@@ -601,11 +618,11 @@ public class ChartView extends View {
|
||||
return;
|
||||
}
|
||||
|
||||
int min = Math.min(series.length, data.get(0).length - 1);
|
||||
|
||||
// All of the data points to the respective series.
|
||||
for (int i = 0; i < data.size(); i++) {
|
||||
double[] d = data.get(i);
|
||||
int min = Math.min(series.length, d.length - 1);
|
||||
|
||||
for (int j = 0; j < min; j++) {
|
||||
ChartValueSeries cvs = series[j];
|
||||
Path path = cvs.getPath();
|
||||
@@ -616,17 +633,36 @@ public class ChartView extends View {
|
||||
// Close the path.
|
||||
int yCorner = TOP_BORDER + effectiveHeight;
|
||||
int xCorner = getX(data.get(0)[0]);
|
||||
int min = series.length;
|
||||
for (int j = 0; j < min; j++) {
|
||||
ChartValueSeries cvs = series[j];
|
||||
Path path = cvs.getPath();
|
||||
// Bottom right corner
|
||||
path.lineTo(getX(data.get(data.size() - 1)[0]), yCorner);
|
||||
// Bottom left corner
|
||||
path.lineTo(xCorner, yCorner);
|
||||
// Top right corner
|
||||
path.lineTo(xCorner, getY(cvs, data.get(0)[j + 1]));
|
||||
int first = getFirstPointPopulatedIndex(j + 1);
|
||||
if (first != -1) {
|
||||
// Bottom right corner
|
||||
path.lineTo(getX(data.get(data.size() - 1)[0]), yCorner);
|
||||
// Bottom left corner
|
||||
path.lineTo(xCorner, yCorner);
|
||||
// Top right corner
|
||||
path.lineTo(xCorner, getY(cvs, data.get(first)[j + 1]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the index of the first point which has a series populated.
|
||||
* @param seriesIndex The index of the value series to search for.
|
||||
* @return The index in the first data for the point in the series that has series
|
||||
* index value populated or -1 if none is found.
|
||||
*/
|
||||
private int getFirstPointPopulatedIndex(int seriesIndex) {
|
||||
for (int i = 0; i < data.size(); i++) {
|
||||
if (data.get(i).length > seriesIndex) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the histogram dimensions.
|
||||
|
||||
@@ -17,6 +17,7 @@ package com.google.android.apps.mytracks;
|
||||
|
||||
import com.google.android.maps.mytracks.R;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
@@ -63,8 +64,8 @@ class MenuManager {
|
||||
return true;
|
||||
}
|
||||
case R.id.menu_list_tracks: {
|
||||
Intent startIntent = new Intent(activity, MyTracksList.class);
|
||||
activity.startActivityForResult(startIntent, MyTracksConstants.SHOW_TRACK);
|
||||
activity.startActivityForResult(new Intent(activity, MyTracksList.class),
|
||||
MyTracksConstants.SHOW_TRACK);
|
||||
return true;
|
||||
}
|
||||
case R.id.menu_list_markers: {
|
||||
@@ -73,20 +74,17 @@ class MenuManager {
|
||||
activity.startActivityForResult(startIntent, MyTracksConstants.SHOW_WAYPOINT);
|
||||
return true;
|
||||
}
|
||||
case R.id.menu_sensor_state: {
|
||||
return startActivity(SensorStateActivity.class);
|
||||
}
|
||||
case R.id.menu_settings: {
|
||||
Intent startIntent = new Intent(activity, MyTracksSettings.class);
|
||||
activity.startActivity(startIntent);
|
||||
return true;
|
||||
return startActivity(MyTracksSettings.class);
|
||||
}
|
||||
case R.id.menu_aggregated_stats: {
|
||||
Intent startIntent = new Intent(activity, AggregatedStatsActivity.class);
|
||||
activity.startActivity(startIntent);
|
||||
return true;
|
||||
return startActivity(AggregatedStatsActivity.class);
|
||||
}
|
||||
case R.id.menu_help: {
|
||||
Intent startIntent = new Intent(activity, WelcomeActivity.class);
|
||||
activity.startActivity(startIntent);
|
||||
return true;
|
||||
return startActivity(WelcomeActivity.class);
|
||||
}
|
||||
case MyTracksConstants.MENU_CLEAR_MAP: {
|
||||
activity.setSelectedTrackId(-1);
|
||||
@@ -95,4 +93,9 @@ class MenuManager {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean startActivity(Class<? extends Activity> activityClass) {
|
||||
activity.startActivity(new Intent(activity, activityClass));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,7 +63,6 @@ import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
@@ -229,7 +228,9 @@ public class MyTracks extends TabActivity implements OnTouchListener,
|
||||
}
|
||||
try {
|
||||
return trackRecordingService.isRecording();
|
||||
} catch (RemoteException e) {
|
||||
// TODO: We catch Exception, because after eliminating the service process
|
||||
// all exceptions it may throw are no longer wrapped in a RemoteException.
|
||||
} catch (Exception e) {
|
||||
Log.e(MyTracksConstants.TAG, "MyTracks: Remote exception.", e);
|
||||
|
||||
// Fall back to alternative check method.
|
||||
@@ -411,6 +412,11 @@ public class MyTracks extends TabActivity implements OnTouchListener,
|
||||
return dialogManager.onCreateDialog(id, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Dialog onCreateDialog(int id) {
|
||||
return dialogManager.onCreateDialog(id, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPrepareDialog(int id, Dialog dialog) {
|
||||
super.onPrepareDialog(id, dialog);
|
||||
@@ -914,7 +920,9 @@ public class MyTracks extends TabActivity implements OnTouchListener,
|
||||
Log.e(MyTracksConstants.TAG, "Cannot insert waypoint marker?");
|
||||
return -4;
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
// TODO: We catch Exception, because after eliminating the service process
|
||||
// all exceptions it may throw are no longer wrapped in a RemoteException.
|
||||
} catch (Exception e) {
|
||||
Toast.makeText(this, R.string.error_unable_to_insert_marker,
|
||||
Toast.LENGTH_LONG).show();
|
||||
Log.e(MyTracksConstants.TAG, "Cannot insert waypoint marker.", e);
|
||||
@@ -954,7 +962,9 @@ public class MyTracks extends TabActivity implements OnTouchListener,
|
||||
Log.e(MyTracksConstants.TAG, "Cannot insert statistics marker?");
|
||||
return -4;
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
// TODO: We catch Exception, because after eliminating the service process
|
||||
// all exceptions it may throw are no longer wrapped in a RemoteException.
|
||||
} catch (Exception e) {
|
||||
Toast.makeText(this, R.string.error_unable_to_insert_marker,
|
||||
Toast.LENGTH_LONG).show();
|
||||
Log.e(MyTracksConstants.TAG, "Cannot insert statistics marker?", e);
|
||||
@@ -1022,7 +1032,9 @@ public class MyTracks extends TabActivity implements OnTouchListener,
|
||||
setSelectedTrackId(recordingTrackId);
|
||||
Toast.makeText(this, getString(R.string.status_now_recording),
|
||||
Toast.LENGTH_SHORT).show();
|
||||
} catch (RemoteException e) {
|
||||
// TODO: We catch Exception, because after eliminating the service process
|
||||
// all exceptions it may throw are no longer wrapped in a RemoteException.
|
||||
} catch (Exception e) {
|
||||
Toast.makeText(this,
|
||||
getString(R.string.error_unable_to_start_recording),
|
||||
Toast.LENGTH_SHORT).show();
|
||||
@@ -1055,7 +1067,9 @@ public class MyTracks extends TabActivity implements OnTouchListener,
|
||||
long currentTrackId = recordingTrackId;
|
||||
try {
|
||||
trackRecordingService.endCurrentTrack();
|
||||
} catch (RemoteException e) {
|
||||
// TODO: We catch Exception, because after eliminating the service process
|
||||
// all exceptions it may throw are no longer wrapped in a RemoteException.
|
||||
} catch (Exception e) {
|
||||
Log.e(MyTracksConstants.TAG, "Unable to stop recording.", e);
|
||||
}
|
||||
Intent intent = new Intent(MyTracks.this, MyTracksDetails.class);
|
||||
@@ -1120,7 +1134,7 @@ public class MyTracks extends TabActivity implements OnTouchListener,
|
||||
long getSelectedTrackId() {
|
||||
return selectedTrackId;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Binds to track recording service if it is running.
|
||||
*/
|
||||
|
||||
@@ -15,12 +15,17 @@
|
||||
*/
|
||||
package com.google.android.apps.mytracks;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.android.apps.mytracks.io.backup.BackupActivityHelper;
|
||||
import com.google.android.apps.mytracks.io.backup.BackupPreferencesListener;
|
||||
import com.google.android.apps.mytracks.services.StatusAnnouncerFactory;
|
||||
import com.google.android.apps.mytracks.util.ApiFeatures;
|
||||
import com.google.android.apps.mytracks.util.BluetoothDeviceUtils;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.preference.CheckBoxPreference;
|
||||
@@ -30,6 +35,7 @@ import android.preference.PreferenceActivity;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.preference.Preference.OnPreferenceChangeListener;
|
||||
import android.preference.Preference.OnPreferenceClickListener;
|
||||
import android.provider.Settings;
|
||||
|
||||
/**
|
||||
* An activity that let's the user see and edit the settings.
|
||||
@@ -53,6 +59,7 @@ public class MyTracksSettings extends PreferenceActivity {
|
||||
public static final int DEFAULT_SPLIT_FREQUENCY = 0;
|
||||
|
||||
private BackupPreferencesListener backupListener;
|
||||
|
||||
private SharedPreferences preferences;
|
||||
|
||||
/** Called when the activity is first created. */
|
||||
@@ -96,6 +103,19 @@ public class MyTracksSettings extends PreferenceActivity {
|
||||
});
|
||||
updatePreferenceUnits(metricUnitsPreference.isChecked());
|
||||
|
||||
ListPreference sensorTypePreference =
|
||||
(ListPreference) findPreference(getString(R.string.sensor_type_key));
|
||||
sensorTypePreference.setOnPreferenceChangeListener(
|
||||
new OnPreferenceChangeListener() {
|
||||
@Override
|
||||
public boolean onPreferenceChange(Preference preference,
|
||||
Object newValue) {
|
||||
updateSensorSettings((String) newValue);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
updateSensorSettings(sensorTypePreference.getValue());
|
||||
|
||||
// Disable TTS announcement preference if not available
|
||||
if (!apiFeatures.hasTextToSpeech()) {
|
||||
IntegerListPreference announcementFrequency =
|
||||
@@ -112,6 +132,7 @@ public class MyTracksSettings extends PreferenceActivity {
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
|
||||
configureBluetoothPreferences();
|
||||
Preference backupNowPreference =
|
||||
findPreference(getString(R.string.backup_to_sd_key));
|
||||
Preference restoreNowPreference =
|
||||
@@ -158,7 +179,15 @@ public class MyTracksSettings extends PreferenceActivity {
|
||||
getPreferenceManager().getSharedPreferences()
|
||||
.unregisterOnSharedPreferenceChangeListener(backupListener);
|
||||
|
||||
super.onDestroy();
|
||||
super.onPause();
|
||||
}
|
||||
private void updateSensorSettings(String sensorType) {
|
||||
boolean usesBluetooth =
|
||||
getString(R.string.zephyr_sensor_type).equals(sensorType);
|
||||
findPreference(
|
||||
getString(R.string.bluetooth_sensor_key)).setEnabled(usesBluetooth);
|
||||
findPreference(
|
||||
getString(R.string.bluetooth_pairing_key)).setEnabled(usesBluetooth);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -194,4 +223,44 @@ public class MyTracksSettings extends PreferenceActivity {
|
||||
? R.array.split_frequency_options
|
||||
: R.array.split_frequency_options_ft);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Configures preference actions related to bluetooth.
|
||||
*/
|
||||
private void configureBluetoothPreferences() {
|
||||
if (BluetoothDeviceUtils.isBluetoothMethodSupported()) {
|
||||
// Populate the list of bluetooth devices
|
||||
populateBluetoothDeviceList();
|
||||
|
||||
// Make the pair devices preference go to the system preferences
|
||||
findPreference(getString(R.string.bluetooth_pairing_key))
|
||||
.setOnPreferenceClickListener(new OnPreferenceClickListener() {
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
Intent settingsIntent = new Intent(Settings.ACTION_BLUETOOTH_SETTINGS);
|
||||
startActivity(settingsIntent);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Populates the list preference with all available bluetooth devices.
|
||||
*/
|
||||
private void populateBluetoothDeviceList() {
|
||||
// Build the list of entries and their values
|
||||
List<String> entries = new ArrayList<String>();
|
||||
List<String> entryValues = new ArrayList<String>();
|
||||
|
||||
// The actual devices
|
||||
BluetoothDeviceUtils.getInstance().populateDeviceLists(entries, entryValues);
|
||||
|
||||
CharSequence[] entriesArray = entries.toArray(new CharSequence[entries.size()]);
|
||||
CharSequence[] entryValuesArray = entryValues.toArray(new CharSequence[entryValues.size()]);
|
||||
ListPreference devicesPreference =
|
||||
(ListPreference) findPreference(getString(R.string.bluetooth_sensor_key));
|
||||
devicesPreference.setEntryValues(entryValuesArray);
|
||||
devicesPreference.setEntries(entriesArray);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,193 @@
|
||||
/*
|
||||
* Copyright 2010 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package com.google.android.apps.mytracks;
|
||||
|
||||
import static com.google.android.apps.mytracks.MyTracksConstants.TAG;
|
||||
import com.google.android.apps.mytracks.content.Sensor;
|
||||
import com.google.android.apps.mytracks.services.ITrackRecordingService;
|
||||
import com.google.android.apps.mytracks.services.sensors.SensorUtils;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
import android.widget.TextView;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
/**
|
||||
* An activity that displays information about sensors.
|
||||
*
|
||||
* @author Sandor Dornbush
|
||||
*/
|
||||
public class SensorStateActivity extends Activity {
|
||||
|
||||
private static final SimpleDateFormat TIMESTAMP_FORMAT =
|
||||
new SimpleDateFormat("HH:mm:ss");
|
||||
private static final long REFRESH_PERIOD_MS = 250;
|
||||
|
||||
private final StatsUtilities utils;
|
||||
|
||||
/**
|
||||
* This timer periodically invokes the refresh timer task.
|
||||
*/
|
||||
private Timer timer;
|
||||
|
||||
private final Runnable stateUpdater = new Runnable() {
|
||||
public void run() {
|
||||
updateState();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* A task which will update the U/I.
|
||||
*/
|
||||
private class RefreshTask extends TimerTask {
|
||||
@Override
|
||||
public void run() {
|
||||
runOnUiThread(stateUpdater);
|
||||
}
|
||||
};
|
||||
|
||||
public SensorStateActivity() {
|
||||
utils = new StatsUtilities(this);
|
||||
Log.w(TAG, "SensorStateActivity()");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
Log.w(TAG, "SensorStateActivity.onCreate");
|
||||
|
||||
setContentView(R.layout.sensor_state);
|
||||
|
||||
updateState();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
timer = new Timer();
|
||||
timer.schedule(new RefreshTask(), REFRESH_PERIOD_MS, REFRESH_PERIOD_MS);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
timer.cancel();
|
||||
timer.purge();
|
||||
timer = null;
|
||||
}
|
||||
|
||||
protected void updateState() {
|
||||
MyTracks mt = MyTracks.getInstance();
|
||||
|
||||
ITrackRecordingService service =
|
||||
mt == null ? null : mt.getTrackRecordingService();
|
||||
if (service == null) {
|
||||
Log.d(MyTracksConstants.TAG, "Could not get track recording service.");
|
||||
updateSensorState(Sensor.SensorState.NONE);
|
||||
updateSensorData(null);
|
||||
return;
|
||||
}
|
||||
Sensor.SensorDataSet sds = null;
|
||||
try {
|
||||
byte[] buff = service.getSensorData();
|
||||
if (buff != null) {
|
||||
sds = Sensor.SensorDataSet.parseFrom(buff);
|
||||
updateSensorData(sds);
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
Log.e(MyTracksConstants.TAG, "Could not read sensor data.", e);
|
||||
} catch (InvalidProtocolBufferException e) {
|
||||
Log.e(MyTracksConstants.TAG, "Could not read sensor data.", e);
|
||||
}
|
||||
updateSensorData(sds);
|
||||
|
||||
try {
|
||||
int i = service.getSensorState();
|
||||
updateSensorState(Sensor.SensorState.valueOf(i));
|
||||
} catch (RemoteException e) {
|
||||
Log.e(MyTracksConstants.TAG, "Could not read sensor state.", e);
|
||||
updateSensorState(Sensor.SensorState.NONE);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateSensorState(Sensor.SensorState state) {
|
||||
TextView sensorTime =
|
||||
((TextView) findViewById(R.id.sensor_state_register));
|
||||
sensorTime.setText(SensorUtils.getStateAsString(state, this));
|
||||
}
|
||||
|
||||
protected void updateSensorData(Sensor.SensorDataSet sds) {
|
||||
if (sds == null) {
|
||||
utils.setUnknown(R.id.sensor_data_time_register);
|
||||
utils.setUnknown(R.id.cadence_state_register);
|
||||
utils.setUnknown(R.id.power_state_register);
|
||||
utils.setUnknown(R.id.heart_rate_register);
|
||||
return;
|
||||
}
|
||||
|
||||
TextView sensorTime =
|
||||
((TextView) findViewById(R.id.sensor_data_time_register));
|
||||
sensorTime.setText(
|
||||
TIMESTAMP_FORMAT.format(new Date(sds.getCreationTime())));
|
||||
|
||||
if (sds.hasPower() && sds.getPower().hasValue()
|
||||
&& sds.getPower().getState() == Sensor.SensorState.SENDING) {
|
||||
utils.setText(R.id.power_state_register,
|
||||
Integer.toString(sds.getPower().getValue()));
|
||||
} else {
|
||||
utils.setText(R.id.power_state_register,
|
||||
SensorUtils.getStateAsString(
|
||||
sds.hasPower()
|
||||
? sds.getPower().getState()
|
||||
: Sensor.SensorState.NONE,
|
||||
this));
|
||||
}
|
||||
|
||||
if (sds.hasCadence() && sds.getCadence().hasValue()
|
||||
&& sds.getCadence().getState() == Sensor.SensorState.SENDING) {
|
||||
utils.setText(R.id.cadence_state_register,
|
||||
Integer.toString(sds.getCadence().getValue()));
|
||||
} else {
|
||||
utils.setText(R.id.cadence_state_register,
|
||||
SensorUtils.getStateAsString(
|
||||
sds.hasCadence()
|
||||
? sds.getCadence().getState()
|
||||
: Sensor.SensorState.NONE,
|
||||
this));
|
||||
}
|
||||
|
||||
if (sds.hasHeartRate() && sds.getHeartRate().hasValue()
|
||||
&& sds.getHeartRate().getState() == Sensor.SensorState.SENDING) {
|
||||
utils.setText(R.id.heart_rate_register,
|
||||
Integer.toString(sds.getHeartRate().getValue()));
|
||||
} else {
|
||||
utils.setText(R.id.heart_rate_register,
|
||||
SensorUtils.getStateAsString(
|
||||
sds.hasHeartRate()
|
||||
? sds.getHeartRate().getState()
|
||||
: Sensor.SensorState.NONE,
|
||||
this));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package com.google.android.apps.mytracks.content;
|
||||
|
||||
import com.google.android.apps.mytracks.MyTracksConstants;
|
||||
|
||||
import android.content.ContentProvider;
|
||||
import android.content.ContentUris;
|
||||
import android.content.ContentValues;
|
||||
@@ -38,7 +40,7 @@ import android.util.Log;
|
||||
public class MyTracksProvider extends ContentProvider {
|
||||
|
||||
private static final String DATABASE_NAME = "mytracks.db";
|
||||
private static final int DATABASE_VERSION = 17;
|
||||
private static final int DATABASE_VERSION = 18;
|
||||
private static final int TRACKPOINTS = 1;
|
||||
private static final int TRACKPOINTS_ID = 2;
|
||||
private static final int TRACKS = 3;
|
||||
@@ -70,7 +72,8 @@ public class MyTracksProvider extends ContentProvider {
|
||||
+ TrackPointsColumns.ALTITUDE + " FLOAT, "
|
||||
+ TrackPointsColumns.ACCURACY + " FLOAT, "
|
||||
+ TrackPointsColumns.SPEED + " FLOAT, "
|
||||
+ TrackPointsColumns.BEARING + " FLOAT);");
|
||||
+ TrackPointsColumns.BEARING + " FLOAT, "
|
||||
+ TrackPointsColumns.SENSOR + " BLOB);");
|
||||
db.execSQL("CREATE TABLE " + TRACKS_TABLE + " ("
|
||||
+ TracksColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
|
||||
+ TracksColumns.NAME + " STRING, "
|
||||
@@ -132,12 +135,19 @@ public class MyTracksProvider extends ContentProvider {
|
||||
|
||||
@Override
|
||||
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
||||
Log.w(TAG, "Upgrading database from version " + oldVersion + " to "
|
||||
+ newVersion + ", which will destroy all old data");
|
||||
db.execSQL("DROP TABLE IF EXISTS " + TRACKPOINTS_TABLE);
|
||||
db.execSQL("DROP TABLE IF EXISTS " + TRACKS_TABLE);
|
||||
db.execSQL("DROP TABLE IF EXISTS " + WAYPOINTS_TABLE);
|
||||
onCreate(db);
|
||||
if (oldVersion < 17) {
|
||||
Log.w(TAG, "Upgrading database from version " + oldVersion + " to "
|
||||
+ newVersion + ", which will destroy all old data");
|
||||
db.execSQL("DROP TABLE IF EXISTS " + TRACKPOINTS_TABLE);
|
||||
db.execSQL("DROP TABLE IF EXISTS " + TRACKS_TABLE);
|
||||
db.execSQL("DROP TABLE IF EXISTS " + WAYPOINTS_TABLE);
|
||||
onCreate(db);
|
||||
} else if (oldVersion >= 17) {
|
||||
Log.w(TAG, "Upgrading database from version " + oldVersion + " to "
|
||||
+ newVersion + ", adding sensor column.");
|
||||
db.execSQL("ALTER TABLE " + TRACKPOINTS_TABLE
|
||||
+ " ADD " + TrackPointsColumns.SENSOR + " BLOB");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -235,6 +245,7 @@ public class MyTracksProvider extends ContentProvider {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int bulkInsert(Uri url, ContentValues[] valuesBulk) {
|
||||
Log.d(MyTracksProvider.TAG, "MyTracksProvider.bulkInsert");
|
||||
@@ -346,6 +357,8 @@ public class MyTracksProvider extends ContentProvider {
|
||||
throw new IllegalArgumentException("Unknown URL " + url);
|
||||
}
|
||||
|
||||
Log.i(MyTracksConstants.TAG,
|
||||
"Build query: " + qb.buildQuery(projection, selection, selectionArgs, null, null, sortOrder, null));
|
||||
Cursor c = qb.query(db, projection, selection, selectionArgs, null, null,
|
||||
sortOrder);
|
||||
c.setNotificationUri(getContext().getContentResolver(), url);
|
||||
|
||||
@@ -342,8 +342,14 @@ public class GpxImporter extends DefaultHandler {
|
||||
|
||||
// create new location and set attributes
|
||||
Location loc = new Location(LocationManager.GPS_PROVIDER);
|
||||
loc.setLatitude(Double.parseDouble(latitude));
|
||||
loc.setLongitude(Double.parseDouble(longitude));
|
||||
try {
|
||||
loc.setLatitude(Double.parseDouble(latitude));
|
||||
loc.setLongitude(Double.parseDouble(longitude));
|
||||
} catch (NumberFormatException e) {
|
||||
String msg = createErrorMessage(
|
||||
"Unable to parse lat/long: " + latitude + "/" + longitude);
|
||||
throw new SAXException(msg, e);
|
||||
}
|
||||
return loc;
|
||||
}
|
||||
|
||||
@@ -472,9 +478,14 @@ public class GpxImporter extends DefaultHandler {
|
||||
}
|
||||
}
|
||||
|
||||
private void onAltitudeElementEnd() {
|
||||
private void onAltitudeElementEnd() throws SAXException {
|
||||
if (location != null) {
|
||||
location.setAltitude(Double.parseDouble(content));
|
||||
try {
|
||||
location.setAltitude(Double.parseDouble(content));
|
||||
} catch (NumberFormatException e) {
|
||||
String msg = createErrorMessage("Unable to parse altitude: " + content);
|
||||
throw new SAXException(msg, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,8 +15,11 @@
|
||||
*/
|
||||
package com.google.android.apps.mytracks.io;
|
||||
|
||||
import com.google.android.apps.mytracks.content.MyTracksLocation;
|
||||
import com.google.android.apps.mytracks.content.Sensor;
|
||||
import com.google.android.apps.mytracks.content.Track;
|
||||
import com.google.android.apps.mytracks.content.Waypoint;
|
||||
import com.google.android.apps.mytracks.content.Sensor.SensorDataSet;
|
||||
import com.google.android.apps.mytracks.io.TrackWriterFactory.TrackFileFormat;
|
||||
|
||||
import android.location.Location;
|
||||
@@ -141,6 +144,37 @@ public class TcxTrackWriter implements TrackFormatWriter {
|
||||
pw.print(location.getAltitude());
|
||||
pw.println("</AltitudeMeters>");
|
||||
|
||||
if (location instanceof MyTracksLocation) {
|
||||
SensorDataSet sensorData = ((MyTracksLocation) location).getSensorDataSet();
|
||||
if (sensorData != null) {
|
||||
if (sensorData.hasHeartRate()
|
||||
&& sensorData.getHeartRate().getState() == Sensor.SensorState.SENDING
|
||||
&& sensorData.getHeartRate().hasValue()) {
|
||||
pw.print(" <HeartRateBpm>");
|
||||
pw.print("<Value>");
|
||||
pw.print(sensorData.getHeartRate().getValue());
|
||||
pw.print("</Value>");
|
||||
pw.println("</HeartRateBpm>");
|
||||
}
|
||||
if (sensorData.hasPower()
|
||||
&& sensorData.getPower().getState() == Sensor.SensorState.SENDING
|
||||
&& sensorData.getPower().hasValue()) {
|
||||
pw.print(" <Extensions>");
|
||||
pw.print("<TPX xmlns=\"http://www.garmin.com/xmlschemas/ActivityExtension/v2\">");
|
||||
pw.print("<Watts>");
|
||||
pw.print(sensorData.getPower().getValue());
|
||||
pw.print("</Watts>");
|
||||
pw.println("</TPX></Extensions>");
|
||||
}
|
||||
if (sensorData.hasCadence()
|
||||
&& sensorData.getCadence().getState() == Sensor.SensorState.SENDING
|
||||
&& sensorData.getCadence().hasValue()) {
|
||||
pw.print(" <Cadence>");
|
||||
pw.print(sensorData.getCadence().getValue());
|
||||
pw.println("</Cadence>");
|
||||
}
|
||||
}
|
||||
}
|
||||
pw.println(" </Trackpoint>");
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright 2010 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package com.google.android.apps.mytracks.io.backup;
|
||||
|
||||
import static com.google.android.apps.mytracks.content.ContentTypeIds.*;
|
||||
import com.google.android.apps.mytracks.content.TrackPointsColumns;
|
||||
import com.google.android.apps.mytracks.content.TracksColumns;
|
||||
import com.google.android.apps.mytracks.content.WaypointsColumns;
|
||||
|
||||
public class BackupColumns {
|
||||
/** Columns that go into the backup. */
|
||||
public static final String[] POINTS_BACKUP_COLUMNS =
|
||||
{ TrackPointsColumns._ID, TrackPointsColumns.TRACKID, TrackPointsColumns.LATITUDE,
|
||||
TrackPointsColumns.LONGITUDE, TrackPointsColumns.ALTITUDE, TrackPointsColumns.BEARING,
|
||||
TrackPointsColumns.TIME, TrackPointsColumns.ACCURACY, TrackPointsColumns.SPEED };
|
||||
public static final byte[] POINTS_BACKUP_COLUMN_TYPES =
|
||||
{ LONG_TYPE_ID, LONG_TYPE_ID, INT_TYPE_ID, INT_TYPE_ID, FLOAT_TYPE_ID,
|
||||
FLOAT_TYPE_ID, LONG_TYPE_ID, FLOAT_TYPE_ID, FLOAT_TYPE_ID };
|
||||
|
||||
public static final String[] TRACKS_BACKUP_COLUMNS = {
|
||||
TracksColumns._ID, TracksColumns.NAME, TracksColumns.DESCRIPTION, TracksColumns.CATEGORY,
|
||||
TracksColumns.STARTID, TracksColumns.STOPID, TracksColumns.STARTTIME, TracksColumns.STOPTIME,
|
||||
TracksColumns.NUMPOINTS, TracksColumns.TOTALDISTANCE, TracksColumns.TOTALTIME,
|
||||
TracksColumns.MOVINGTIME, TracksColumns.AVGSPEED, TracksColumns.AVGMOVINGSPEED,
|
||||
TracksColumns.MAXSPEED, TracksColumns.MINELEVATION, TracksColumns.MAXELEVATION,
|
||||
TracksColumns.ELEVATIONGAIN, TracksColumns.MINGRADE, TracksColumns.MAXGRADE,
|
||||
TracksColumns.MINLAT, TracksColumns.MAXLAT, TracksColumns.MINLON, TracksColumns.MAXLON };
|
||||
public static final byte[] TRACKS_BACKUP_COLUMN_TYPES = {
|
||||
LONG_TYPE_ID, STRING_TYPE_ID, STRING_TYPE_ID, STRING_TYPE_ID,
|
||||
LONG_TYPE_ID, LONG_TYPE_ID, LONG_TYPE_ID, LONG_TYPE_ID, INT_TYPE_ID,
|
||||
FLOAT_TYPE_ID, LONG_TYPE_ID, LONG_TYPE_ID, FLOAT_TYPE_ID, FLOAT_TYPE_ID,
|
||||
FLOAT_TYPE_ID, FLOAT_TYPE_ID, FLOAT_TYPE_ID, FLOAT_TYPE_ID, FLOAT_TYPE_ID,
|
||||
FLOAT_TYPE_ID, INT_TYPE_ID, INT_TYPE_ID, INT_TYPE_ID, INT_TYPE_ID };
|
||||
|
||||
public static final String[] WAYPOINTS_BACKUP_COLUMNS = {
|
||||
WaypointsColumns._ID, WaypointsColumns.TRACKID, WaypointsColumns.NAME,
|
||||
WaypointsColumns.DESCRIPTION, WaypointsColumns.CATEGORY, WaypointsColumns.ICON,
|
||||
WaypointsColumns.TYPE, WaypointsColumns.LENGTH, WaypointsColumns.DURATION,
|
||||
WaypointsColumns.STARTTIME, WaypointsColumns.STARTID, WaypointsColumns.STOPID,
|
||||
WaypointsColumns.LATITUDE, WaypointsColumns.LONGITUDE, WaypointsColumns.ALTITUDE,
|
||||
WaypointsColumns.BEARING, WaypointsColumns.TIME, WaypointsColumns.ACCURACY,
|
||||
WaypointsColumns.SPEED, WaypointsColumns.TOTALDISTANCE, WaypointsColumns.TOTALTIME,
|
||||
WaypointsColumns.MOVINGTIME, WaypointsColumns.AVGSPEED, WaypointsColumns.AVGMOVINGSPEED,
|
||||
WaypointsColumns.MAXSPEED, WaypointsColumns.MINELEVATION, WaypointsColumns.MAXELEVATION,
|
||||
WaypointsColumns.ELEVATIONGAIN, WaypointsColumns.MINGRADE, WaypointsColumns.MAXGRADE };
|
||||
public static final byte[] WAYPOINTS_BACKUP_COLUMN_TYPES = {
|
||||
LONG_TYPE_ID, LONG_TYPE_ID, STRING_TYPE_ID, STRING_TYPE_ID,
|
||||
STRING_TYPE_ID, STRING_TYPE_ID, INT_TYPE_ID, FLOAT_TYPE_ID, LONG_TYPE_ID,
|
||||
LONG_TYPE_ID, LONG_TYPE_ID, LONG_TYPE_ID, INT_TYPE_ID, INT_TYPE_ID,
|
||||
FLOAT_TYPE_ID, FLOAT_TYPE_ID, LONG_TYPE_ID, FLOAT_TYPE_ID, FLOAT_TYPE_ID,
|
||||
FLOAT_TYPE_ID, LONG_TYPE_ID, LONG_TYPE_ID, FLOAT_TYPE_ID, FLOAT_TYPE_ID,
|
||||
FLOAT_TYPE_ID, FLOAT_TYPE_ID, FLOAT_TYPE_ID, FLOAT_TYPE_ID, FLOAT_TYPE_ID,
|
||||
FLOAT_TYPE_ID };
|
||||
}
|
||||
@@ -153,16 +153,16 @@ class ExternalFileBackup {
|
||||
// Create all the auxiliary classes that will do the writing
|
||||
PreferenceBackupHelper preferencesHelper = new PreferenceBackupHelper();
|
||||
DatabaseDumper trackDumper = new DatabaseDumper(
|
||||
TracksColumns.BACKUP_COLUMNS,
|
||||
TracksColumns.BACKUP_COLUMN_TYPES,
|
||||
BackupColumns.TRACKS_BACKUP_COLUMNS,
|
||||
BackupColumns.TRACKS_BACKUP_COLUMN_TYPES,
|
||||
false);
|
||||
DatabaseDumper waypointDumper = new DatabaseDumper(
|
||||
WaypointsColumns.BACKUP_COLUMNS,
|
||||
WaypointsColumns.BACKUP_COLUMN_TYPES,
|
||||
BackupColumns.WAYPOINTS_BACKUP_COLUMNS,
|
||||
BackupColumns.WAYPOINTS_BACKUP_COLUMN_TYPES,
|
||||
false);
|
||||
DatabaseDumper pointDumper = new DatabaseDumper(
|
||||
TrackPointsColumns.BACKUP_COLUMNS,
|
||||
TrackPointsColumns.BACKUP_COLUMN_TYPES,
|
||||
BackupColumns.POINTS_BACKUP_COLUMNS,
|
||||
BackupColumns.POINTS_BACKUP_COLUMN_TYPES,
|
||||
false);
|
||||
|
||||
// Open the target for writing
|
||||
|
||||
@@ -40,7 +40,6 @@ public class PreferenceManager implements OnSharedPreferenceChangeListener {
|
||||
private final String minRecordingIntervalKey;
|
||||
private final String minRequiredAccuracyKey;
|
||||
private final String recordingTrackKey;
|
||||
private final String signalSamplingFrequencyKey;
|
||||
private final String splitFrequencyKey;
|
||||
|
||||
public PreferenceManager(TrackRecordingService service) {
|
||||
@@ -72,8 +71,6 @@ public class PreferenceManager implements OnSharedPreferenceChangeListener {
|
||||
service.getString(R.string.min_required_accuracy_key);
|
||||
recordingTrackKey =
|
||||
service.getString(R.string.recording_track_key);
|
||||
signalSamplingFrequencyKey =
|
||||
service.getString(R.string.signal_sampling_frequency_key);
|
||||
splitFrequencyKey =
|
||||
service.getString(R.string.split_frequency_key);
|
||||
|
||||
@@ -163,10 +160,6 @@ public class PreferenceManager implements OnSharedPreferenceChangeListener {
|
||||
service.getSplitManager().setSplitFrequency(
|
||||
sharedPreferences.getInt(splitFrequencyKey, 0));
|
||||
}
|
||||
if (key == null || key.equals(signalSamplingFrequencyKey)) {
|
||||
service.getSignalManager().setFrequency(
|
||||
sharedPreferences.getInt(signalSamplingFrequencyKey, -1), service);
|
||||
}
|
||||
if (key == null || key.equals(metricUnitsKey)) {
|
||||
service.getSplitManager().setMetricUnits(
|
||||
sharedPreferences.getBoolean(metricUnitsKey, true));
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package com.google.android.apps.mytracks.services;
|
||||
|
||||
import com.google.android.apps.mytracks.MyTracksConstants;
|
||||
import com.google.android.apps.mytracks.util.ApiFeatures;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* Factory for producing a proper {@link SignalStrengthTask} according to the
|
||||
* current API level.
|
||||
*
|
||||
* @author Rodrigo Damazio
|
||||
*/
|
||||
public class SignalStrengthTaskFactory {
|
||||
private final boolean hasModernSignalStrength;
|
||||
|
||||
SignalStrengthTaskFactory(ApiFeatures apiFeatures) {
|
||||
this.hasModernSignalStrength = apiFeatures.hasModernSignalStrength();
|
||||
}
|
||||
|
||||
public PeriodicTask create(Context context) {
|
||||
if (hasModernSignalStrength) {
|
||||
Log.d(MyTracksConstants.TAG,
|
||||
"TrackRecordingService using modern signal strength api.");
|
||||
return new SignalStrengthTaskModern(context);
|
||||
} else {
|
||||
Log.w(MyTracksConstants.TAG,
|
||||
"TrackRecordingService using legacy signal strength api.");
|
||||
return new SignalStrengthTask(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
+215
-89
@@ -20,11 +20,16 @@ import static com.google.android.apps.mytracks.MyTracksConstants.RESUME_TRACK_EX
|
||||
import com.google.android.apps.mytracks.MyTracks;
|
||||
import com.google.android.apps.mytracks.MyTracksConstants;
|
||||
import com.google.android.apps.mytracks.MyTracksSettings;
|
||||
import com.google.android.apps.mytracks.content.MyTracksLocation;
|
||||
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
|
||||
import com.google.android.apps.mytracks.content.Sensor;
|
||||
import com.google.android.apps.mytracks.content.Track;
|
||||
import com.google.android.apps.mytracks.content.TracksColumns;
|
||||
import com.google.android.apps.mytracks.content.Waypoint;
|
||||
import com.google.android.apps.mytracks.content.WaypointsColumns;
|
||||
import com.google.android.apps.mytracks.content.Sensor.SensorDataSet;
|
||||
import com.google.android.apps.mytracks.services.sensors.SensorManager;
|
||||
import com.google.android.apps.mytracks.services.sensors.SensorManagerFactory;
|
||||
import com.google.android.apps.mytracks.stats.TripStatistics;
|
||||
import com.google.android.apps.mytracks.stats.TripStatisticsBuilder;
|
||||
import com.google.android.apps.mytracks.util.ApiFeatures;
|
||||
@@ -69,7 +74,7 @@ public class TrackRecordingService extends Service implements LocationListener {
|
||||
"http://maps.google.com/mapfiles/ms/micons/ylw-pushpin.png";
|
||||
|
||||
static final int MAX_AUTO_RESUME_TRACK_RETRY_ATTEMPTS = 3;
|
||||
|
||||
|
||||
private NotificationManager notificationManager;
|
||||
private LocationManager locationManager;
|
||||
private WakeLock wakeLock;
|
||||
@@ -109,9 +114,10 @@ public class TrackRecordingService extends Service implements LocationListener {
|
||||
* Status announcer executer.
|
||||
*/
|
||||
private PeriodicTaskExecuter announcementExecuter;
|
||||
private TaskExecuterManager signalManager;
|
||||
private SplitManager splitManager;
|
||||
|
||||
private SensorManager sensorManager;
|
||||
|
||||
private PreferenceManager prefManager;
|
||||
|
||||
/**
|
||||
@@ -215,7 +221,14 @@ public class TrackRecordingService extends Service implements LocationListener {
|
||||
|
||||
// Insert the new location:
|
||||
try {
|
||||
Uri pointUri = providerUtils.insertTrackPoint(location, trackId);
|
||||
Location locationToInsert = location;
|
||||
if (sensorManager != null && sensorManager.isEnabled()) {
|
||||
SensorDataSet sd = sensorManager.getSensorDataSet();
|
||||
if (sd != null && sensorManager.isDataValid()) {
|
||||
locationToInsert = new MyTracksLocation(location, sd);
|
||||
}
|
||||
}
|
||||
Uri pointUri = providerUtils.insertTrackPoint(locationToInsert, trackId);
|
||||
int pointId = Integer.parseInt(pointUri.getLastPathSegment());
|
||||
|
||||
// Update the current track:
|
||||
@@ -411,7 +424,6 @@ public class TrackRecordingService extends Service implements LocationListener {
|
||||
statsBuilder = new TripStatisticsBuilder(stats.getStartTime());
|
||||
setUpAnnouncer();
|
||||
|
||||
signalManager.restore();
|
||||
splitManager.restore();
|
||||
length = 0;
|
||||
lastValidLocation = null;
|
||||
@@ -525,11 +537,15 @@ public class TrackRecordingService extends Service implements LocationListener {
|
||||
if (lastLocation != null) {
|
||||
distanceToLast = location.distanceTo(lastLocation);
|
||||
}
|
||||
boolean hasSensorData = sensorManager != null
|
||||
&& sensorManager.isEnabled()
|
||||
&& sensorManager.getSensorDataSet() != null
|
||||
&& sensorManager.isDataValid();
|
||||
|
||||
// If the user has been stationary for two recording just record the first
|
||||
// two and ignore the rest. This code will only have an effect if the
|
||||
// maxRecordingDistance = 0
|
||||
if (distanceToLast == 0) {
|
||||
if (distanceToLast == 0 && !hasSensorData) {
|
||||
if (isMoving) {
|
||||
Log.d(MyTracksConstants.TAG, "Found two identical locations.");
|
||||
isMoving = false;
|
||||
@@ -549,7 +565,8 @@ public class TrackRecordingService extends Service implements LocationListener {
|
||||
Log.d(MyTracksConstants.TAG,
|
||||
"Not recording. More than two identical locations.");
|
||||
}
|
||||
} else if (distanceToLastRecorded > minRecordingDistance) {
|
||||
} else if (distanceToLastRecorded > minRecordingDistance
|
||||
|| hasSensorData) {
|
||||
if (lastLocation != null && !isMoving) {
|
||||
// Last location was the last stationary location. Need to go back and
|
||||
// add it.
|
||||
@@ -629,14 +646,11 @@ public class TrackRecordingService extends Service implements LocationListener {
|
||||
locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
|
||||
splitManager = new SplitManager(this);
|
||||
|
||||
SignalStrengthTaskFactory strengthTaskFactory =
|
||||
new SignalStrengthTaskFactory(ApiFeatures.getInstance());
|
||||
signalManager =
|
||||
new TaskExecuterManager(-1, strengthTaskFactory.create(this), this);
|
||||
|
||||
sensorManager = SensorManagerFactory.getSensorManager(this);
|
||||
prefManager = new PreferenceManager(this);
|
||||
registerLocationListener();
|
||||
/**
|
||||
|
||||
/*
|
||||
* After 5 min, check every minute that location listener still is
|
||||
* registered and spit out additional debugging info to the logs:
|
||||
*/
|
||||
@@ -710,17 +724,27 @@ public class TrackRecordingService extends Service implements LocationListener {
|
||||
showNotification();
|
||||
prefManager.shutdown();
|
||||
prefManager = null;
|
||||
binder = null;
|
||||
checkLocationListener.cancel();
|
||||
checkLocationListener = null;
|
||||
timer.cancel();
|
||||
timer.purge();
|
||||
unregisterLocationListener();
|
||||
shutdownAnnouncer();
|
||||
signalManager.shutdown();
|
||||
signalManager = null;
|
||||
splitManager.shutdown();
|
||||
splitManager = null;
|
||||
if (sensorManager != null) {
|
||||
sensorManager.onDestroy();
|
||||
sensorManager = null;
|
||||
}
|
||||
|
||||
// Make sure we have no indirect references to this service.
|
||||
locationManager = null;
|
||||
notificationManager = null;
|
||||
providerUtils = null;
|
||||
binder.detachFromService();
|
||||
binder = null;
|
||||
|
||||
// This should be the last operation.
|
||||
releaseWakeLock();
|
||||
|
||||
super.onDestroy();
|
||||
@@ -841,15 +865,25 @@ public class TrackRecordingService extends Service implements LocationListener {
|
||||
throw new IllegalStateException(
|
||||
"Unable to insert waypoint marker while not recording!");
|
||||
}
|
||||
|
||||
if (waypoint.getLocation() != null) {
|
||||
waypoint.setLength(length);
|
||||
waypoint.setDuration(waypoint.getLocation().getTime()
|
||||
- statsBuilder.getStatistics().getStartTime());
|
||||
Uri uri = providerUtils.insertWaypoint(waypoint);
|
||||
return Long.parseLong(uri.getLastPathSegment());
|
||||
|
||||
if (waypoint.getLocation() == null) {
|
||||
if (lastValidLocation == null) {
|
||||
Log.w(MyTracksConstants.TAG, "Cannot insert waypoint with no location");
|
||||
return -1;
|
||||
}
|
||||
|
||||
waypoint.setLocation(lastValidLocation);
|
||||
}
|
||||
return -1;
|
||||
|
||||
if (waypoint.getTrackId() < 0) {
|
||||
waypoint.setTrackId(recordingTrackId);
|
||||
}
|
||||
|
||||
waypoint.setLength(length);
|
||||
waypoint.setDuration(waypoint.getLocation().getTime()
|
||||
- statsBuilder.getStatistics().getStartTime());
|
||||
Uri uri = providerUtils.insertWaypoint(waypoint);
|
||||
return Long.parseLong(uri.getLastPathSegment());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -896,82 +930,153 @@ public class TrackRecordingService extends Service implements LocationListener {
|
||||
updateCurrentWaypoint();
|
||||
return Long.parseLong(uri.getLastPathSegment());
|
||||
}
|
||||
|
||||
|
||||
private ServiceBinder binder = new ServiceBinder(this);
|
||||
|
||||
/**
|
||||
* The ITrackRecordingService is defined through IDL.
|
||||
* TODO: There is a bug in Android that leaks Binder instances. This bug is
|
||||
* especially visible if we have a non-static class, as there is no way to
|
||||
* nullify reference to the outer class (the service).
|
||||
* A workaround is to use a static class and explicitly clear service
|
||||
* and detach it from the underlying Binder. With this approach, we minimize
|
||||
* the leak to 24 bytes per each service instance.
|
||||
*
|
||||
* For more details, see the following bug:
|
||||
* http://code.google.com/p/android/issues/detail?id=6426.
|
||||
*/
|
||||
private ITrackRecordingService.Stub binder =
|
||||
new ITrackRecordingService.Stub() {
|
||||
@Override
|
||||
public boolean isRecording() {
|
||||
return TrackRecordingService.this.isRecording();
|
||||
}
|
||||
private static class ServiceBinder extends ITrackRecordingService.Stub {
|
||||
private TrackRecordingService service;
|
||||
|
||||
public ServiceBinder(TrackRecordingService service) {
|
||||
this.service = service;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the reference to the outer class to minimize the leak.
|
||||
*/
|
||||
public void detachFromService() {
|
||||
this.service = null;
|
||||
attachInterface(null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRecording() {
|
||||
if (service == null) {
|
||||
throw new IllegalStateException("The service has been already detached!");
|
||||
}
|
||||
return service.isRecording();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getRecordingTrackId() {
|
||||
return recordingTrackId;
|
||||
}
|
||||
@Override
|
||||
public long getRecordingTrackId() {
|
||||
if (service == null) {
|
||||
throw new IllegalStateException("The service has been already detached!");
|
||||
}
|
||||
return service.recordingTrackId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasRecorded() {
|
||||
return providerUtils.getLastTrackId() >= 0;
|
||||
}
|
||||
@Override
|
||||
public boolean hasRecorded() {
|
||||
if (service == null) {
|
||||
throw new IllegalStateException("The service has been already detached!");
|
||||
}
|
||||
return service.providerUtils.getLastTrackId() >= 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long startNewTrack() {
|
||||
return TrackRecordingService.this.startNewTrack();
|
||||
}
|
||||
@Override
|
||||
public long startNewTrack() {
|
||||
if (service == null) {
|
||||
throw new IllegalStateException("The service has been already detached!");
|
||||
}
|
||||
return service.startNewTrack();
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert the given waypoint marker. Users can insert waypoint markers
|
||||
* to tag locations with a name, description, category etc.
|
||||
*
|
||||
* @param waypoint a waypoint
|
||||
* @return the unique id of the inserted marker
|
||||
*/
|
||||
@Override
|
||||
public long insertWaypointMarker(Waypoint waypoint) {
|
||||
return TrackRecordingService.this.insertWaypointMarker(waypoint);
|
||||
}
|
||||
/**
|
||||
* Insert the given waypoint marker. Users can insert waypoint markers
|
||||
* to tag locations with a name, description, category etc.
|
||||
*
|
||||
* @param waypoint a waypoint
|
||||
* @return the unique id of the inserted marker
|
||||
*/
|
||||
@Override
|
||||
public long insertWaypointMarker(Waypoint waypoint) {
|
||||
if (service == null) {
|
||||
throw new IllegalStateException("The service has been already detached!");
|
||||
}
|
||||
return service.insertWaypointMarker(waypoint);
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert a statistics marker. A statistics marker holds the stats for
|
||||
* the last segment up to this marker.
|
||||
*
|
||||
* @param location the location where to insert
|
||||
* @return the unique id of the inserted marker
|
||||
*/
|
||||
@Override
|
||||
public long insertStatisticsMarker(Location location) {
|
||||
return TrackRecordingService.this.insertStatisticsMarker(location);
|
||||
}
|
||||
/**
|
||||
* Insert a statistics marker. A statistics marker holds the stats for
|
||||
* the last segment up to this marker.
|
||||
*
|
||||
* @param location the location where to insert
|
||||
* @return the unique id of the inserted marker
|
||||
*/
|
||||
@Override
|
||||
public long insertStatisticsMarker(Location location) {
|
||||
if (service == null) {
|
||||
throw new IllegalStateException("The service has been already detached!");
|
||||
}
|
||||
return service.insertStatisticsMarker(location);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endCurrentTrack() {
|
||||
TrackRecordingService.this.endCurrentTrack();
|
||||
}
|
||||
@Override
|
||||
public void endCurrentTrack() {
|
||||
if (service == null) {
|
||||
throw new IllegalStateException("The service has been already detached!");
|
||||
}
|
||||
service.endCurrentTrack();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteAllTracks() {
|
||||
if (isRecording()) {
|
||||
throw new IllegalStateException(
|
||||
"Cannot delete all tracks while recording!");
|
||||
}
|
||||
providerUtils.deleteAllTracks();
|
||||
}
|
||||
@Override
|
||||
public void deleteAllTracks() {
|
||||
if (service == null) {
|
||||
throw new IllegalStateException("The service has been already detached!");
|
||||
}
|
||||
if (isRecording()) {
|
||||
throw new IllegalStateException("Cannot delete all tracks while recording!");
|
||||
}
|
||||
service.providerUtils.deleteAllTracks();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void recordLocation(Location loc) {
|
||||
onLocationChanged(loc);
|
||||
}
|
||||
};
|
||||
@Override
|
||||
public void recordLocation(Location loc) {
|
||||
if (service == null) {
|
||||
throw new IllegalStateException("The service has been already detached!");
|
||||
}
|
||||
service.onLocationChanged(loc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getSensorData() {
|
||||
if (service.sensorManager == null) {
|
||||
Log.d(MyTracksConstants.TAG, "No sensor manager for data.");
|
||||
return null;
|
||||
}
|
||||
if (service.sensorManager.getSensorDataSet() == null) {
|
||||
Log.d(MyTracksConstants.TAG, "Sensor data set is null.");
|
||||
return null;
|
||||
}
|
||||
return service.sensorManager.getSensorDataSet().toByteArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSensorState() {
|
||||
if (service.sensorManager == null) {
|
||||
Log.d(MyTracksConstants.TAG, "No sensor manager for data.");
|
||||
return Sensor.SensorState.NONE.getNumber();
|
||||
}
|
||||
return service.sensorManager.getSensorState().getNumber();
|
||||
}
|
||||
}
|
||||
|
||||
public long startNewTrack() {
|
||||
Log.d(MyTracksConstants.TAG, "TrackRecordingService.startNewTrack");
|
||||
if (recordingTrackId != -1 || isRecording) {
|
||||
throw new IllegalStateException("A track is already in progress!");
|
||||
}
|
||||
|
||||
|
||||
long startTime = System.currentTimeMillis();
|
||||
acquireWakeLock();
|
||||
|
||||
@@ -996,14 +1101,20 @@ public class TrackRecordingService extends Service implements LocationListener {
|
||||
showNotification();
|
||||
registerLocationListener();
|
||||
splitManager.restore();
|
||||
signalManager.restore();
|
||||
if (sensorManager != null) {
|
||||
sensorManager.onStartTrack();
|
||||
}
|
||||
|
||||
// Reset the number of auto-resume retries.
|
||||
setAutoResumeTrackRetries(
|
||||
getSharedPreferences(MyTracksSettings.SETTINGS_NAME, 0), 0);
|
||||
// Persist the current recording track.
|
||||
prefManager.setRecordingTrack(recordingTrackId);
|
||||
|
||||
|
||||
// Notify the world that we're now recording.
|
||||
sendTrackBroadcast(
|
||||
R.string.track_started_broadcast_action, recordingTrackId);
|
||||
|
||||
return recordingTrackId;
|
||||
}
|
||||
|
||||
@@ -1033,8 +1144,27 @@ public class TrackRecordingService extends Service implements LocationListener {
|
||||
"_id=" + recordingTrack.getId(), null);
|
||||
}
|
||||
showNotification();
|
||||
long recordedTrackId = recordingTrackId;
|
||||
prefManager.setRecordingTrack(recordingTrackId = -1);
|
||||
|
||||
if (sensorManager != null) {
|
||||
sensorManager.shutdown();
|
||||
}
|
||||
|
||||
releaseWakeLock();
|
||||
|
||||
// Notify the world that we're no longer recording.
|
||||
sendTrackBroadcast(
|
||||
R.string.track_stopped_broadcast_action, recordedTrackId);
|
||||
}
|
||||
|
||||
private void sendTrackBroadcast(int actionResId, long trackId) {
|
||||
Intent broadcastIntent =
|
||||
new Intent()
|
||||
.setAction(getString(actionResId))
|
||||
.putExtra(getString(R.string.track_id_broadcast_extra), trackId);
|
||||
sendBroadcast(broadcastIntent,
|
||||
getString(R.string.broadcast_notifications_permission));
|
||||
}
|
||||
|
||||
public TripStatistics getTripStatistics() {
|
||||
@@ -1110,8 +1240,4 @@ public class TrackRecordingService extends Service implements LocationListener {
|
||||
public SplitManager getSplitManager() {
|
||||
return splitManager;
|
||||
}
|
||||
|
||||
public TaskExecuterManager getSignalManager() {
|
||||
return signalManager;
|
||||
}
|
||||
}
|
||||
|
||||
+432
@@ -0,0 +1,432 @@
|
||||
/*
|
||||
* Copyright (C) 2010 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
|
||||
package com.google.android.apps.mytracks.services.sensors;
|
||||
|
||||
import com.google.android.apps.mytracks.MyTracksConstants;
|
||||
import com.google.android.apps.mytracks.content.Sensor;
|
||||
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.bluetooth.BluetoothSocket;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* This class does all the work for setting up and managing Bluetooth
|
||||
* connections with other devices. It has a thread that listens for incoming
|
||||
* connections, a thread for connecting with a device, and a thread for
|
||||
* performing data transmissions when connected.
|
||||
*
|
||||
* @author Sandor Dornbush
|
||||
*/
|
||||
public class BluetoothConnectionManager {
|
||||
// Unique UUID for this application
|
||||
private static final UUID SPP_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
|
||||
|
||||
private MessageParser parser;
|
||||
|
||||
// Member fields
|
||||
private final BluetoothAdapter adapter;
|
||||
private final Handler handler;
|
||||
private ConnectThread connectThread;
|
||||
private ConnectedThread connectedThread;
|
||||
|
||||
private Sensor.SensorState state;
|
||||
|
||||
// Message types sent from the BluetoothSenorService Handler
|
||||
public static final int MESSAGE_STATE_CHANGE = 1;
|
||||
public static final int MESSAGE_READ = 2;
|
||||
public static final int MESSAGE_WRITE = 3;
|
||||
public static final int MESSAGE_DEVICE_NAME = 4;
|
||||
|
||||
// Key names received from the BluetoothSenorService Handler
|
||||
public static final String DEVICE_NAME = "device_name";
|
||||
|
||||
/**
|
||||
* Constructor. Prepares a new BluetoothSensor session.
|
||||
*
|
||||
* @param context The UI Activity Context
|
||||
* @param handler A Handler to send messages back to the UI Activity
|
||||
*/
|
||||
public BluetoothConnectionManager(Handler handler, MessageParser parser) {
|
||||
this.adapter = BluetoothAdapter.getDefaultAdapter();
|
||||
this.state = Sensor.SensorState.NONE;
|
||||
this.handler = handler;
|
||||
this.parser = parser;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the current state of the sensor connection
|
||||
*
|
||||
* @param state An integer defining the current connection state
|
||||
*/
|
||||
private synchronized void setState(Sensor.SensorState state) {
|
||||
// TODO pretty print this.
|
||||
Log.d(MyTracksConstants.TAG, "setState(" + state + ")");
|
||||
this.state = state;
|
||||
|
||||
// Give the new state to the Handler so the UI Activity can update
|
||||
handler.obtainMessage(MESSAGE_STATE_CHANGE, state.getNumber(), -1).sendToTarget();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current connection state.
|
||||
*/
|
||||
public synchronized Sensor.SensorState getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the sensor service. Specifically start AcceptThread to begin a session
|
||||
* in listening (server) mode. Called by the Activity onResume()
|
||||
*/
|
||||
public synchronized void start() {
|
||||
Log.d(MyTracksConstants.TAG, "BluetoothConnectionManager.start()");
|
||||
|
||||
// Cancel any thread attempting to make a connection
|
||||
if (connectThread != null) {
|
||||
connectThread.cancel();
|
||||
connectThread = null;
|
||||
}
|
||||
|
||||
// Cancel any thread currently running a connection
|
||||
if (connectedThread != null) {
|
||||
connectedThread.cancel();
|
||||
connectedThread = null;
|
||||
}
|
||||
|
||||
setState(Sensor.SensorState.NONE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the ConnectThread to initiate a connection to a remote device.
|
||||
*
|
||||
* @param device The BluetoothDevice to connect
|
||||
*/
|
||||
public synchronized void connect(BluetoothDevice device) {
|
||||
Log.d(MyTracksConstants.TAG, "connect to: " + device);
|
||||
|
||||
// Cancel any thread attempting to make a connection
|
||||
if (state == Sensor.SensorState.CONNECTING) {
|
||||
if (connectThread != null) {
|
||||
connectThread.cancel();
|
||||
connectThread = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Cancel any thread currently running a connection
|
||||
if (connectedThread != null) {
|
||||
connectedThread.cancel();
|
||||
connectedThread = null;
|
||||
}
|
||||
|
||||
// Start the thread to connect with the given device
|
||||
connectThread = new ConnectThread(device);
|
||||
connectThread.start();
|
||||
setState(Sensor.SensorState.CONNECTING);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the ConnectedThread to begin managing a Bluetooth connection
|
||||
*
|
||||
* @param socket The BluetoothSocket on which the connection was made
|
||||
* @param device The BluetoothDevice that has been connected
|
||||
*/
|
||||
public synchronized void connected(BluetoothSocket socket,
|
||||
BluetoothDevice device) {
|
||||
Log.d(MyTracksConstants.TAG, "connected");
|
||||
|
||||
// Cancel the thread that completed the connection
|
||||
if (connectThread != null) {
|
||||
connectThread.cancel();
|
||||
connectThread = null;
|
||||
}
|
||||
|
||||
// Cancel any thread currently running a connection
|
||||
if (connectedThread != null) {
|
||||
connectedThread.cancel();
|
||||
connectedThread = null;
|
||||
}
|
||||
|
||||
// Start the thread to manage the connection and perform transmissions
|
||||
connectedThread = new ConnectedThread(socket);
|
||||
connectedThread.start();
|
||||
|
||||
// Send the name of the connected device back to the UI Activity
|
||||
Message msg = handler.obtainMessage(MESSAGE_DEVICE_NAME);
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString(DEVICE_NAME, device.getName());
|
||||
msg.setData(bundle);
|
||||
handler.sendMessage(msg);
|
||||
|
||||
setState(Sensor.SensorState.CONNECTED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop all threads
|
||||
*/
|
||||
public synchronized void stop() {
|
||||
Log.d(MyTracksConstants.TAG, "stop()");
|
||||
if (connectThread != null) {
|
||||
connectThread.cancel();
|
||||
connectThread = null;
|
||||
}
|
||||
if (connectedThread != null) {
|
||||
connectedThread.cancel();
|
||||
connectedThread = null;
|
||||
}
|
||||
setState(Sensor.SensorState.NONE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write to the ConnectedThread in an unsynchronized manner
|
||||
*
|
||||
* @param out The bytes to write
|
||||
* @see ConnectedThread#write(byte[])
|
||||
*/
|
||||
public void write(byte[] out) {
|
||||
// Create temporary object
|
||||
ConnectedThread r;
|
||||
// Synchronize a copy of the ConnectedThread
|
||||
synchronized (this) {
|
||||
if (state != Sensor.SensorState.CONNECTED) {
|
||||
return;
|
||||
}
|
||||
r = connectedThread;
|
||||
}
|
||||
// Perform the write unsynchronized
|
||||
r.write(out);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate that the connection attempt failed and notify the UI Activity.
|
||||
*/
|
||||
private void connectionFailed() {
|
||||
setState(Sensor.SensorState.DISCONNECTED);
|
||||
Log.i(MyTracksConstants.TAG, "Bluetooth connection failed.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate that the connection was lost and notify the UI Activity.
|
||||
*/
|
||||
private void connectionLost() {
|
||||
setState(Sensor.SensorState.DISCONNECTED);
|
||||
Log.i(MyTracksConstants.TAG, "Bluetooth connection lost.");
|
||||
}
|
||||
|
||||
/**
|
||||
* This thread runs while attempting to make an outgoing connection with a
|
||||
* device. It runs straight through; the connection either succeeds or fails.
|
||||
*/
|
||||
private class ConnectThread extends Thread {
|
||||
private final BluetoothSocket socket;
|
||||
private final BluetoothDevice device;
|
||||
|
||||
public ConnectThread(BluetoothDevice device) {
|
||||
setName("ConnectThread-" + device.getName());
|
||||
this.device = device;
|
||||
BluetoothSocket tmp = null;
|
||||
|
||||
// Get a BluetoothSocket for a connection with the
|
||||
// given BluetoothDevice
|
||||
try {
|
||||
tmp = getSocket();
|
||||
} catch (IOException e) {
|
||||
Log.e(MyTracksConstants.TAG, "create() failed", e);
|
||||
}
|
||||
socket = tmp;
|
||||
}
|
||||
|
||||
private BluetoothSocket getSocket() throws IOException {
|
||||
try {
|
||||
Class<? extends BluetoothDevice> c = device.getClass();
|
||||
Method insecure = c.getMethod("createInsecureRfcommSocket",
|
||||
Integer.class);
|
||||
insecure.setAccessible(true);
|
||||
return (BluetoothSocket) insecure.invoke(device, 1);
|
||||
} catch (SecurityException e) {
|
||||
Log.e(MyTracksConstants.TAG, "Unable to get insecure connect.", e);
|
||||
} catch (NoSuchMethodException e) {
|
||||
Log.e(MyTracksConstants.TAG, "Unable to get insecure connect.", e);
|
||||
} catch (IllegalArgumentException e) {
|
||||
Log.e(MyTracksConstants.TAG, "Unable to get insecure connect.", e);
|
||||
} catch (IllegalAccessException e) {
|
||||
Log.e(MyTracksConstants.TAG, "Unable to get insecure connect.", e);
|
||||
} catch (InvocationTargetException e) {
|
||||
Log.e(MyTracksConstants.TAG, "Unable to get insecure connect.", e);
|
||||
}
|
||||
return device.createRfcommSocketToServiceRecord(SPP_UUID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
Log.d(MyTracksConstants.TAG, "BEGIN mConnectThread");
|
||||
|
||||
// Always cancel discovery because it will slow down a connection
|
||||
adapter.cancelDiscovery();
|
||||
|
||||
// Make a connection to the BluetoothSocket
|
||||
try {
|
||||
// This is a blocking call and will only return on a
|
||||
// successful connection or an exception
|
||||
socket.connect();
|
||||
} catch (IOException e) {
|
||||
connectionFailed();
|
||||
// Close the socket
|
||||
try {
|
||||
socket.close();
|
||||
} catch (IOException e2) {
|
||||
Log.e(MyTracksConstants.TAG,
|
||||
"unable to close() socket during connection failure", e2);
|
||||
}
|
||||
// Start the service over to restart listening mode
|
||||
BluetoothConnectionManager.this.start();
|
||||
return;
|
||||
}
|
||||
|
||||
// Reset the ConnectThread because we're done
|
||||
synchronized (BluetoothConnectionManager.this) {
|
||||
connectThread = null;
|
||||
}
|
||||
|
||||
// Start the connected thread
|
||||
connected(socket, device);
|
||||
}
|
||||
|
||||
public void cancel() {
|
||||
try {
|
||||
socket.close();
|
||||
} catch (IOException e) {
|
||||
Log.e(MyTracksConstants.TAG, "close() of connect socket failed", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This thread runs during a connection with a remote device. It handles all
|
||||
* incoming and outgoing transmissions.
|
||||
*/
|
||||
private class ConnectedThread extends Thread {
|
||||
private final BluetoothSocket btSocket;
|
||||
private final InputStream mmInStream;
|
||||
private final OutputStream mmOutStream;
|
||||
|
||||
public ConnectedThread(BluetoothSocket socket) {
|
||||
Log.d(MyTracksConstants.TAG, "create ConnectedThread");
|
||||
btSocket = socket;
|
||||
InputStream tmpIn = null;
|
||||
OutputStream tmpOut = null;
|
||||
|
||||
// Get the BluetoothSocket input and output streams
|
||||
try {
|
||||
tmpIn = socket.getInputStream();
|
||||
tmpOut = socket.getOutputStream();
|
||||
} catch (IOException e) {
|
||||
Log.e(MyTracksConstants.TAG, "temp sockets not created", e);
|
||||
}
|
||||
|
||||
mmInStream = tmpIn;
|
||||
mmOutStream = tmpOut;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
Log.i(MyTracksConstants.TAG, "BEGIN mConnectedThread");
|
||||
byte[] buffer = new byte[parser.getFrameSize()];
|
||||
int bytes;
|
||||
int offset = 0;
|
||||
|
||||
// Keep listening to the InputStream while connected
|
||||
while (true) {
|
||||
try {
|
||||
// Read from the InputStream
|
||||
bytes = mmInStream.read(buffer, offset, parser.getFrameSize() - offset);
|
||||
|
||||
if (bytes < 0) {
|
||||
throw new IOException("EOF reached");
|
||||
}
|
||||
|
||||
offset += bytes;
|
||||
|
||||
if (offset != parser.getFrameSize()) {
|
||||
// partial frame received, call read() again to receive the rest
|
||||
continue;
|
||||
}
|
||||
|
||||
// check if its a valid frame
|
||||
if (!parser.isValid(buffer)) {
|
||||
int index = parser.findNextAlignment(buffer);
|
||||
if (index > 0) {
|
||||
// re-align
|
||||
offset = parser.getFrameSize() - index;
|
||||
System.arraycopy(buffer, index, buffer, 0, offset);
|
||||
Log.w(MyTracksConstants.TAG, "Misaligned data, found new message at " +
|
||||
index + " recovering...");
|
||||
continue;
|
||||
}
|
||||
Log.w(MyTracksConstants.TAG, "Could not find valid data, dropping data");
|
||||
offset = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
offset = 0;
|
||||
|
||||
// Send the obtained bytes to the UI Activity
|
||||
handler.obtainMessage(MESSAGE_READ, bytes, -1, buffer)
|
||||
.sendToTarget();
|
||||
} catch (IOException e) {
|
||||
Log.e(MyTracksConstants.TAG, "disconnected", e);
|
||||
connectionLost();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write to the connected OutStream.
|
||||
*
|
||||
* @param buffer The bytes to write
|
||||
*/
|
||||
public void write(byte[] buffer) {
|
||||
try {
|
||||
mmOutStream.write(buffer);
|
||||
|
||||
// Share the sent message back to the UI Activity
|
||||
handler.obtainMessage(MESSAGE_WRITE, -1, -1, buffer).sendToTarget();
|
||||
} catch (IOException e) {
|
||||
Log.e(MyTracksConstants.TAG, "Exception during write", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void cancel() {
|
||||
try {
|
||||
btSocket.close();
|
||||
} catch (IOException e) {
|
||||
Log.e(MyTracksConstants.TAG, "close() of connect socket failed", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+166
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
* Copyright 2010 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package com.google.android.apps.mytracks.services.sensors;
|
||||
|
||||
import com.google.android.apps.mytracks.MyTracksConstants;
|
||||
import com.google.android.apps.mytracks.MyTracksSettings;
|
||||
import com.google.android.apps.mytracks.content.Sensor;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
||||
/**
|
||||
* Manage the connection to a bluetooth sensor.
|
||||
*
|
||||
* @author Sandor Dornbush
|
||||
*/
|
||||
public class BluetoothSensorManager extends SensorManager {
|
||||
|
||||
// Local Bluetooth adapter
|
||||
private BluetoothAdapter bluetoothAdapter = null;
|
||||
|
||||
// Member object for the sensor threads and connections.
|
||||
private BluetoothConnectionManager connectionManager = null;
|
||||
|
||||
// Name of the connected device
|
||||
private String connectedDeviceName = null;
|
||||
|
||||
private Context context = null;
|
||||
|
||||
private Sensor.SensorDataSet sensorDataSet = null;
|
||||
|
||||
private MessageParser parser;
|
||||
|
||||
public BluetoothSensorManager(
|
||||
Context context, MessageParser parser) {
|
||||
this.context = context;
|
||||
this.parser = parser;
|
||||
// Get local Bluetooth adapter
|
||||
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
|
||||
// If BT is not available or not enabled quit.
|
||||
if (!isEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
setupSensor();
|
||||
}
|
||||
|
||||
private void setupSensor() {
|
||||
Log.d(MyTracksConstants.TAG, "setupSensor()");
|
||||
|
||||
// Initialize the BluetoothSensorAdapter to perform bluetooth connections.
|
||||
connectionManager = new BluetoothConnectionManager(messageHandler, parser);
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
return bluetoothAdapter != null && bluetoothAdapter.isEnabled();
|
||||
}
|
||||
|
||||
public void setupChannel() {
|
||||
if (!isEnabled() || connectionManager == null) {
|
||||
Log.w(MyTracksConstants.TAG, "Disabled manager onStartTrack");
|
||||
return;
|
||||
}
|
||||
SharedPreferences prefs =
|
||||
context.getSharedPreferences(MyTracksSettings.SETTINGS_NAME, 0);
|
||||
String address =
|
||||
prefs.getString(context.getString(R.string.bluetooth_sensor_key), null);
|
||||
if (address == null) {
|
||||
return;
|
||||
}
|
||||
Log.w(MyTracksConstants.TAG, "Connecting to bluetooth sensor: " + address);
|
||||
// Get the BluetoothDevice object
|
||||
BluetoothDevice device = bluetoothAdapter.getRemoteDevice(address);
|
||||
// Attempt to connect to the device
|
||||
connectionManager.connect(device);
|
||||
|
||||
// Performing this check in onResume() covers the case in which BT was
|
||||
// not enabled during onStart(), so we were paused to enable it...
|
||||
// onResume() will be called when ACTION_REQUEST_ENABLE activity returns.
|
||||
if (connectionManager != null) {
|
||||
// Only if the state is STATE_NONE, do we know that we haven't started
|
||||
// already
|
||||
if (connectionManager.getState() == Sensor.SensorState.NONE) {
|
||||
// Start the Bluetooth sensor services
|
||||
Log.w(MyTracksConstants.TAG, "Disabled manager onStartTrack");
|
||||
connectionManager.start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void onDestroy() {
|
||||
// Stop the Bluetooth sensor services
|
||||
if (connectionManager != null) {
|
||||
connectionManager.stop();
|
||||
}
|
||||
}
|
||||
|
||||
public Sensor.SensorDataSet getSensorDataSet() {
|
||||
return sensorDataSet;
|
||||
}
|
||||
|
||||
public Sensor.SensorState getSensorState() {
|
||||
return (connectionManager == null)
|
||||
? Sensor.SensorState.NONE
|
||||
: connectionManager.getState();
|
||||
}
|
||||
|
||||
// The Handler that gets information back from the BluetoothSensorService
|
||||
private final Handler messageHandler = new Handler() {
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
switch (msg.what) {
|
||||
case BluetoothConnectionManager.MESSAGE_STATE_CHANGE:
|
||||
// TODO should we update the SensorManager state var?
|
||||
Log.i(MyTracksConstants.TAG, "MESSAGE_STATE_CHANGE: " + msg.arg1);
|
||||
break;
|
||||
case BluetoothConnectionManager.MESSAGE_WRITE:
|
||||
break;
|
||||
case BluetoothConnectionManager.MESSAGE_READ:
|
||||
byte[] readBuf = null;
|
||||
try {
|
||||
readBuf = (byte[]) msg.obj;
|
||||
sensorDataSet = parser.parseBuffer(readBuf);
|
||||
Log.d(MyTracksConstants.TAG, "MESSAGE_READ: " + sensorDataSet.toString());
|
||||
} catch (IllegalArgumentException iae) {
|
||||
sensorDataSet = null;
|
||||
Log.i(MyTracksConstants.TAG,
|
||||
"Got bad sensor data: " + new String(readBuf, 0, readBuf.length),
|
||||
iae);
|
||||
} catch (RuntimeException re) {
|
||||
sensorDataSet = null;
|
||||
Log.i(MyTracksConstants.TAG, "Unexpected exception on read.", re);
|
||||
}
|
||||
break;
|
||||
case BluetoothConnectionManager.MESSAGE_DEVICE_NAME:
|
||||
// save the connected device's name
|
||||
connectedDeviceName =
|
||||
msg.getData().getString(BluetoothConnectionManager.DEVICE_NAME);
|
||||
Toast.makeText(context.getApplicationContext(),
|
||||
"Connected to " + connectedDeviceName, Toast.LENGTH_SHORT)
|
||||
.show();
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (C) 2010 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
|
||||
package com.google.android.apps.mytracks.services.sensors;
|
||||
|
||||
import com.google.android.apps.mytracks.content.Sensor;
|
||||
|
||||
/**
|
||||
* An interface for parsing a byte array to a SensorData object.
|
||||
*
|
||||
* @author Sandor Dornbush
|
||||
*/
|
||||
public interface MessageParser {
|
||||
|
||||
public int getFrameSize();
|
||||
|
||||
public Sensor.SensorDataSet parseBuffer(byte[] readBuff);
|
||||
|
||||
public boolean isValid(byte[] buffer);
|
||||
|
||||
public int findNextAlignment(byte[] buffer);
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Copyright 2010 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package com.google.android.apps.mytracks.services.sensors;
|
||||
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import com.google.android.apps.mytracks.MyTracksConstants;
|
||||
import com.google.android.apps.mytracks.content.Sensor;
|
||||
|
||||
/**
|
||||
* Manage the connection to a sensor.
|
||||
*
|
||||
* @author Sandor Dornbush
|
||||
*/
|
||||
public abstract class SensorManager {
|
||||
|
||||
/**
|
||||
* The maximum age where the data is considered valid.
|
||||
*/
|
||||
public static final long MAX_AGE = 5000;
|
||||
|
||||
/**
|
||||
* Time to wait after a time out to retry.
|
||||
*/
|
||||
public static final int RETRY_PERIOD = 30000;
|
||||
|
||||
private Sensor.SensorState sensorState = Sensor.SensorState.NONE;
|
||||
|
||||
private long sensorStateTimestamp = 0;
|
||||
|
||||
/**
|
||||
* A task to run periodically to check to see if connection was lost.
|
||||
*/
|
||||
private TimerTask checkSensorManager = new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
Log.i(MyTracksConstants.TAG,
|
||||
"SensorManager state: " + getSensorState());
|
||||
switch (getSensorState()) {
|
||||
case CONNECTING:
|
||||
long age = System.currentTimeMillis() - getSensorStateTimestamp();
|
||||
if (age > 2 * RETRY_PERIOD) {
|
||||
Log.i(MyTracksConstants.TAG, "Retrying connecting SensorManager.");
|
||||
setupChannel();
|
||||
}
|
||||
break;
|
||||
case DISCONNECTED:
|
||||
Log.i(MyTracksConstants.TAG,
|
||||
"Re-registering disconnected SensoManager.");
|
||||
setupChannel();
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* This timer invokes periodically the checkLocationListener timer task.
|
||||
*/
|
||||
private final Timer timer = new Timer();
|
||||
|
||||
/**
|
||||
* Is the sensor that this manages enabled.
|
||||
* @return true if the sensor is enabled
|
||||
*/
|
||||
public abstract boolean isEnabled();
|
||||
|
||||
/**
|
||||
* This is called when my tracks starts recording a new track.
|
||||
* This is the place to open connections to the sensor.
|
||||
*/
|
||||
public void onStartTrack() {
|
||||
setupChannel();
|
||||
timer.schedule(checkSensorManager, RETRY_PERIOD, RETRY_PERIOD);
|
||||
}
|
||||
|
||||
public abstract void setupChannel();
|
||||
|
||||
public void shutdown() {
|
||||
timer.cancel();
|
||||
onDestroy();
|
||||
}
|
||||
|
||||
/**
|
||||
* This is called when my tracks stops recording.
|
||||
* This is the place to shutdown any open connections.
|
||||
*/
|
||||
public abstract void onDestroy();
|
||||
|
||||
/**
|
||||
* Return the last sensor reading.
|
||||
* @return The last reading from the sensor.
|
||||
*/
|
||||
public abstract Sensor.SensorDataSet getSensorDataSet();
|
||||
|
||||
public void setSensorState(Sensor.SensorState sensorState) {
|
||||
this.sensorState = sensorState;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current sensor state.
|
||||
* @return The current sensor state.
|
||||
*/
|
||||
public Sensor.SensorState getSensorState() {
|
||||
return sensorState;
|
||||
}
|
||||
|
||||
public long getSensorStateTimestamp() {
|
||||
return sensorStateTimestamp;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return True if the data is recent enough to be considered valid.
|
||||
*/
|
||||
public boolean isDataValid() {
|
||||
return (System.currentTimeMillis() - getSensorDataSet().getCreationTime()) < MAX_AGE;
|
||||
}
|
||||
|
||||
}
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2009 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
|
||||
package com.google.android.apps.mytracks.services.sensors;
|
||||
|
||||
import com.google.android.apps.mytracks.MyTracksConstants;
|
||||
import com.google.android.apps.mytracks.MyTracksSettings;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* A factory of SensorManagers.
|
||||
*
|
||||
* @author Sandor Dornbush
|
||||
*/
|
||||
public class SensorManagerFactory {
|
||||
|
||||
private SensorManagerFactory() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a new sensor manager.
|
||||
* @param context Context to fetch system preferences.
|
||||
* @return The sensor manager that corresponds to the sensor type setting.
|
||||
*/
|
||||
public static SensorManager getSensorManager(Context context) {
|
||||
SharedPreferences prefs =
|
||||
context.getSharedPreferences(MyTracksSettings.SETTINGS_NAME, 0);
|
||||
if (prefs == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String sensor = prefs.getString(context.getString(R.string.sensor_type_key),
|
||||
null);
|
||||
Log.i(MyTracksConstants.TAG, "Creating sensor of type: " + sensor);
|
||||
|
||||
if (sensor == null) {
|
||||
return null;
|
||||
} else if (sensor.equals(context.getString(R.string.zephyr_sensor_type))) {
|
||||
return new ZephyrSensorManager(context);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2010 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package com.google.android.apps.mytracks.services.sensors;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.google.android.apps.mytracks.content.Sensor;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
|
||||
/**
|
||||
* A collection of methods for message parsers.
|
||||
*
|
||||
* @author Sandor Dornbush
|
||||
*/
|
||||
public class SensorUtils {
|
||||
|
||||
private SensorUtils() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract one unsigned short from a big endian byte array.
|
||||
* @param buffer the buffer to extract the short from
|
||||
* @param index the first byte to be interpreted as part of the short
|
||||
* @return The unsigned short at the given index in the buffer
|
||||
*/
|
||||
public static int unsignedShortToInt(byte[] buffer, int index) {
|
||||
int r = (buffer[index] & 0xFF) << 8;
|
||||
r |= buffer[index + 1] & 0xFF;
|
||||
return r;
|
||||
}
|
||||
|
||||
public static String getStateAsString(Sensor.SensorState state, Context c) {
|
||||
switch (state) {
|
||||
case NONE:
|
||||
return c.getString(R.string.none);
|
||||
case CONNECTING:
|
||||
return c.getString(R.string.connecting);
|
||||
case CONNECTED:
|
||||
return c.getString(R.string.connected);
|
||||
case DISCONNECTED:
|
||||
return c.getString(R.string.disconnected);
|
||||
case SENDING:
|
||||
return c.getString(R.string.sending);
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright 2010 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package com.google.android.apps.mytracks.services.sensors;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import com.google.android.apps.mytracks.MyTracksConstants;
|
||||
import com.google.android.apps.mytracks.content.Sensor;
|
||||
|
||||
/**
|
||||
* An implementation of a SensorData parser for Zephyr HRM.
|
||||
*
|
||||
* @author Sandor Dornbush
|
||||
*/
|
||||
public class ZephyrMessageParser implements MessageParser {
|
||||
|
||||
@Override
|
||||
public Sensor.SensorDataSet parseBuffer(byte[] buffer) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < buffer.length; i++) {
|
||||
sb.append(String.format("%02X", buffer[i]));
|
||||
}
|
||||
Log.w(MyTracksConstants.TAG, "Got zephyr data: " + sb);
|
||||
// The provided units are 1/16 strides per minute.
|
||||
int cadence = SensorUtils.unsignedShortToInt(buffer, 56);
|
||||
// Heart Rate
|
||||
Sensor.SensorData.Builder b = Sensor.SensorData.newBuilder()
|
||||
.setValue(buffer[12] & 0xFF)
|
||||
.setState(Sensor.SensorState.SENDING);
|
||||
// Cadence
|
||||
//.setCadence(cadence / 16)
|
||||
//.build();
|
||||
Sensor.SensorDataSet sds =
|
||||
Sensor.SensorDataSet.newBuilder()
|
||||
.setCreationTime(System.currentTimeMillis())
|
||||
.setHeartRate(b)
|
||||
.build();
|
||||
|
||||
return sds;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid(byte[] buffer) {
|
||||
// TODO crc etc.
|
||||
return buffer[0] == 0x02 && buffer[59] == 0x03;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFrameSize() {
|
||||
return 60;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int findNextAlignment(byte[] buffer) {
|
||||
// TODO test or understand this code.
|
||||
for (int i = 0; i < buffer.length - 1; i++) {
|
||||
if (buffer[i] == 0x03 && buffer[i+1] == 0x02) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright 2010 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package com.google.android.apps.mytracks.services.sensors;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
public class ZephyrSensorManager extends BluetoothSensorManager {
|
||||
|
||||
public ZephyrSensorManager(Context context) {
|
||||
super(context, new ZephyrMessageParser());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -102,10 +102,6 @@ public class ApiFeatures {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean hasModernSignalStrength() {
|
||||
return getApiLevel() >= 7;
|
||||
}
|
||||
|
||||
public boolean hasStrictMode() {
|
||||
return getApiLevel() >= 9;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
* Copyright 2010 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package com.google.android.apps.mytracks.util;
|
||||
|
||||
import com.google.android.apps.mytracks.MyTracksConstants;
|
||||
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.bluetooth.BluetoothClass;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.os.Build;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Utilities for dealing with bluetooth devices.
|
||||
* This can be used safely even in systems that don't support bluetooth,
|
||||
* in which case a dummy implementation will be used.
|
||||
*
|
||||
* @author Rodrigo Damazio
|
||||
*/
|
||||
public abstract class BluetoothDeviceUtils {
|
||||
public static final String ANY_DEVICE = "any";
|
||||
private static BluetoothDeviceUtils instance;
|
||||
|
||||
/**
|
||||
* Dummy implementation, for systems that don't support bluetooth.
|
||||
*/
|
||||
private static class DummyImpl extends BluetoothDeviceUtils {
|
||||
@Override
|
||||
public void populateDeviceLists(List<String> deviceNames, List<String> deviceAddresses) {
|
||||
// Do nothing - no devices to add
|
||||
}
|
||||
|
||||
@Override
|
||||
public BluetoothDevice findDeviceMatching(String targetDeviceAddress) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Real implementation, for systems that DO support bluetooth.
|
||||
*/
|
||||
private static class RealImpl extends BluetoothDeviceUtils {
|
||||
private final BluetoothAdapter bluetoothAdapter;
|
||||
|
||||
public RealImpl() {
|
||||
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
|
||||
|
||||
if (bluetoothAdapter == null) {
|
||||
throw new IllegalStateException("Unable to get bluetooth adapter");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void populateDeviceLists(List<String> deviceNames, List<String> deviceAddresses) {
|
||||
ensureNotDiscovering();
|
||||
|
||||
Set<BluetoothDevice> pairedDevices = bluetoothAdapter.getBondedDevices();
|
||||
for (BluetoothDevice device : pairedDevices) {
|
||||
BluetoothClass bluetoothClass = device.getBluetoothClass();
|
||||
if (bluetoothClass != null) {
|
||||
// Not really sure what we want, but I know what we don't want.
|
||||
switch(bluetoothClass.getMajorDeviceClass()) {
|
||||
case BluetoothClass.Device.Major.COMPUTER:
|
||||
case BluetoothClass.Device.Major.PHONE:
|
||||
break;
|
||||
default:
|
||||
deviceAddresses.add(device.getAddress());
|
||||
deviceNames.add(device.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BluetoothDevice findDeviceMatching(String targetDeviceAddress) {
|
||||
if (targetDeviceAddress.equals(ANY_DEVICE)) {
|
||||
return findAnyDevice();
|
||||
} else {
|
||||
return findDeviceByAddress(targetDeviceAddress);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds and returns the first suitable bluetooth sensor.
|
||||
*/
|
||||
private BluetoothDevice findAnyDevice() {
|
||||
ensureNotDiscovering();
|
||||
|
||||
Set<BluetoothDevice> pairedDevices = bluetoothAdapter.getBondedDevices();
|
||||
for (BluetoothDevice device : pairedDevices) {
|
||||
// Look for the first paired computer device
|
||||
if (isSuitableDevice(device)) {
|
||||
return device;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds and returns a device with the given address, or null if it's not
|
||||
* a suitable sensor.
|
||||
*/
|
||||
private BluetoothDevice findDeviceByAddress(String targetDeviceAddress) {
|
||||
ensureNotDiscovering();
|
||||
|
||||
BluetoothDevice device = bluetoothAdapter.getRemoteDevice(targetDeviceAddress);
|
||||
if (isSuitableDevice(device)) {
|
||||
return device;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures the bluetooth adapter is not in discovery mode.
|
||||
*/
|
||||
private void ensureNotDiscovering() {
|
||||
// If it's in discovery mode, cancel that for now.
|
||||
bluetoothAdapter.cancelDiscovery();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the given device is a suitable sensor.
|
||||
*
|
||||
* @param device the device to check
|
||||
* @return true if it's suitable, false otherwise
|
||||
*/
|
||||
private boolean isSuitableDevice(BluetoothDevice device) {
|
||||
// Check that the device is bonded
|
||||
if (device.getBondState() != BluetoothDevice.BOND_BONDED) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the proper (singleton) instance of this class.
|
||||
*/
|
||||
public static BluetoothDeviceUtils getInstance() {
|
||||
if (instance == null) {
|
||||
if (!isBluetoothMethodSupported()) {
|
||||
Log.d(MyTracksConstants.TAG, "Using dummy bluetooth utils");
|
||||
instance = new DummyImpl();
|
||||
} else {
|
||||
Log.d(MyTracksConstants.TAG, "Using real bluetooth utils");
|
||||
try {
|
||||
instance = new RealImpl();
|
||||
} catch (IllegalStateException ise) {
|
||||
Log.w(MyTracksConstants.TAG, "Oops, I mean, using dummy bluetooth utils", ise);
|
||||
instance = new DummyImpl();
|
||||
}
|
||||
}
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Populates the given lists with the names and addresses of all suitable
|
||||
* bluetooth devices.
|
||||
*
|
||||
* @param deviceNames the list to populate with user-visible names
|
||||
* @param deviceAddresses the list to populate with device addresses
|
||||
*/
|
||||
public abstract void populateDeviceLists(List<String> deviceNames, List<String> deviceAddresses);
|
||||
|
||||
/**
|
||||
* Finds the bluetooth device with the given address.
|
||||
*
|
||||
* @param targetDeviceAddress the address of the device, or
|
||||
* {@link #ANY_DEVICE} for using the first suitable device
|
||||
* @return the device's descriptor, or null if not found
|
||||
*/
|
||||
public abstract BluetoothDevice findDeviceMatching(String targetDeviceAddress);
|
||||
|
||||
/**
|
||||
* @return whether the bluetooth method is supported on this device
|
||||
*/
|
||||
public static boolean isBluetoothMethodSupported() {
|
||||
return Integer.parseInt(Build.VERSION.SDK) >= 5;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="src" path="gen"/>
|
||||
<classpathentry exported="true" kind="lib" path="libs/protobuf-java-2.3.0-lite.jar"/>
|
||||
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
</classpath>
|
||||
@@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>MyTracksLib</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>com.android.ide.eclipse.adt.ApkBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>com.android.ide.eclipse.adt.AndroidNature</nature>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
||||
@@ -0,0 +1,12 @@
|
||||
#Sun Nov 28 01:17:12 PST 2010
|
||||
eclipse.preferences.version=1
|
||||
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
|
||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
|
||||
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
|
||||
org.eclipse.jdt.core.compiler.compliance=1.6
|
||||
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
|
||||
org.eclipse.jdt.core.compiler.debug.localVariable=generate
|
||||
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
|
||||
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.source=1.6
|
||||
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright 2010 Google Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.google.android.apps.mytracks.lib"
|
||||
android:versionCode="1"
|
||||
android:versionName="1.0">
|
||||
<!--
|
||||
THIS IS A LIBRARY PROJECT.
|
||||
See http://developer.android.com/guide/developing/eclipse-adt.html#libraryProject
|
||||
for details on what should go here vs in the application project.
|
||||
-->
|
||||
<application android:icon="@drawable/arrow_icon"
|
||||
android:label="@string/lib_name">
|
||||
</application>
|
||||
<uses-sdk android:minSdkVersion="3" />
|
||||
</manifest>
|
||||
@@ -0,0 +1,12 @@
|
||||
# This file is automatically generated by Android Tools.
|
||||
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
|
||||
#
|
||||
# This file must be checked in Version Control Systems.
|
||||
#
|
||||
# To customize properties used by the Ant build system use,
|
||||
# "build.properties", and override values to adapt the script to your
|
||||
# project structure.
|
||||
|
||||
# Project target.
|
||||
target=android-8
|
||||
android.library=true
|
||||
Binary file not shown.
@@ -0,0 +1,53 @@
|
||||
// Copyright 2010 Google Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
// use this file except in compliance with the License. You may obtain a copy of
|
||||
// the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
// License for the specific language governing permissions and limitations under
|
||||
// the License.
|
||||
|
||||
package com.google.android.apps.mytracks.content;
|
||||
|
||||
option optimize_for = LITE_RUNTIME;
|
||||
|
||||
// An enumeration of the state of a single sensor.
|
||||
enum SensorState {
|
||||
// There is no sensor.
|
||||
NONE = 1;
|
||||
|
||||
// Now initiating an outgoing connection.
|
||||
CONNECTING = 2;
|
||||
|
||||
// Now connected to a remote device.
|
||||
CONNECTED = 3;
|
||||
|
||||
// A state where the sensor is not connected.
|
||||
DISCONNECTED = 4;
|
||||
|
||||
// This is the only state where the sensor data can be used.
|
||||
SENDING = 5;
|
||||
};
|
||||
|
||||
// The state and possible reading for one integer sensor.
|
||||
message SensorData {
|
||||
required SensorState state = 1 [default = NONE];
|
||||
|
||||
// Value is only defined if state = SENDING.
|
||||
optional int32 value = 2;
|
||||
};
|
||||
|
||||
// A message to encapsulate sensor readings associated with a track point.
|
||||
message SensorDataSet {
|
||||
// This is a required field.
|
||||
optional uint64 creation_time = 1 [default = 0];
|
||||
|
||||
optional SensorData heart_rate = 2;
|
||||
optional SensorData cadence = 3;
|
||||
optional SensorData power = 4;
|
||||
}
|
||||
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright 2010 Google Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<resources>
|
||||
<string name="lib_name">My Tracks Base Library</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,35 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright 2010 Google Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<resources>
|
||||
<!-- Permissions -->
|
||||
<!-- This must be kept in sync with AndroidManifest.xml (we can't reference it there) -->
|
||||
<string name="broadcast_notifications_permission">com.google.android.apps.mytracks.TRACK_NOTIFICATIONS</string>
|
||||
<string name="read_track_data_permission">com.google.android.apps.mytracks.READ_TRACK_DATA</string>
|
||||
<string name="write_track_data_permission">com.google.android.apps.mytracks.WRITE_TRACK_DATA</string>
|
||||
|
||||
<!-- Broadcast notification Intent constants -->
|
||||
<string name="track_started_broadcast_action">com.google.android.apps.mytracks.TRACK_STARTED</string>
|
||||
<string name="track_paused_broadcast_action">com.google.android.apps.mytracks.TRACK_PAUSED</string>
|
||||
<string name="track_resumed_broadcast_action">com.google.android.apps.mytracks.TRACK_RESUMED</string>
|
||||
<string name="track_stopped_broadcast_action">com.google.android.apps.mytracks.TRACK_STOPPED</string>
|
||||
<string name="track_id_broadcast_extra">com.google.android.apps.mytracks.TRACK_ID</string>
|
||||
|
||||
<!-- My Tracks service constants -->
|
||||
<string name="mytracks_service_class">com.google.android.apps.mytracks.services.TrackRecordingService</string>
|
||||
<string name="mytracks_service_package">com.google.android.maps.mytracks</string>
|
||||
|
||||
</resources>
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright 2010 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package com.google.android.apps.mytracks.content;
|
||||
|
||||
import android.location.Location;
|
||||
|
||||
/**
|
||||
* This class extends the standard Android location with extra information.
|
||||
*
|
||||
* @author Sandor Dornbush
|
||||
*/
|
||||
public class MyTracksLocation extends Location {
|
||||
|
||||
private Sensor.SensorDataSet sensorDataSet = null;
|
||||
|
||||
/**
|
||||
* The id of this location from the provider.
|
||||
*/
|
||||
private int id = -1;
|
||||
|
||||
public MyTracksLocation(Location location, Sensor.SensorDataSet sd) {
|
||||
super(location);
|
||||
this.sensorDataSet = sd;
|
||||
}
|
||||
|
||||
public MyTracksLocation(String string) {
|
||||
super(string);
|
||||
}
|
||||
|
||||
public Sensor.SensorDataSet getSensorDataSet() {
|
||||
return sensorDataSet;
|
||||
}
|
||||
|
||||
public void setSensorData(Sensor.SensorDataSet sensorData) {
|
||||
this.sensorDataSet = sensorData;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
super.reset();
|
||||
sensorDataSet = null;
|
||||
id = -1;
|
||||
}
|
||||
}
|
||||
+46
-23
@@ -15,7 +15,10 @@
|
||||
*/
|
||||
package com.google.android.apps.mytracks.content;
|
||||
|
||||
import static com.google.android.apps.mytracks.lib.MyTracksLibConstants.*;
|
||||
import com.google.android.apps.mytracks.content.Sensor;
|
||||
import com.google.android.apps.mytracks.stats.TripStatistics;
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.ContentValues;
|
||||
@@ -74,6 +77,12 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
|
||||
if (location.hasSpeed()) {
|
||||
values.put(TrackPointsColumns.SPEED, location.getSpeed());
|
||||
}
|
||||
if (location instanceof MyTracksLocation) {
|
||||
MyTracksLocation mtLocation = (MyTracksLocation) location;
|
||||
if (mtLocation.getSensorDataSet() != null) {
|
||||
values.put(TrackPointsColumns.SENSOR, mtLocation.getSensorDataSet().toByteArray());
|
||||
}
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
@@ -171,7 +180,7 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
|
||||
|
||||
@Override
|
||||
public Location createLocation(Cursor cursor) {
|
||||
Location location = new Location("");
|
||||
Location location = new MyTracksLocation("");
|
||||
fillLocation(cursor, location);
|
||||
return location;
|
||||
}
|
||||
@@ -188,6 +197,7 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
|
||||
int idxBearing = cursor.getColumnIndexOrThrow(TrackPointsColumns.BEARING);
|
||||
int idxAccuracy = cursor.getColumnIndexOrThrow(TrackPointsColumns.ACCURACY);
|
||||
int idxSpeed = cursor.getColumnIndexOrThrow(TrackPointsColumns.SPEED);
|
||||
int idxSensor = cursor.getColumnIndexOrThrow(TrackPointsColumns.SENSOR);
|
||||
|
||||
if (!cursor.isNull(idxLatitude)) {
|
||||
location.setLatitude(1. * cursor.getInt(idxLatitude) / 1E6);
|
||||
@@ -210,6 +220,18 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
|
||||
if (!cursor.isNull(idxAccuracy)) {
|
||||
location.setAccuracy(cursor.getFloat(idxAccuracy));
|
||||
}
|
||||
if (location instanceof MyTracksLocation &&
|
||||
!cursor.isNull(idxSensor)) {
|
||||
MyTracksLocation mtLocation = (MyTracksLocation) location;
|
||||
// TODO get the right buffer.
|
||||
Sensor.SensorDataSet sensorData;
|
||||
try {
|
||||
sensorData = Sensor.SensorDataSet.parseFrom(cursor.getBlob(idxSensor));
|
||||
mtLocation.setSensorData(sensorData);
|
||||
} catch (InvalidProtocolBufferException e) {
|
||||
Log.w(TAG, "Failed to parse sensor data.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -449,7 +471,8 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
|
||||
@Override
|
||||
public void deleteAllTracks() {
|
||||
contentResolver.delete(TracksColumns.CONTENT_URI, null, null);
|
||||
contentResolver.delete(TrackPointsColumns.CONTENT_URI, null, null);
|
||||
contentResolver.delete(TrackPointsColumns.CONTENT_URI,
|
||||
null, null);
|
||||
contentResolver.delete(WaypointsColumns.CONTENT_URI, null, null);
|
||||
}
|
||||
|
||||
@@ -463,7 +486,8 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
|
||||
}
|
||||
contentResolver.delete(WaypointsColumns.CONTENT_URI,
|
||||
WaypointsColumns.TRACKID + "=" + trackId, null);
|
||||
contentResolver.delete(TracksColumns.CONTENT_URI, "_id=" + trackId, null);
|
||||
contentResolver.delete(
|
||||
TracksColumns.CONTENT_URI, "_id=" + trackId, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -475,17 +499,16 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
|
||||
final Waypoint nextWaypoint =
|
||||
getNextStatisticsWaypointAfter(deletedWaypoint);
|
||||
if (nextWaypoint != null) {
|
||||
Log.d(MyTracksProvider.TAG, "Correcting marker " + nextWaypoint.getId()
|
||||
Log.d(TAG, "Correcting marker " + nextWaypoint.getId()
|
||||
+ " after deleted marker " + deletedWaypoint.getId());
|
||||
nextWaypoint.getStatistics().merge(deletedWaypoint.getStatistics());
|
||||
nextWaypoint.setDescription(
|
||||
descriptionGenerator.generateWaypointDescription(nextWaypoint));
|
||||
if (!updateWaypoint(nextWaypoint)) {
|
||||
Log.w(MyTracksProvider.TAG, "Update of marker was unsuccessful.");
|
||||
Log.w(TAG, "Update of marker was unsuccessful.");
|
||||
}
|
||||
} else {
|
||||
Log.d(MyTracksProvider.TAG,
|
||||
"No statistics marker after the deleted one was found.");
|
||||
Log.d(TAG, "No statistics marker after the deleted one was found.");
|
||||
}
|
||||
}
|
||||
contentResolver.delete(
|
||||
@@ -510,7 +533,7 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
|
||||
return createWaypoint(cursor);
|
||||
}
|
||||
} catch (RuntimeException e) {
|
||||
Log.w(MyTracksProvider.TAG, "Caught unexpected exception.", e);
|
||||
Log.w(TAG, "Caught unexpected exception.", e);
|
||||
} finally {
|
||||
if (cursor != null) {
|
||||
cursor.close();
|
||||
@@ -529,7 +552,7 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
|
||||
null /*selectionArgs*/);
|
||||
return rows == 1;
|
||||
} catch (RuntimeException e) {
|
||||
Log.e(MyTracksProvider.TAG, "Caught unexpected exception.", e);
|
||||
Log.e(TAG, "Caught unexpected exception.", e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -549,7 +572,7 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
|
||||
return createLocation(cursor);
|
||||
}
|
||||
} catch (RuntimeException e) {
|
||||
Log.w(MyTracksProvider.TAG, "Caught an unexpeceted exception.", e);
|
||||
Log.w(TAG, "Caught an unexpeceted exception.", e);
|
||||
} finally {
|
||||
if (cursor != null) {
|
||||
cursor.close();
|
||||
@@ -573,7 +596,7 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
|
||||
return createTrack(cursor);
|
||||
}
|
||||
} catch (RuntimeException e) {
|
||||
Log.w(MyTracksProvider.TAG, "Caught unexpected exception.", e);
|
||||
Log.w(TAG, "Caught unexpected exception.", e);
|
||||
} finally {
|
||||
if (cursor != null) {
|
||||
cursor.close();
|
||||
@@ -601,7 +624,7 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
|
||||
return createWaypoint(cursor);
|
||||
}
|
||||
} catch (RuntimeException e) {
|
||||
Log.w(MyTracksProvider.TAG, "Caught an unexpected exception.", e);
|
||||
Log.w(TAG, "Caught an unexpected exception.", e);
|
||||
} finally {
|
||||
cursor.close();
|
||||
}
|
||||
@@ -623,7 +646,7 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
|
||||
return createWaypoint(cursor);
|
||||
}
|
||||
} catch (RuntimeException e) {
|
||||
Log.w(MyTracksProvider.TAG, "Caught an unexpected exception.", e);
|
||||
Log.w(TAG, "Caught an unexpected exception.", e);
|
||||
} finally {
|
||||
cursor.close();
|
||||
}
|
||||
@@ -647,7 +670,7 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
|
||||
cursor.getColumnIndexOrThrow(TrackPointsColumns._ID));
|
||||
}
|
||||
} catch (RuntimeException e) {
|
||||
Log.w(MyTracksProvider.TAG, "Caught an unexpected exception.", e);
|
||||
Log.w(TAG, "Caught an unexpected exception.", e);
|
||||
} finally {
|
||||
cursor.close();
|
||||
}
|
||||
@@ -671,7 +694,7 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
|
||||
cursor.getColumnIndexOrThrow(WaypointsColumns._ID));
|
||||
}
|
||||
} catch (RuntimeException e) {
|
||||
Log.w(MyTracksProvider.TAG, "Caught an unexpected exception.", e);
|
||||
Log.w(TAG, "Caught an unexpected exception.", e);
|
||||
} finally {
|
||||
cursor.close();
|
||||
}
|
||||
@@ -695,7 +718,7 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
|
||||
cursor.getColumnIndexOrThrow(WaypointsColumns._ID));
|
||||
}
|
||||
} catch (RuntimeException e) {
|
||||
Log.w(MyTracksProvider.TAG, "Caught an unexpected exception.", e);
|
||||
Log.w(TAG, "Caught an unexpected exception.", e);
|
||||
} finally {
|
||||
cursor.close();
|
||||
}
|
||||
@@ -714,7 +737,7 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
|
||||
return createTrack(cursor);
|
||||
}
|
||||
} catch (RuntimeException e) {
|
||||
Log.w(MyTracksProvider.TAG, "Caught an unexpected exception.", e);
|
||||
Log.w(TAG, "Caught an unexpected exception.", e);
|
||||
} finally {
|
||||
if (cursor != null) {
|
||||
cursor.close();
|
||||
@@ -818,7 +841,7 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
|
||||
long lastId = -1;
|
||||
Cursor cursor = getLocationsCursor(track.getId(), -1, maxPoints, true);
|
||||
if (cursor == null) {
|
||||
Log.w(MyTracksProvider.TAG, "Cannot get a locations cursor!");
|
||||
Log.w(TAG, "Cannot get a locations cursor!");
|
||||
return lastId;
|
||||
}
|
||||
try {
|
||||
@@ -835,7 +858,7 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
|
||||
} while (cursor.moveToPrevious());
|
||||
}
|
||||
} catch (RuntimeException e) {
|
||||
Log.w(MyTracksProvider.TAG, "Caught unexpected exception.", e);
|
||||
Log.w(TAG, "Caught unexpected exception.", e);
|
||||
} finally {
|
||||
cursor.close();
|
||||
}
|
||||
@@ -851,14 +874,14 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
|
||||
|
||||
@Override
|
||||
public Uri insertTrack(Track track) {
|
||||
Log.d(MyTracksProvider.TAG, "MyTracksProviderUtilsImpl.insertTrack");
|
||||
Log.d(TAG, "MyTracksProviderUtilsImpl.insertTrack");
|
||||
return contentResolver.insert(TracksColumns.CONTENT_URI,
|
||||
createContentValues(track));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Uri insertTrackPoint(Location location, long trackId) {
|
||||
Log.d(MyTracksProvider.TAG, "MyTracksProviderUtilsImpl.insertTrackPoint");
|
||||
Log.d(TAG, "MyTracksProviderUtilsImpl.insertTrackPoint");
|
||||
return contentResolver.insert(TrackPointsColumns.CONTENT_URI,
|
||||
createContentValues(location, trackId));
|
||||
}
|
||||
@@ -877,7 +900,7 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
|
||||
|
||||
@Override
|
||||
public Uri insertWaypoint(Waypoint waypoint) {
|
||||
Log.d(MyTracksProvider.TAG, "MyTracksProviderUtilsImpl.insertWaypoint");
|
||||
Log.d(TAG, "MyTracksProviderUtilsImpl.insertWaypoint");
|
||||
waypoint.setId(-1);
|
||||
return contentResolver.insert(WaypointsColumns.CONTENT_URI,
|
||||
createContentValues(waypoint));
|
||||
@@ -907,7 +930,7 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
|
||||
|
||||
@Override
|
||||
public void updateTrack(Track track) {
|
||||
Log.d(MyTracksProvider.TAG, "MyTracksProviderUtilsImpl.updateTrack");
|
||||
Log.d(TAG, "MyTracksProviderUtilsImpl.updateTrack");
|
||||
contentResolver.update(TracksColumns.CONTENT_URI,
|
||||
createContentValues(track), "_id=" + track.getId(), null);
|
||||
}
|
||||
@@ -0,0 +1,816 @@
|
||||
// Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
// source: proto/sensor.proto
|
||||
|
||||
package com.google.android.apps.mytracks.content;
|
||||
|
||||
public final class Sensor {
|
||||
private Sensor() {}
|
||||
public static void registerAllExtensions(
|
||||
com.google.protobuf.ExtensionRegistryLite registry) {
|
||||
}
|
||||
public enum SensorState
|
||||
implements com.google.protobuf.Internal.EnumLite {
|
||||
NONE(0, 1),
|
||||
CONNECTING(1, 2),
|
||||
CONNECTED(2, 3),
|
||||
DISCONNECTED(3, 4),
|
||||
SENDING(4, 5),
|
||||
;
|
||||
|
||||
|
||||
public final int getNumber() { return value; }
|
||||
|
||||
public static SensorState valueOf(int value) {
|
||||
switch (value) {
|
||||
case 1: return NONE;
|
||||
case 2: return CONNECTING;
|
||||
case 3: return CONNECTED;
|
||||
case 4: return DISCONNECTED;
|
||||
case 5: return SENDING;
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static com.google.protobuf.Internal.EnumLiteMap<SensorState>
|
||||
internalGetValueMap() {
|
||||
return internalValueMap;
|
||||
}
|
||||
private static com.google.protobuf.Internal.EnumLiteMap<SensorState>
|
||||
internalValueMap =
|
||||
new com.google.protobuf.Internal.EnumLiteMap<SensorState>() {
|
||||
public SensorState findValueByNumber(int number) {
|
||||
return SensorState.valueOf(number)
|
||||
; }
|
||||
};
|
||||
|
||||
private final int index;
|
||||
private final int value;
|
||||
private SensorState(int index, int value) {
|
||||
this.index = index;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
// @@protoc_insertion_point(enum_scope:com.google.android.apps.mytracks.content.SensorState)
|
||||
}
|
||||
|
||||
public static final class SensorData extends
|
||||
com.google.protobuf.GeneratedMessageLite {
|
||||
// Use SensorData.newBuilder() to construct.
|
||||
private SensorData() {
|
||||
initFields();
|
||||
}
|
||||
private SensorData(boolean noInit) {}
|
||||
|
||||
private static final SensorData defaultInstance;
|
||||
public static SensorData getDefaultInstance() {
|
||||
return defaultInstance;
|
||||
}
|
||||
|
||||
public SensorData getDefaultInstanceForType() {
|
||||
return defaultInstance;
|
||||
}
|
||||
|
||||
// required .com.google.android.apps.mytracks.content.SensorState state = 1 [default = NONE];
|
||||
public static final int STATE_FIELD_NUMBER = 1;
|
||||
private boolean hasState;
|
||||
private com.google.android.apps.mytracks.content.Sensor.SensorState state_;
|
||||
public boolean hasState() { return hasState; }
|
||||
public com.google.android.apps.mytracks.content.Sensor.SensorState getState() { return state_; }
|
||||
|
||||
// optional int32 value = 2;
|
||||
public static final int VALUE_FIELD_NUMBER = 2;
|
||||
private boolean hasValue;
|
||||
private int value_ = 0;
|
||||
public boolean hasValue() { return hasValue; }
|
||||
public int getValue() { return value_; }
|
||||
|
||||
private void initFields() {
|
||||
state_ = com.google.android.apps.mytracks.content.Sensor.SensorState.NONE;
|
||||
}
|
||||
public final boolean isInitialized() {
|
||||
if (!hasState) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public void writeTo(com.google.protobuf.CodedOutputStream output)
|
||||
throws java.io.IOException {
|
||||
getSerializedSize();
|
||||
if (hasState()) {
|
||||
output.writeEnum(1, getState().getNumber());
|
||||
}
|
||||
if (hasValue()) {
|
||||
output.writeInt32(2, getValue());
|
||||
}
|
||||
}
|
||||
|
||||
private int memoizedSerializedSize = -1;
|
||||
public int getSerializedSize() {
|
||||
int size = memoizedSerializedSize;
|
||||
if (size != -1) return size;
|
||||
|
||||
size = 0;
|
||||
if (hasState()) {
|
||||
size += com.google.protobuf.CodedOutputStream
|
||||
.computeEnumSize(1, getState().getNumber());
|
||||
}
|
||||
if (hasValue()) {
|
||||
size += com.google.protobuf.CodedOutputStream
|
||||
.computeInt32Size(2, getValue());
|
||||
}
|
||||
memoizedSerializedSize = size;
|
||||
return size;
|
||||
}
|
||||
|
||||
public static com.google.android.apps.mytracks.content.Sensor.SensorData parseFrom(
|
||||
com.google.protobuf.ByteString data)
|
||||
throws com.google.protobuf.InvalidProtocolBufferException {
|
||||
return newBuilder().mergeFrom(data).buildParsed();
|
||||
}
|
||||
public static com.google.android.apps.mytracks.content.Sensor.SensorData parseFrom(
|
||||
com.google.protobuf.ByteString data,
|
||||
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
|
||||
throws com.google.protobuf.InvalidProtocolBufferException {
|
||||
return newBuilder().mergeFrom(data, extensionRegistry)
|
||||
.buildParsed();
|
||||
}
|
||||
public static com.google.android.apps.mytracks.content.Sensor.SensorData parseFrom(byte[] data)
|
||||
throws com.google.protobuf.InvalidProtocolBufferException {
|
||||
return newBuilder().mergeFrom(data).buildParsed();
|
||||
}
|
||||
public static com.google.android.apps.mytracks.content.Sensor.SensorData parseFrom(
|
||||
byte[] data,
|
||||
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
|
||||
throws com.google.protobuf.InvalidProtocolBufferException {
|
||||
return newBuilder().mergeFrom(data, extensionRegistry)
|
||||
.buildParsed();
|
||||
}
|
||||
public static com.google.android.apps.mytracks.content.Sensor.SensorData parseFrom(java.io.InputStream input)
|
||||
throws java.io.IOException {
|
||||
return newBuilder().mergeFrom(input).buildParsed();
|
||||
}
|
||||
public static com.google.android.apps.mytracks.content.Sensor.SensorData parseFrom(
|
||||
java.io.InputStream input,
|
||||
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
|
||||
throws java.io.IOException {
|
||||
return newBuilder().mergeFrom(input, extensionRegistry)
|
||||
.buildParsed();
|
||||
}
|
||||
public static com.google.android.apps.mytracks.content.Sensor.SensorData parseDelimitedFrom(java.io.InputStream input)
|
||||
throws java.io.IOException {
|
||||
Builder builder = newBuilder();
|
||||
if (builder.mergeDelimitedFrom(input)) {
|
||||
return builder.buildParsed();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
public static com.google.android.apps.mytracks.content.Sensor.SensorData parseDelimitedFrom(
|
||||
java.io.InputStream input,
|
||||
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
|
||||
throws java.io.IOException {
|
||||
Builder builder = newBuilder();
|
||||
if (builder.mergeDelimitedFrom(input, extensionRegistry)) {
|
||||
return builder.buildParsed();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
public static com.google.android.apps.mytracks.content.Sensor.SensorData parseFrom(
|
||||
com.google.protobuf.CodedInputStream input)
|
||||
throws java.io.IOException {
|
||||
return newBuilder().mergeFrom(input).buildParsed();
|
||||
}
|
||||
public static com.google.android.apps.mytracks.content.Sensor.SensorData parseFrom(
|
||||
com.google.protobuf.CodedInputStream input,
|
||||
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
|
||||
throws java.io.IOException {
|
||||
return newBuilder().mergeFrom(input, extensionRegistry)
|
||||
.buildParsed();
|
||||
}
|
||||
|
||||
public static Builder newBuilder() { return Builder.create(); }
|
||||
public Builder newBuilderForType() { return newBuilder(); }
|
||||
public static Builder newBuilder(com.google.android.apps.mytracks.content.Sensor.SensorData prototype) {
|
||||
return newBuilder().mergeFrom(prototype);
|
||||
}
|
||||
public Builder toBuilder() { return newBuilder(this); }
|
||||
|
||||
public static final class Builder extends
|
||||
com.google.protobuf.GeneratedMessageLite.Builder<
|
||||
com.google.android.apps.mytracks.content.Sensor.SensorData, Builder> {
|
||||
private com.google.android.apps.mytracks.content.Sensor.SensorData result;
|
||||
|
||||
// Construct using com.google.android.apps.mytracks.content.Sensor.SensorData.newBuilder()
|
||||
private Builder() {}
|
||||
|
||||
private static Builder create() {
|
||||
Builder builder = new Builder();
|
||||
builder.result = new com.google.android.apps.mytracks.content.Sensor.SensorData();
|
||||
return builder;
|
||||
}
|
||||
|
||||
protected com.google.android.apps.mytracks.content.Sensor.SensorData internalGetResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
public Builder clear() {
|
||||
if (result == null) {
|
||||
throw new IllegalStateException(
|
||||
"Cannot call clear() after build().");
|
||||
}
|
||||
result = new com.google.android.apps.mytracks.content.Sensor.SensorData();
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder clone() {
|
||||
return create().mergeFrom(result);
|
||||
}
|
||||
|
||||
public com.google.android.apps.mytracks.content.Sensor.SensorData getDefaultInstanceForType() {
|
||||
return com.google.android.apps.mytracks.content.Sensor.SensorData.getDefaultInstance();
|
||||
}
|
||||
|
||||
public boolean isInitialized() {
|
||||
return result.isInitialized();
|
||||
}
|
||||
public com.google.android.apps.mytracks.content.Sensor.SensorData build() {
|
||||
if (result != null && !isInitialized()) {
|
||||
throw newUninitializedMessageException(result);
|
||||
}
|
||||
return buildPartial();
|
||||
}
|
||||
|
||||
private com.google.android.apps.mytracks.content.Sensor.SensorData buildParsed()
|
||||
throws com.google.protobuf.InvalidProtocolBufferException {
|
||||
if (!isInitialized()) {
|
||||
throw newUninitializedMessageException(
|
||||
result).asInvalidProtocolBufferException();
|
||||
}
|
||||
return buildPartial();
|
||||
}
|
||||
|
||||
public com.google.android.apps.mytracks.content.Sensor.SensorData buildPartial() {
|
||||
if (result == null) {
|
||||
throw new IllegalStateException(
|
||||
"build() has already been called on this Builder.");
|
||||
}
|
||||
com.google.android.apps.mytracks.content.Sensor.SensorData returnMe = result;
|
||||
result = null;
|
||||
return returnMe;
|
||||
}
|
||||
|
||||
public Builder mergeFrom(com.google.android.apps.mytracks.content.Sensor.SensorData other) {
|
||||
if (other == com.google.android.apps.mytracks.content.Sensor.SensorData.getDefaultInstance()) return this;
|
||||
if (other.hasState()) {
|
||||
setState(other.getState());
|
||||
}
|
||||
if (other.hasValue()) {
|
||||
setValue(other.getValue());
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder mergeFrom(
|
||||
com.google.protobuf.CodedInputStream input,
|
||||
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
|
||||
throws java.io.IOException {
|
||||
while (true) {
|
||||
int tag = input.readTag();
|
||||
switch (tag) {
|
||||
case 0:
|
||||
return this;
|
||||
default: {
|
||||
if (!parseUnknownField(input, extensionRegistry, tag)) {
|
||||
return this;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 8: {
|
||||
int rawValue = input.readEnum();
|
||||
com.google.android.apps.mytracks.content.Sensor.SensorState value = com.google.android.apps.mytracks.content.Sensor.SensorState.valueOf(rawValue);
|
||||
if (value != null) {
|
||||
setState(value);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 16: {
|
||||
setValue(input.readInt32());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// required .com.google.android.apps.mytracks.content.SensorState state = 1 [default = NONE];
|
||||
public boolean hasState() {
|
||||
return result.hasState();
|
||||
}
|
||||
public com.google.android.apps.mytracks.content.Sensor.SensorState getState() {
|
||||
return result.getState();
|
||||
}
|
||||
public Builder setState(com.google.android.apps.mytracks.content.Sensor.SensorState value) {
|
||||
if (value == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
result.hasState = true;
|
||||
result.state_ = value;
|
||||
return this;
|
||||
}
|
||||
public Builder clearState() {
|
||||
result.hasState = false;
|
||||
result.state_ = com.google.android.apps.mytracks.content.Sensor.SensorState.NONE;
|
||||
return this;
|
||||
}
|
||||
|
||||
// optional int32 value = 2;
|
||||
public boolean hasValue() {
|
||||
return result.hasValue();
|
||||
}
|
||||
public int getValue() {
|
||||
return result.getValue();
|
||||
}
|
||||
public Builder setValue(int value) {
|
||||
result.hasValue = true;
|
||||
result.value_ = value;
|
||||
return this;
|
||||
}
|
||||
public Builder clearValue() {
|
||||
result.hasValue = false;
|
||||
result.value_ = 0;
|
||||
return this;
|
||||
}
|
||||
|
||||
// @@protoc_insertion_point(builder_scope:com.google.android.apps.mytracks.content.SensorData)
|
||||
}
|
||||
|
||||
static {
|
||||
defaultInstance = new SensorData(true);
|
||||
com.google.android.apps.mytracks.content.Sensor.internalForceInit();
|
||||
defaultInstance.initFields();
|
||||
}
|
||||
|
||||
// @@protoc_insertion_point(class_scope:com.google.android.apps.mytracks.content.SensorData)
|
||||
}
|
||||
|
||||
public static final class SensorDataSet extends
|
||||
com.google.protobuf.GeneratedMessageLite {
|
||||
// Use SensorDataSet.newBuilder() to construct.
|
||||
private SensorDataSet() {
|
||||
initFields();
|
||||
}
|
||||
private SensorDataSet(boolean noInit) {}
|
||||
|
||||
private static final SensorDataSet defaultInstance;
|
||||
public static SensorDataSet getDefaultInstance() {
|
||||
return defaultInstance;
|
||||
}
|
||||
|
||||
public SensorDataSet getDefaultInstanceForType() {
|
||||
return defaultInstance;
|
||||
}
|
||||
|
||||
// optional uint64 creation_time = 1 [default = 0];
|
||||
public static final int CREATION_TIME_FIELD_NUMBER = 1;
|
||||
private boolean hasCreationTime;
|
||||
private long creationTime_ = 0L;
|
||||
public boolean hasCreationTime() { return hasCreationTime; }
|
||||
public long getCreationTime() { return creationTime_; }
|
||||
|
||||
// optional .com.google.android.apps.mytracks.content.SensorData heart_rate = 2;
|
||||
public static final int HEART_RATE_FIELD_NUMBER = 2;
|
||||
private boolean hasHeartRate;
|
||||
private com.google.android.apps.mytracks.content.Sensor.SensorData heartRate_;
|
||||
public boolean hasHeartRate() { return hasHeartRate; }
|
||||
public com.google.android.apps.mytracks.content.Sensor.SensorData getHeartRate() { return heartRate_; }
|
||||
|
||||
// optional .com.google.android.apps.mytracks.content.SensorData cadence = 3;
|
||||
public static final int CADENCE_FIELD_NUMBER = 3;
|
||||
private boolean hasCadence;
|
||||
private com.google.android.apps.mytracks.content.Sensor.SensorData cadence_;
|
||||
public boolean hasCadence() { return hasCadence; }
|
||||
public com.google.android.apps.mytracks.content.Sensor.SensorData getCadence() { return cadence_; }
|
||||
|
||||
// optional .com.google.android.apps.mytracks.content.SensorData power = 4;
|
||||
public static final int POWER_FIELD_NUMBER = 4;
|
||||
private boolean hasPower;
|
||||
private com.google.android.apps.mytracks.content.Sensor.SensorData power_;
|
||||
public boolean hasPower() { return hasPower; }
|
||||
public com.google.android.apps.mytracks.content.Sensor.SensorData getPower() { return power_; }
|
||||
|
||||
private void initFields() {
|
||||
heartRate_ = com.google.android.apps.mytracks.content.Sensor.SensorData.getDefaultInstance();
|
||||
cadence_ = com.google.android.apps.mytracks.content.Sensor.SensorData.getDefaultInstance();
|
||||
power_ = com.google.android.apps.mytracks.content.Sensor.SensorData.getDefaultInstance();
|
||||
}
|
||||
public final boolean isInitialized() {
|
||||
if (hasHeartRate()) {
|
||||
if (!getHeartRate().isInitialized()) return false;
|
||||
}
|
||||
if (hasCadence()) {
|
||||
if (!getCadence().isInitialized()) return false;
|
||||
}
|
||||
if (hasPower()) {
|
||||
if (!getPower().isInitialized()) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void writeTo(com.google.protobuf.CodedOutputStream output)
|
||||
throws java.io.IOException {
|
||||
getSerializedSize();
|
||||
if (hasCreationTime()) {
|
||||
output.writeUInt64(1, getCreationTime());
|
||||
}
|
||||
if (hasHeartRate()) {
|
||||
output.writeMessage(2, getHeartRate());
|
||||
}
|
||||
if (hasCadence()) {
|
||||
output.writeMessage(3, getCadence());
|
||||
}
|
||||
if (hasPower()) {
|
||||
output.writeMessage(4, getPower());
|
||||
}
|
||||
}
|
||||
|
||||
private int memoizedSerializedSize = -1;
|
||||
public int getSerializedSize() {
|
||||
int size = memoizedSerializedSize;
|
||||
if (size != -1) return size;
|
||||
|
||||
size = 0;
|
||||
if (hasCreationTime()) {
|
||||
size += com.google.protobuf.CodedOutputStream
|
||||
.computeUInt64Size(1, getCreationTime());
|
||||
}
|
||||
if (hasHeartRate()) {
|
||||
size += com.google.protobuf.CodedOutputStream
|
||||
.computeMessageSize(2, getHeartRate());
|
||||
}
|
||||
if (hasCadence()) {
|
||||
size += com.google.protobuf.CodedOutputStream
|
||||
.computeMessageSize(3, getCadence());
|
||||
}
|
||||
if (hasPower()) {
|
||||
size += com.google.protobuf.CodedOutputStream
|
||||
.computeMessageSize(4, getPower());
|
||||
}
|
||||
memoizedSerializedSize = size;
|
||||
return size;
|
||||
}
|
||||
|
||||
public static com.google.android.apps.mytracks.content.Sensor.SensorDataSet parseFrom(
|
||||
com.google.protobuf.ByteString data)
|
||||
throws com.google.protobuf.InvalidProtocolBufferException {
|
||||
return newBuilder().mergeFrom(data).buildParsed();
|
||||
}
|
||||
public static com.google.android.apps.mytracks.content.Sensor.SensorDataSet parseFrom(
|
||||
com.google.protobuf.ByteString data,
|
||||
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
|
||||
throws com.google.protobuf.InvalidProtocolBufferException {
|
||||
return newBuilder().mergeFrom(data, extensionRegistry)
|
||||
.buildParsed();
|
||||
}
|
||||
public static com.google.android.apps.mytracks.content.Sensor.SensorDataSet parseFrom(byte[] data)
|
||||
throws com.google.protobuf.InvalidProtocolBufferException {
|
||||
return newBuilder().mergeFrom(data).buildParsed();
|
||||
}
|
||||
public static com.google.android.apps.mytracks.content.Sensor.SensorDataSet parseFrom(
|
||||
byte[] data,
|
||||
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
|
||||
throws com.google.protobuf.InvalidProtocolBufferException {
|
||||
return newBuilder().mergeFrom(data, extensionRegistry)
|
||||
.buildParsed();
|
||||
}
|
||||
public static com.google.android.apps.mytracks.content.Sensor.SensorDataSet parseFrom(java.io.InputStream input)
|
||||
throws java.io.IOException {
|
||||
return newBuilder().mergeFrom(input).buildParsed();
|
||||
}
|
||||
public static com.google.android.apps.mytracks.content.Sensor.SensorDataSet parseFrom(
|
||||
java.io.InputStream input,
|
||||
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
|
||||
throws java.io.IOException {
|
||||
return newBuilder().mergeFrom(input, extensionRegistry)
|
||||
.buildParsed();
|
||||
}
|
||||
public static com.google.android.apps.mytracks.content.Sensor.SensorDataSet parseDelimitedFrom(java.io.InputStream input)
|
||||
throws java.io.IOException {
|
||||
Builder builder = newBuilder();
|
||||
if (builder.mergeDelimitedFrom(input)) {
|
||||
return builder.buildParsed();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
public static com.google.android.apps.mytracks.content.Sensor.SensorDataSet parseDelimitedFrom(
|
||||
java.io.InputStream input,
|
||||
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
|
||||
throws java.io.IOException {
|
||||
Builder builder = newBuilder();
|
||||
if (builder.mergeDelimitedFrom(input, extensionRegistry)) {
|
||||
return builder.buildParsed();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
public static com.google.android.apps.mytracks.content.Sensor.SensorDataSet parseFrom(
|
||||
com.google.protobuf.CodedInputStream input)
|
||||
throws java.io.IOException {
|
||||
return newBuilder().mergeFrom(input).buildParsed();
|
||||
}
|
||||
public static com.google.android.apps.mytracks.content.Sensor.SensorDataSet parseFrom(
|
||||
com.google.protobuf.CodedInputStream input,
|
||||
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
|
||||
throws java.io.IOException {
|
||||
return newBuilder().mergeFrom(input, extensionRegistry)
|
||||
.buildParsed();
|
||||
}
|
||||
|
||||
public static Builder newBuilder() { return Builder.create(); }
|
||||
public Builder newBuilderForType() { return newBuilder(); }
|
||||
public static Builder newBuilder(com.google.android.apps.mytracks.content.Sensor.SensorDataSet prototype) {
|
||||
return newBuilder().mergeFrom(prototype);
|
||||
}
|
||||
public Builder toBuilder() { return newBuilder(this); }
|
||||
|
||||
public static final class Builder extends
|
||||
com.google.protobuf.GeneratedMessageLite.Builder<
|
||||
com.google.android.apps.mytracks.content.Sensor.SensorDataSet, Builder> {
|
||||
private com.google.android.apps.mytracks.content.Sensor.SensorDataSet result;
|
||||
|
||||
// Construct using com.google.android.apps.mytracks.content.Sensor.SensorDataSet.newBuilder()
|
||||
private Builder() {}
|
||||
|
||||
private static Builder create() {
|
||||
Builder builder = new Builder();
|
||||
builder.result = new com.google.android.apps.mytracks.content.Sensor.SensorDataSet();
|
||||
return builder;
|
||||
}
|
||||
|
||||
protected com.google.android.apps.mytracks.content.Sensor.SensorDataSet internalGetResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
public Builder clear() {
|
||||
if (result == null) {
|
||||
throw new IllegalStateException(
|
||||
"Cannot call clear() after build().");
|
||||
}
|
||||
result = new com.google.android.apps.mytracks.content.Sensor.SensorDataSet();
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder clone() {
|
||||
return create().mergeFrom(result);
|
||||
}
|
||||
|
||||
public com.google.android.apps.mytracks.content.Sensor.SensorDataSet getDefaultInstanceForType() {
|
||||
return com.google.android.apps.mytracks.content.Sensor.SensorDataSet.getDefaultInstance();
|
||||
}
|
||||
|
||||
public boolean isInitialized() {
|
||||
return result.isInitialized();
|
||||
}
|
||||
public com.google.android.apps.mytracks.content.Sensor.SensorDataSet build() {
|
||||
if (result != null && !isInitialized()) {
|
||||
throw newUninitializedMessageException(result);
|
||||
}
|
||||
return buildPartial();
|
||||
}
|
||||
|
||||
private com.google.android.apps.mytracks.content.Sensor.SensorDataSet buildParsed()
|
||||
throws com.google.protobuf.InvalidProtocolBufferException {
|
||||
if (!isInitialized()) {
|
||||
throw newUninitializedMessageException(
|
||||
result).asInvalidProtocolBufferException();
|
||||
}
|
||||
return buildPartial();
|
||||
}
|
||||
|
||||
public com.google.android.apps.mytracks.content.Sensor.SensorDataSet buildPartial() {
|
||||
if (result == null) {
|
||||
throw new IllegalStateException(
|
||||
"build() has already been called on this Builder.");
|
||||
}
|
||||
com.google.android.apps.mytracks.content.Sensor.SensorDataSet returnMe = result;
|
||||
result = null;
|
||||
return returnMe;
|
||||
}
|
||||
|
||||
public Builder mergeFrom(com.google.android.apps.mytracks.content.Sensor.SensorDataSet other) {
|
||||
if (other == com.google.android.apps.mytracks.content.Sensor.SensorDataSet.getDefaultInstance()) return this;
|
||||
if (other.hasCreationTime()) {
|
||||
setCreationTime(other.getCreationTime());
|
||||
}
|
||||
if (other.hasHeartRate()) {
|
||||
mergeHeartRate(other.getHeartRate());
|
||||
}
|
||||
if (other.hasCadence()) {
|
||||
mergeCadence(other.getCadence());
|
||||
}
|
||||
if (other.hasPower()) {
|
||||
mergePower(other.getPower());
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder mergeFrom(
|
||||
com.google.protobuf.CodedInputStream input,
|
||||
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
|
||||
throws java.io.IOException {
|
||||
while (true) {
|
||||
int tag = input.readTag();
|
||||
switch (tag) {
|
||||
case 0:
|
||||
return this;
|
||||
default: {
|
||||
if (!parseUnknownField(input, extensionRegistry, tag)) {
|
||||
return this;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 8: {
|
||||
setCreationTime(input.readUInt64());
|
||||
break;
|
||||
}
|
||||
case 18: {
|
||||
com.google.android.apps.mytracks.content.Sensor.SensorData.Builder subBuilder = com.google.android.apps.mytracks.content.Sensor.SensorData.newBuilder();
|
||||
if (hasHeartRate()) {
|
||||
subBuilder.mergeFrom(getHeartRate());
|
||||
}
|
||||
input.readMessage(subBuilder, extensionRegistry);
|
||||
setHeartRate(subBuilder.buildPartial());
|
||||
break;
|
||||
}
|
||||
case 26: {
|
||||
com.google.android.apps.mytracks.content.Sensor.SensorData.Builder subBuilder = com.google.android.apps.mytracks.content.Sensor.SensorData.newBuilder();
|
||||
if (hasCadence()) {
|
||||
subBuilder.mergeFrom(getCadence());
|
||||
}
|
||||
input.readMessage(subBuilder, extensionRegistry);
|
||||
setCadence(subBuilder.buildPartial());
|
||||
break;
|
||||
}
|
||||
case 34: {
|
||||
com.google.android.apps.mytracks.content.Sensor.SensorData.Builder subBuilder = com.google.android.apps.mytracks.content.Sensor.SensorData.newBuilder();
|
||||
if (hasPower()) {
|
||||
subBuilder.mergeFrom(getPower());
|
||||
}
|
||||
input.readMessage(subBuilder, extensionRegistry);
|
||||
setPower(subBuilder.buildPartial());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// optional uint64 creation_time = 1 [default = 0];
|
||||
public boolean hasCreationTime() {
|
||||
return result.hasCreationTime();
|
||||
}
|
||||
public long getCreationTime() {
|
||||
return result.getCreationTime();
|
||||
}
|
||||
public Builder setCreationTime(long value) {
|
||||
result.hasCreationTime = true;
|
||||
result.creationTime_ = value;
|
||||
return this;
|
||||
}
|
||||
public Builder clearCreationTime() {
|
||||
result.hasCreationTime = false;
|
||||
result.creationTime_ = 0L;
|
||||
return this;
|
||||
}
|
||||
|
||||
// optional .com.google.android.apps.mytracks.content.SensorData heart_rate = 2;
|
||||
public boolean hasHeartRate() {
|
||||
return result.hasHeartRate();
|
||||
}
|
||||
public com.google.android.apps.mytracks.content.Sensor.SensorData getHeartRate() {
|
||||
return result.getHeartRate();
|
||||
}
|
||||
public Builder setHeartRate(com.google.android.apps.mytracks.content.Sensor.SensorData value) {
|
||||
if (value == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
result.hasHeartRate = true;
|
||||
result.heartRate_ = value;
|
||||
return this;
|
||||
}
|
||||
public Builder setHeartRate(com.google.android.apps.mytracks.content.Sensor.SensorData.Builder builderForValue) {
|
||||
result.hasHeartRate = true;
|
||||
result.heartRate_ = builderForValue.build();
|
||||
return this;
|
||||
}
|
||||
public Builder mergeHeartRate(com.google.android.apps.mytracks.content.Sensor.SensorData value) {
|
||||
if (result.hasHeartRate() &&
|
||||
result.heartRate_ != com.google.android.apps.mytracks.content.Sensor.SensorData.getDefaultInstance()) {
|
||||
result.heartRate_ =
|
||||
com.google.android.apps.mytracks.content.Sensor.SensorData.newBuilder(result.heartRate_).mergeFrom(value).buildPartial();
|
||||
} else {
|
||||
result.heartRate_ = value;
|
||||
}
|
||||
result.hasHeartRate = true;
|
||||
return this;
|
||||
}
|
||||
public Builder clearHeartRate() {
|
||||
result.hasHeartRate = false;
|
||||
result.heartRate_ = com.google.android.apps.mytracks.content.Sensor.SensorData.getDefaultInstance();
|
||||
return this;
|
||||
}
|
||||
|
||||
// optional .com.google.android.apps.mytracks.content.SensorData cadence = 3;
|
||||
public boolean hasCadence() {
|
||||
return result.hasCadence();
|
||||
}
|
||||
public com.google.android.apps.mytracks.content.Sensor.SensorData getCadence() {
|
||||
return result.getCadence();
|
||||
}
|
||||
public Builder setCadence(com.google.android.apps.mytracks.content.Sensor.SensorData value) {
|
||||
if (value == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
result.hasCadence = true;
|
||||
result.cadence_ = value;
|
||||
return this;
|
||||
}
|
||||
public Builder setCadence(com.google.android.apps.mytracks.content.Sensor.SensorData.Builder builderForValue) {
|
||||
result.hasCadence = true;
|
||||
result.cadence_ = builderForValue.build();
|
||||
return this;
|
||||
}
|
||||
public Builder mergeCadence(com.google.android.apps.mytracks.content.Sensor.SensorData value) {
|
||||
if (result.hasCadence() &&
|
||||
result.cadence_ != com.google.android.apps.mytracks.content.Sensor.SensorData.getDefaultInstance()) {
|
||||
result.cadence_ =
|
||||
com.google.android.apps.mytracks.content.Sensor.SensorData.newBuilder(result.cadence_).mergeFrom(value).buildPartial();
|
||||
} else {
|
||||
result.cadence_ = value;
|
||||
}
|
||||
result.hasCadence = true;
|
||||
return this;
|
||||
}
|
||||
public Builder clearCadence() {
|
||||
result.hasCadence = false;
|
||||
result.cadence_ = com.google.android.apps.mytracks.content.Sensor.SensorData.getDefaultInstance();
|
||||
return this;
|
||||
}
|
||||
|
||||
// optional .com.google.android.apps.mytracks.content.SensorData power = 4;
|
||||
public boolean hasPower() {
|
||||
return result.hasPower();
|
||||
}
|
||||
public com.google.android.apps.mytracks.content.Sensor.SensorData getPower() {
|
||||
return result.getPower();
|
||||
}
|
||||
public Builder setPower(com.google.android.apps.mytracks.content.Sensor.SensorData value) {
|
||||
if (value == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
result.hasPower = true;
|
||||
result.power_ = value;
|
||||
return this;
|
||||
}
|
||||
public Builder setPower(com.google.android.apps.mytracks.content.Sensor.SensorData.Builder builderForValue) {
|
||||
result.hasPower = true;
|
||||
result.power_ = builderForValue.build();
|
||||
return this;
|
||||
}
|
||||
public Builder mergePower(com.google.android.apps.mytracks.content.Sensor.SensorData value) {
|
||||
if (result.hasPower() &&
|
||||
result.power_ != com.google.android.apps.mytracks.content.Sensor.SensorData.getDefaultInstance()) {
|
||||
result.power_ =
|
||||
com.google.android.apps.mytracks.content.Sensor.SensorData.newBuilder(result.power_).mergeFrom(value).buildPartial();
|
||||
} else {
|
||||
result.power_ = value;
|
||||
}
|
||||
result.hasPower = true;
|
||||
return this;
|
||||
}
|
||||
public Builder clearPower() {
|
||||
result.hasPower = false;
|
||||
result.power_ = com.google.android.apps.mytracks.content.Sensor.SensorData.getDefaultInstance();
|
||||
return this;
|
||||
}
|
||||
|
||||
// @@protoc_insertion_point(builder_scope:com.google.android.apps.mytracks.content.SensorDataSet)
|
||||
}
|
||||
|
||||
static {
|
||||
defaultInstance = new SensorDataSet(true);
|
||||
com.google.android.apps.mytracks.content.Sensor.internalForceInit();
|
||||
defaultInstance.initFields();
|
||||
}
|
||||
|
||||
// @@protoc_insertion_point(class_scope:com.google.android.apps.mytracks.content.SensorDataSet)
|
||||
}
|
||||
|
||||
|
||||
static {
|
||||
}
|
||||
|
||||
public static void internalForceInit() {}
|
||||
|
||||
// @@protoc_insertion_point(outer_class_scope)
|
||||
}
|
||||
+1
-1
@@ -34,7 +34,7 @@ import java.util.ArrayList;
|
||||
public class Track implements Parcelable {
|
||||
|
||||
/**
|
||||
* Creator for a Track object
|
||||
* Creator for a Track object.
|
||||
*/
|
||||
public static class Creator implements Parcelable.Creator<Track> {
|
||||
|
||||
+1
-12
@@ -15,8 +15,6 @@
|
||||
*/
|
||||
package com.google.android.apps.mytracks.content;
|
||||
|
||||
import static com.google.android.apps.mytracks.content.ContentTypeIds.*;
|
||||
|
||||
import android.net.Uri;
|
||||
import android.provider.BaseColumns;
|
||||
|
||||
@@ -44,14 +42,5 @@ public interface TrackPointsColumns extends BaseColumns {
|
||||
public static final String TIME = "time";
|
||||
public static final String ACCURACY = "accuracy";
|
||||
public static final String SPEED = "speed";
|
||||
|
||||
/** Columns that go into the backup. */
|
||||
public static final String[] BACKUP_COLUMNS =
|
||||
{ _ID, TRACKID, LATITUDE, LONGITUDE, ALTITUDE, BEARING, TIME,
|
||||
ACCURACY, SPEED };
|
||||
|
||||
/** Types of the columns that go into the backup. */
|
||||
public static final byte[] BACKUP_COLUMN_TYPES =
|
||||
{ LONG_TYPE_ID, LONG_TYPE_ID, INT_TYPE_ID, INT_TYPE_ID, FLOAT_TYPE_ID,
|
||||
FLOAT_TYPE_ID, LONG_TYPE_ID, FLOAT_TYPE_ID, FLOAT_TYPE_ID };
|
||||
public static final String SENSOR = "sensor";
|
||||
}
|
||||
-14
@@ -15,8 +15,6 @@
|
||||
*/
|
||||
package com.google.android.apps.mytracks.content;
|
||||
|
||||
import static com.google.android.apps.mytracks.content.ContentTypeIds.*;
|
||||
|
||||
import android.net.Uri;
|
||||
import android.provider.BaseColumns;
|
||||
|
||||
@@ -61,16 +59,4 @@ public interface TracksColumns extends BaseColumns {
|
||||
public static final String MINLON = "minlon";
|
||||
public static final String MAXLON = "maxlon";
|
||||
public static final String MAPID = "mapid";
|
||||
|
||||
public static final String[] BACKUP_COLUMNS = {
|
||||
_ID, NAME, DESCRIPTION, CATEGORY, STARTID, STOPID, STARTTIME, STOPTIME,
|
||||
NUMPOINTS, TOTALDISTANCE, TOTALTIME, MOVINGTIME, AVGSPEED, AVGMOVINGSPEED,
|
||||
MAXSPEED, MINELEVATION, MAXELEVATION, ELEVATIONGAIN, MINGRADE, MAXGRADE,
|
||||
MINLAT, MAXLAT, MINLON, MAXLON };
|
||||
public static final byte[] BACKUP_COLUMN_TYPES = {
|
||||
LONG_TYPE_ID, STRING_TYPE_ID, STRING_TYPE_ID, STRING_TYPE_ID,
|
||||
LONG_TYPE_ID, LONG_TYPE_ID, LONG_TYPE_ID, LONG_TYPE_ID, INT_TYPE_ID,
|
||||
FLOAT_TYPE_ID, LONG_TYPE_ID, LONG_TYPE_ID, FLOAT_TYPE_ID, FLOAT_TYPE_ID,
|
||||
FLOAT_TYPE_ID, FLOAT_TYPE_ID, FLOAT_TYPE_ID, FLOAT_TYPE_ID, FLOAT_TYPE_ID,
|
||||
FLOAT_TYPE_ID, INT_TYPE_ID, INT_TYPE_ID, INT_TYPE_ID, INT_TYPE_ID };
|
||||
}
|
||||
+8
-2
@@ -49,7 +49,10 @@ public final class Waypoint implements Parcelable {
|
||||
waypoint.type = source.readInt();
|
||||
waypoint.startId = source.readLong();
|
||||
waypoint.stopId = source.readLong();
|
||||
waypoint.stats = source.readParcelable(classLoader);
|
||||
byte hasStats = source.readByte();
|
||||
if (hasStats > 0) {
|
||||
waypoint.stats = source.readParcelable(classLoader);
|
||||
}
|
||||
byte hasLocation = source.readByte();
|
||||
if (hasLocation > 0) {
|
||||
waypoint.location = source.readParcelable(classLoader);
|
||||
@@ -100,7 +103,10 @@ public final class Waypoint implements Parcelable {
|
||||
dest.writeInt(type);
|
||||
dest.writeLong(startId);
|
||||
dest.writeLong(stopId);
|
||||
dest.writeParcelable(stats, 0);
|
||||
dest.writeByte(stats == null ? (byte) 0 : (byte) 1);
|
||||
if (stats != null) {
|
||||
dest.writeParcelable(stats, 0);
|
||||
}
|
||||
dest.writeByte(location == null ? (byte) 0 : (byte) 1);
|
||||
if (location != null) {
|
||||
dest.writeParcelable(location, 0);
|
||||
-17
@@ -15,8 +15,6 @@
|
||||
*/
|
||||
package com.google.android.apps.mytracks.content;
|
||||
|
||||
import static com.google.android.apps.mytracks.content.ContentTypeIds.*;
|
||||
|
||||
import android.net.Uri;
|
||||
import android.provider.BaseColumns;
|
||||
|
||||
@@ -68,19 +66,4 @@ public interface WaypointsColumns extends BaseColumns {
|
||||
public static final String ELEVATIONGAIN = "elevationgain";
|
||||
public static final String MINGRADE = "mingrade";
|
||||
public static final String MAXGRADE = "maxgrade";
|
||||
|
||||
public static final String[] BACKUP_COLUMNS = {
|
||||
_ID, TRACKID, NAME, DESCRIPTION, CATEGORY, ICON, TYPE, LENGTH, DURATION,
|
||||
STARTTIME, STARTID, STOPID, LATITUDE, LONGITUDE, ALTITUDE, BEARING, TIME,
|
||||
ACCURACY, SPEED, TOTALDISTANCE, TOTALTIME, MOVINGTIME, AVGSPEED,
|
||||
AVGMOVINGSPEED, MAXSPEED, MINELEVATION, MAXELEVATION, ELEVATIONGAIN,
|
||||
MINGRADE, MAXGRADE };
|
||||
public static final byte[] BACKUP_COLUMN_TYPES = {
|
||||
LONG_TYPE_ID, LONG_TYPE_ID, STRING_TYPE_ID, STRING_TYPE_ID,
|
||||
STRING_TYPE_ID, STRING_TYPE_ID, INT_TYPE_ID, FLOAT_TYPE_ID, LONG_TYPE_ID,
|
||||
LONG_TYPE_ID, LONG_TYPE_ID, LONG_TYPE_ID, INT_TYPE_ID, INT_TYPE_ID,
|
||||
FLOAT_TYPE_ID, FLOAT_TYPE_ID, LONG_TYPE_ID, FLOAT_TYPE_ID, FLOAT_TYPE_ID,
|
||||
FLOAT_TYPE_ID, LONG_TYPE_ID, LONG_TYPE_ID, FLOAT_TYPE_ID, FLOAT_TYPE_ID,
|
||||
FLOAT_TYPE_ID, FLOAT_TYPE_ID, FLOAT_TYPE_ID, FLOAT_TYPE_ID, FLOAT_TYPE_ID,
|
||||
FLOAT_TYPE_ID };
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright 2010 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package com.google.android.apps.mytracks.lib;
|
||||
|
||||
/**
|
||||
* Constants for the My Tracks common library.
|
||||
* These constants should ideally not be used by third-party applications.
|
||||
*
|
||||
* @author Rodrigo Damazio
|
||||
*/
|
||||
public class MyTracksLibConstants {
|
||||
public static final String TAG = "MyTracksLib";
|
||||
|
||||
private MyTracksLibConstants() {}
|
||||
}
|
||||
+14
@@ -84,4 +84,18 @@ interface ITrackRecordingService {
|
||||
* Deletes all the stored tracks.
|
||||
*/
|
||||
void deleteAllTracks();
|
||||
|
||||
/**
|
||||
* The current sensor data.
|
||||
* The data is returned as a byte array which is a binary version of a
|
||||
* Sensor.SensorDataSet object.
|
||||
* @return the current sensor data or null if there is none.
|
||||
*/
|
||||
byte[] getSensorData();
|
||||
|
||||
/**
|
||||
* The current state of the sensor manager.
|
||||
* The value is the value of a Sensor.SensorState enum.
|
||||
*/
|
||||
int getSensorState();
|
||||
}
|
||||
+5
@@ -103,6 +103,11 @@ public class ExtremityMonitor {
|
||||
public void setMax(double max) {
|
||||
this.max = max;
|
||||
}
|
||||
|
||||
public boolean hasData() {
|
||||
return min != Double.POSITIVE_INFINITY
|
||||
&& max != Double.NEGATIVE_INFINITY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
+1
-1
@@ -26,7 +26,7 @@ import android.os.Parcelable;
|
||||
*
|
||||
* @author Rodrigo Damazio
|
||||
*/
|
||||
public class TripStatistics implements Parcelable {
|
||||
public class TripStatistics implements Parcelable {
|
||||
|
||||
/**
|
||||
* The start time for the trip. This is system time which might not match gps
|
||||
@@ -19,9 +19,9 @@ import static com.google.android.testing.mocking.AndroidMock.eq;
|
||||
import static com.google.android.testing.mocking.AndroidMock.expect;
|
||||
|
||||
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
|
||||
import com.google.android.apps.mytracks.content.MyTracksProviderUtils.Factory;
|
||||
import com.google.android.apps.mytracks.content.Track;
|
||||
import com.google.android.apps.mytracks.content.TracksColumns;
|
||||
import com.google.android.apps.mytracks.content.MyTracksProviderUtils.Factory;
|
||||
import com.google.android.apps.mytracks.testing.TestingProviderUtilsFactory;
|
||||
import com.google.android.testing.mocking.AndroidMock;
|
||||
import com.google.android.testing.mocking.UsesMocks;
|
||||
@@ -77,7 +77,7 @@ public class GpxImporterTest extends AndroidTestCase {
|
||||
DATE_FORMAT2.setTimeZone(utc);
|
||||
}
|
||||
|
||||
// TODO use real files from different sources with more track points
|
||||
// TODO: use real files from different sources with more track points.
|
||||
private static final String VALID_TEST_GPX = "<gpx><trk><name><![CDATA["
|
||||
+ TRACK_NAME + "]]></name><desc><![CDATA[" + TRACK_DESC
|
||||
+ "]]></desc><trkseg>" + "<trkpt lat=\"" + TRACK_LAT_1 + "\" lon=\""
|
||||
@@ -93,6 +93,12 @@ public class GpxImporterTest extends AndroidTestCase {
|
||||
.replaceAll(TRACK_LAT_1, "1000.0");
|
||||
private static final String INVALID_TIME_TEST_GPX = VALID_TEST_GPX
|
||||
.replaceAll(TRACK_TIME_1, "invalid");
|
||||
private static final String INVALID_ALTITUDE_TEST_GPX = VALID_TEST_GPX
|
||||
.replaceAll(TRACK_ELE_1, "invalid");
|
||||
private static final String INVALID_LATITUDE_TEST_GPX = VALID_TEST_GPX
|
||||
.replaceAll(TRACK_LAT_1, "invalid");
|
||||
private static final String INVALID_LONGITUDE_TEST_GPX = VALID_TEST_GPX
|
||||
.replaceAll(TRACK_LON_1, "invalid");
|
||||
|
||||
private static final long TRACK_ID = 1;
|
||||
private static final long TRACK_POINT_ID_1 = 1;
|
||||
@@ -122,7 +128,7 @@ public class GpxImporterTest extends AndroidTestCase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Test import success
|
||||
* Test import success.
|
||||
*/
|
||||
public void testImportSuccess() throws Exception {
|
||||
Capture<Track> trackParam = new Capture<Track>();
|
||||
@@ -171,7 +177,7 @@ public class GpxImporterTest extends AndroidTestCase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Test with invalid location - track should be deleted
|
||||
* Test with invalid location - track should be deleted.
|
||||
*/
|
||||
public void testImportLocationFailure() throws ParserConfigurationException,
|
||||
SAXException, IOException {
|
||||
@@ -179,7 +185,7 @@ public class GpxImporterTest extends AndroidTestCase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Test with invalid time - track should be deleted
|
||||
* Test with invalid time - track should be deleted.
|
||||
*/
|
||||
public void testImportTimeFailure() throws ParserConfigurationException,
|
||||
SAXException, IOException {
|
||||
@@ -187,13 +193,37 @@ public class GpxImporterTest extends AndroidTestCase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Test with invalid xml - track should be deleted
|
||||
* Test with invalid xml - track should be deleted.
|
||||
*/
|
||||
public void testImportXMLFailure() throws ParserConfigurationException,
|
||||
SAXException, IOException {
|
||||
testInvalidXML(INVALID_XML_TEST_GPX);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test with invalid altitude - track should be deleted.
|
||||
*/
|
||||
public void testImportInvalidAltitude() throws ParserConfigurationException,
|
||||
SAXException, IOException {
|
||||
testInvalidXML(INVALID_ALTITUDE_TEST_GPX);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test with invalid latitude - track should be deleted.
|
||||
*/
|
||||
public void testImportInvalidLatitude() throws ParserConfigurationException,
|
||||
SAXException, IOException {
|
||||
testInvalidXML(INVALID_LATITUDE_TEST_GPX);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test with invalid longitude - track should be deleted.
|
||||
*/
|
||||
public void testImportInvalidLongitude() throws ParserConfigurationException,
|
||||
SAXException, IOException {
|
||||
testInvalidXML(INVALID_LONGITUDE_TEST_GPX);
|
||||
}
|
||||
|
||||
private void testInvalidXML(String xml) throws ParserConfigurationException,
|
||||
IOException {
|
||||
expect(providerUtils.insertTrack((Track) AndroidMock.anyObject()))
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
// Copyright 2010 Google Inc. All Rights Reserved.
|
||||
package com.google.android.apps.mytracks.io;
|
||||
|
||||
import android.location.Location;
|
||||
import com.google.android.apps.mytracks.content.MyTracksLocation;
|
||||
import com.google.android.apps.mytracks.content.Sensor;
|
||||
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
@@ -38,11 +39,11 @@ public class TcxTrackWriterTest extends TrackFormatWriterTest {
|
||||
/**
|
||||
* Asserts that the given tags describe the given points, in the same order.
|
||||
*/
|
||||
private void assertTagsMatchPoints(List<Element> tags, Location... locs) {
|
||||
private void assertTagsMatchPoints(List<Element> tags, MyTracksLocation... locs) {
|
||||
assertEquals(locs.length, tags.size());
|
||||
for (int i = 0; i < locs.length; i++) {
|
||||
Element tag = tags.get(i);
|
||||
Location loc = locs[i];
|
||||
MyTracksLocation loc = locs[i];
|
||||
|
||||
assertTagMatchesLocation(tag, loc);
|
||||
}
|
||||
@@ -51,7 +52,7 @@ public class TcxTrackWriterTest extends TrackFormatWriterTest {
|
||||
/**
|
||||
* Asserts that the given tag describes the given location.
|
||||
*/
|
||||
private void assertTagMatchesLocation(Element tag, Location loc) {
|
||||
private void assertTagMatchesLocation(Element tag, MyTracksLocation loc) {
|
||||
Element posTag = getChildElement(tag, "Position");
|
||||
assertEquals(Double.toString(loc.getLatitude()),
|
||||
getChildTextValue(posTag, "LatitudeDegrees"));
|
||||
@@ -62,5 +63,16 @@ public class TcxTrackWriterTest extends TrackFormatWriterTest {
|
||||
getChildTextValue(tag, "Time"));
|
||||
assertEquals(Double.toString(loc.getAltitude()),
|
||||
getChildTextValue(tag, "AltitudeMeters"));
|
||||
assertTrue(loc.getSensorDataSet() != null);
|
||||
Sensor.SensorDataSet sds = loc.getSensorDataSet();
|
||||
|
||||
List<Element> bpm = getChildElements(tag, "HeartRateBpm", 1);
|
||||
assertEquals(Integer.toString(sds.getHeartRate().getValue()),
|
||||
getChildTextValue(bpm.get(0), "Value"));
|
||||
|
||||
List<Element> ext = getChildElements(tag, "Extensions", 1);
|
||||
List<Element> tpx = getChildElements(ext.get(0), "TPX", 1);
|
||||
assertEquals(Integer.toString(sds.getPower().getValue()),
|
||||
getChildTextValue(tpx.get(0), "Watts"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
// Copyright 2010 Google Inc. All Rights Reserved.
|
||||
package com.google.android.apps.mytracks.io;
|
||||
|
||||
import com.google.android.apps.mytracks.content.MyTracksLocation;
|
||||
import com.google.android.apps.mytracks.content.Sensor;
|
||||
import com.google.android.apps.mytracks.content.Track;
|
||||
import com.google.android.apps.mytracks.content.Waypoint;
|
||||
|
||||
import android.location.Location;
|
||||
import android.test.AndroidTestCase;
|
||||
|
||||
import org.w3c.dom.Document;
|
||||
@@ -46,7 +47,7 @@ public abstract class TrackFormatWriterTest extends AndroidTestCase {
|
||||
private static final int BUFFER_SIZE = 10240;
|
||||
protected static final long TRACK_ID = 12345L;
|
||||
protected Track track;
|
||||
protected Location location1, location2, location3, location4;
|
||||
protected MyTracksLocation location1, location2, location3, location4;
|
||||
protected Waypoint wp1, wp2;
|
||||
|
||||
@Override
|
||||
@@ -58,10 +59,10 @@ public abstract class TrackFormatWriterTest extends AndroidTestCase {
|
||||
track.setName(TRACK_NAME);
|
||||
track.setDescription(TRACK_DESCRIPTION);
|
||||
|
||||
location1 = new Location("mock");
|
||||
location2 = new Location("mock");
|
||||
location3 = new Location("mock");
|
||||
location4 = new Location("mock");
|
||||
location1 = new MyTracksLocation("mock");
|
||||
location2 = new MyTracksLocation("mock");
|
||||
location3 = new MyTracksLocation("mock");
|
||||
location4 = new MyTracksLocation("mock");
|
||||
populateLocations(location1, location2, location3, location4);
|
||||
|
||||
wp1 = new Waypoint();
|
||||
@@ -77,13 +78,24 @@ public abstract class TrackFormatWriterTest extends AndroidTestCase {
|
||||
/**
|
||||
* Populates the given locations with coordinates and time.
|
||||
*/
|
||||
protected void populateLocations(Location... locs) {
|
||||
protected void populateLocations(MyTracksLocation... locs) {
|
||||
for (int i = 0; i < locs.length; i++) {
|
||||
Location loc = locs[i];
|
||||
MyTracksLocation loc = locs[i];
|
||||
loc.setAltitude(i * 1000);
|
||||
loc.setLatitude(i);
|
||||
loc.setLongitude(-i);
|
||||
loc.setTime(10000000 + i * 1000);
|
||||
Sensor.SensorData.Builder hr = Sensor.SensorData.newBuilder()
|
||||
.setValue(100 + i)
|
||||
.setState(Sensor.SensorState.SENDING);
|
||||
Sensor.SensorData.Builder power = Sensor.SensorData.newBuilder()
|
||||
.setValue(400 + i)
|
||||
.setState(Sensor.SensorState.SENDING);
|
||||
Sensor.SensorDataSet sds =
|
||||
Sensor.SensorDataSet.newBuilder().setHeartRate(hr.build())
|
||||
.setPower(power)
|
||||
.build();
|
||||
loc.setSensorData(sds);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,7 +151,7 @@ public abstract class TrackFormatWriterTest extends AndroidTestCase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all child elements of a given parent which gave the given name.
|
||||
* Returns all child elements of a given parent which have the given name.
|
||||
*
|
||||
* @param parent the parent to get children from
|
||||
* @param elementName the element name to look for
|
||||
|
||||
-72
@@ -1,72 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package com.google.android.apps.mytracks.services;
|
||||
|
||||
import com.google.android.apps.mytracks.util.ApiFeatures;
|
||||
|
||||
import android.test.AndroidTestCase;
|
||||
|
||||
/**
|
||||
* Tests for {@link SignalStrengthTaskFactoryTest}.
|
||||
* These tests require Eclair+ (API level 7) to run.
|
||||
*
|
||||
* @author Rodrigo Damazio
|
||||
*/
|
||||
public class SignalStrengthTaskFactoryTest extends AndroidTestCase {
|
||||
/**
|
||||
* Mock version of the {@link ApiFeatures} class.
|
||||
*/
|
||||
private static class MockApiFeatures extends ApiFeatures {
|
||||
private boolean hasModernStrength;
|
||||
|
||||
public void setHasModernSignalStrength(boolean hasModernStrength) {
|
||||
this.hasModernStrength = hasModernStrength;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasModernSignalStrength() {
|
||||
return hasModernStrength;
|
||||
}
|
||||
}
|
||||
|
||||
private MockApiFeatures apiFeatures;
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
|
||||
apiFeatures = new MockApiFeatures();
|
||||
}
|
||||
|
||||
public void testCreate() {
|
||||
apiFeatures.setHasModernSignalStrength(true);
|
||||
SignalStrengthTaskFactory factory =
|
||||
new SignalStrengthTaskFactory(apiFeatures);
|
||||
|
||||
PeriodicTask task = factory.create(getContext());
|
||||
assertTrue(task.getClass().getName(),
|
||||
task instanceof SignalStrengthTaskModern);
|
||||
}
|
||||
|
||||
public void testCreate_legacy() {
|
||||
apiFeatures.setHasModernSignalStrength(false);
|
||||
SignalStrengthTaskFactory factory =
|
||||
new SignalStrengthTaskFactory(apiFeatures);
|
||||
|
||||
PeriodicTask task = factory.create(getContext());
|
||||
assertTrue(task.getClass().getName(), task instanceof SignalStrengthTask);
|
||||
}
|
||||
}
|
||||
+114
-33
@@ -26,10 +26,12 @@ import com.google.android.apps.mytracks.stats.TripStatistics;
|
||||
import com.google.android.apps.mytracks.util.ApiFeatures;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.ContextWrapper;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.SharedPreferences.Editor;
|
||||
import android.location.Location;
|
||||
@@ -39,7 +41,9 @@ import android.test.ServiceTestCase;
|
||||
import android.test.mock.MockContentResolver;
|
||||
import android.test.suitebuilder.annotation.MediumTest;
|
||||
import android.test.suitebuilder.annotation.SmallTest;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -130,9 +134,9 @@ public class TrackRecordingServiceTest
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
|
||||
|
||||
ApiFeatures.injectInstance(new MockApiFeatures());
|
||||
|
||||
|
||||
MockContentResolver mockContentResolver = new MockContentResolver();
|
||||
RenamingDelegatingContext targetContext = new RenamingDelegatingContext(
|
||||
getContext(), getContext(), "test.");
|
||||
@@ -141,14 +145,14 @@ public class TrackRecordingServiceTest
|
||||
provider.attachInfo(context, null);
|
||||
mockContentResolver.addProvider(MyTracksProviderUtils.AUTHORITY, provider);
|
||||
setContext(context);
|
||||
|
||||
|
||||
providerUtils = MyTracksProviderUtils.Factory.get(context);
|
||||
|
||||
|
||||
sharedPreferences = context.getSharedPreferences(
|
||||
MyTracksSettings.SETTINGS_NAME, 0);
|
||||
// Let's use default values.
|
||||
sharedPreferences.edit().clear().commit();
|
||||
|
||||
|
||||
// Disable auto resume by default.
|
||||
updateAutoResumePrefs(0, -1);
|
||||
// No recording track.
|
||||
@@ -168,7 +172,7 @@ public class TrackRecordingServiceTest
|
||||
IBinder service = bindService(createStartIntent());
|
||||
assertNotNull(service);
|
||||
}
|
||||
|
||||
|
||||
@MediumTest
|
||||
public void testResumeAfterReboot_shouldResume() throws Exception {
|
||||
// Insert a dummy track and mark it as recording track.
|
||||
@@ -214,7 +218,7 @@ public class TrackRecordingServiceTest
|
||||
startIntent.putExtra(RESUME_TRACK_EXTRA_NAME, true);
|
||||
startService(startIntent);
|
||||
assertNotNull(getService());
|
||||
|
||||
|
||||
assertTrue(getService().isRecording());
|
||||
}
|
||||
|
||||
@@ -237,7 +241,7 @@ public class TrackRecordingServiceTest
|
||||
ITrackRecordingService service = bindAndGetService(createStartIntent());
|
||||
assertEquals(-1, service.getRecordingTrackId());
|
||||
}
|
||||
|
||||
|
||||
@MediumTest
|
||||
public void testResumeAfterReboot_expiredTrack() throws Exception {
|
||||
// Insert a dummy track last updated 20 min ago.
|
||||
@@ -251,7 +255,7 @@ public class TrackRecordingServiceTest
|
||||
startIntent.putExtra(RESUME_TRACK_EXTRA_NAME, true);
|
||||
startService(startIntent);
|
||||
assertNotNull(getService());
|
||||
|
||||
|
||||
// We don't expect to resume the previous track, because it has expired.
|
||||
assertFalse(getService().isRecording());
|
||||
ITrackRecordingService service = bindAndGetService(createStartIntent());
|
||||
@@ -284,17 +288,17 @@ public class TrackRecordingServiceTest
|
||||
public void testRecording_noTracks() throws Exception {
|
||||
List<Track> tracks = providerUtils.getAllTracks();
|
||||
assertTrue(tracks.isEmpty());
|
||||
|
||||
|
||||
ITrackRecordingService service = bindAndGetService(createStartIntent());
|
||||
// Test if we start in no-recording mode by default.
|
||||
assertFalse(service.isRecording());
|
||||
assertEquals(-1, service.getRecordingTrackId());
|
||||
}
|
||||
|
||||
|
||||
@MediumTest
|
||||
public void testRecording_oldTracks() throws Exception {
|
||||
createDummyTrack(123, -1, false);
|
||||
|
||||
|
||||
ITrackRecordingService service = bindAndGetService(createStartIntent());
|
||||
assertFalse(service.isRecording());
|
||||
assertEquals(-1, service.getRecordingTrackId());
|
||||
@@ -304,22 +308,71 @@ public class TrackRecordingServiceTest
|
||||
public void testRecording_orphanedRecordingTrack() throws Exception {
|
||||
// Just set recording track to a bogus value.
|
||||
setRecordingTrack(256);
|
||||
|
||||
|
||||
// Make sure that the service will not start recording and will clear
|
||||
// the bogus track.
|
||||
ITrackRecordingService service = bindAndGetService(createStartIntent());
|
||||
assertFalse(service.isRecording());
|
||||
assertEquals(-1, service.getRecordingTrackId());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Synchronous/waitable broadcast receiver to be used in testing.
|
||||
*/
|
||||
private class BlockingBroadcastReceiver extends BroadcastReceiver {
|
||||
private static final long MAX_WAIT_TIME_MS = 10000;
|
||||
private List<Intent> receivedIntents = new ArrayList<Intent>();
|
||||
|
||||
public List<Intent> getReceivedIntents() {
|
||||
return receivedIntents;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
Log.d("MyTracksTest", "Got broadcast: " + intent);
|
||||
synchronized (receivedIntents) {
|
||||
receivedIntents.add(intent);
|
||||
receivedIntents.notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean waitUntilReceived(int receiveCount) {
|
||||
long deadline = System.currentTimeMillis() + MAX_WAIT_TIME_MS;
|
||||
synchronized (receivedIntents) {
|
||||
while (receivedIntents.size() < receiveCount) {
|
||||
try {
|
||||
// Wait releases synchronized lock until it returns
|
||||
receivedIntents.wait(500);
|
||||
} catch (InterruptedException e) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
if (System.currentTimeMillis() > deadline) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@MediumTest
|
||||
public void testStartNewTrack_noRecording() throws Exception {
|
||||
// NOTICE: due to the way Android permissions work, if this fails,
|
||||
// uninstall the test apk then retry - the test must be installed *after*
|
||||
// My Tracks (go figure).
|
||||
// Reference: http://code.google.com/p/android/issues/detail?id=5521
|
||||
BlockingBroadcastReceiver startReceiver = new BlockingBroadcastReceiver();
|
||||
String startAction = context.getString(R.string.track_started_broadcast_action);
|
||||
context.registerReceiver(startReceiver, new IntentFilter(startAction));
|
||||
|
||||
List<Track> tracks = providerUtils.getAllTracks();
|
||||
assertTrue(tracks.isEmpty());
|
||||
|
||||
|
||||
ITrackRecordingService service = bindAndGetService(createStartIntent());
|
||||
assertFalse(service.isRecording());
|
||||
|
||||
|
||||
long id = service.startNewTrack();
|
||||
assertTrue(id >= 0);
|
||||
assertTrue(service.isRecording());
|
||||
@@ -329,15 +382,26 @@ public class TrackRecordingServiceTest
|
||||
assertEquals(id, sharedPreferences.getLong(
|
||||
context.getString(R.string.recording_track_key), -1));
|
||||
assertEquals(id, service.getRecordingTrackId());
|
||||
|
||||
// Verify that the start broadcast was received.
|
||||
assertTrue(startReceiver.waitUntilReceived(1));
|
||||
List<Intent> receivedIntents = startReceiver.getReceivedIntents();
|
||||
assertEquals(1, receivedIntents.size());
|
||||
Intent broadcastIntent = receivedIntents.get(0);
|
||||
assertEquals(startAction, broadcastIntent.getAction());
|
||||
assertEquals(id, broadcastIntent.getLongExtra(
|
||||
context.getString(R.string.track_id_broadcast_extra), -1));
|
||||
|
||||
context.unregisterReceiver(startReceiver);
|
||||
}
|
||||
|
||||
|
||||
@MediumTest
|
||||
public void testStartNewTrack_alreadyRecording() throws Exception {
|
||||
createDummyTrack(123, -1, true);
|
||||
|
||||
|
||||
ITrackRecordingService service = bindAndGetService(createStartIntent());
|
||||
assertTrue(service.isRecording());
|
||||
|
||||
|
||||
try {
|
||||
service.startNewTrack();
|
||||
fail("Expecting IllegalStateException");
|
||||
@@ -347,12 +411,17 @@ public class TrackRecordingServiceTest
|
||||
assertEquals(123, sharedPreferences.getLong(
|
||||
context.getString(R.string.recording_track_key), 0));
|
||||
assertEquals(123, service.getRecordingTrackId());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@MediumTest
|
||||
public void testEndCurrentTrack_alreadyRecording() throws Exception {
|
||||
// See comment above if this fails randomly.
|
||||
BlockingBroadcastReceiver stopReceiver = new BlockingBroadcastReceiver();
|
||||
String stopAction = context.getString(R.string.track_stopped_broadcast_action);
|
||||
context.registerReceiver(stopReceiver, new IntentFilter(stopAction));
|
||||
|
||||
createDummyTrack(123, -1, true);
|
||||
|
||||
|
||||
ITrackRecordingService service = bindAndGetService(createStartIntent());
|
||||
assertTrue(service.isRecording());
|
||||
|
||||
@@ -362,8 +431,19 @@ public class TrackRecordingServiceTest
|
||||
assertEquals(-1, sharedPreferences.getLong(
|
||||
context.getString(R.string.recording_track_key), 0));
|
||||
assertEquals(-1, service.getRecordingTrackId());
|
||||
|
||||
// Verify that the stop broadcast was received.
|
||||
assertTrue(stopReceiver.waitUntilReceived(1));
|
||||
List<Intent> receivedIntents = stopReceiver.getReceivedIntents();
|
||||
assertEquals(1, receivedIntents.size());
|
||||
Intent broadcastIntent = receivedIntents.get(0);
|
||||
assertEquals(stopAction, broadcastIntent.getAction());
|
||||
assertEquals(123, broadcastIntent.getLongExtra(
|
||||
context.getString(R.string.track_id_broadcast_extra), -1));
|
||||
|
||||
context.unregisterReceiver(stopReceiver);
|
||||
}
|
||||
|
||||
|
||||
@MediumTest
|
||||
public void testEndCurrentTrack_noRecording() throws Exception {
|
||||
ITrackRecordingService service = bindAndGetService(createStartIntent());
|
||||
@@ -561,16 +641,6 @@ public class TrackRecordingServiceTest
|
||||
functionalTest(R.string.min_recording_distance_key, 2);
|
||||
}
|
||||
|
||||
@MediumTest
|
||||
public void testWithProperties_noSignalSamplingFreq() throws Exception {
|
||||
functionalTest(R.string.signal_sampling_frequency_key, (Object) null);
|
||||
}
|
||||
|
||||
@MediumTest
|
||||
public void testWithProperties_defaultSignalSamplingFreq() throws Exception {
|
||||
functionalTest(R.string.signal_sampling_frequency_key, 1);
|
||||
}
|
||||
|
||||
@MediumTest
|
||||
public void testWithProperties_noSplitFreq() throws Exception {
|
||||
functionalTest(R.string.split_frequency_key, (Object) null);
|
||||
@@ -622,6 +692,17 @@ public class TrackRecordingServiceTest
|
||||
functionalTest(R.string.min_required_accuracy_key, 500);
|
||||
}
|
||||
|
||||
@MediumTest
|
||||
public void testWithProperties_noSensorType() throws Exception {
|
||||
functionalTest(R.string.sensor_type_key, (Object) null);
|
||||
}
|
||||
|
||||
@MediumTest
|
||||
public void testWithProperties_zephyrSensorType() throws Exception {
|
||||
functionalTest(R.string.sensor_type_key,
|
||||
context.getString(R.string.zephyr_sensor_type));
|
||||
}
|
||||
|
||||
private ITrackRecordingService bindAndGetService(Intent intent) {
|
||||
ITrackRecordingService service = ITrackRecordingService.Stub.asInterface(
|
||||
bindService(intent));
|
||||
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
package com.google.android.apps.mytracks.services.sensors;
|
||||
|
||||
import com.google.android.apps.mytracks.MyTracksSettings;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
|
||||
import android.content.SharedPreferences;
|
||||
import android.test.AndroidTestCase;
|
||||
import android.test.suitebuilder.annotation.SmallTest;
|
||||
|
||||
public class SensorManagerFactoryTest extends AndroidTestCase {
|
||||
|
||||
private SharedPreferences sharedPreferences;
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
|
||||
sharedPreferences = getContext().getSharedPreferences(
|
||||
MyTracksSettings.SETTINGS_NAME, 0);
|
||||
// Let's use default values.
|
||||
sharedPreferences.edit().clear().commit();
|
||||
}
|
||||
|
||||
@SmallTest
|
||||
public void testDefaultSettings() throws Exception {
|
||||
assertNull(SensorManagerFactory.getSensorManager(getContext()));
|
||||
}
|
||||
|
||||
@SmallTest
|
||||
public void testCreateZephyr() throws Exception {
|
||||
sharedPreferences.edit()
|
||||
.putString(getContext().getString(R.string.sensor_type_key),
|
||||
getContext().getString(R.string.zephyr_sensor_type))
|
||||
.commit();
|
||||
SensorManager sm = SensorManagerFactory.getSensorManager(getContext());
|
||||
assertNotNull(sm);
|
||||
assertTrue(sm instanceof ZephyrSensorManager);
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
package com.google.android.apps.mytracks.services.sensors;
|
||||
|
||||
import com.google.android.apps.mytracks.content.Sensor;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
public class ZephyrMessageParserTest extends TestCase {
|
||||
|
||||
ZephyrMessageParser parser = new ZephyrMessageParser();
|
||||
|
||||
public void testIsValid() {
|
||||
byte[] buf = new byte[60];
|
||||
assertFalse(parser.isValid(buf));
|
||||
buf[0] = 0x02;
|
||||
assertFalse(parser.isValid(buf));
|
||||
buf[59] = 0x03;
|
||||
assertTrue(parser.isValid(buf));
|
||||
}
|
||||
|
||||
public void testParseBuffer() {
|
||||
byte[] buf = new byte[60];
|
||||
buf[12] = 50;
|
||||
Sensor.SensorDataSet sds = parser.parseBuffer(buf);
|
||||
assertTrue(sds.hasHeartRate());
|
||||
assertTrue(sds.getHeartRate().getState() == Sensor.SensorState.SENDING);
|
||||
assertEquals(50, sds.getHeartRate().getValue());
|
||||
}
|
||||
|
||||
public void testFindNextAlignment() {
|
||||
byte[] buf = new byte[60];
|
||||
assertEquals(-1, parser.findNextAlignment(buf));
|
||||
buf[10] = 0x03;
|
||||
buf[11] = 0x02;
|
||||
assertEquals(10, parser.findNextAlignment(buf));
|
||||
}
|
||||
}
|
||||
@@ -65,17 +65,6 @@ public class ApiFeaturesTest extends TestCase {
|
||||
}
|
||||
}
|
||||
|
||||
public void testHasModernSignalStrength() {
|
||||
for (int i = 3; i <= 6; i++) {
|
||||
features.setApiLevel(i);
|
||||
assertFalse(features.hasModernSignalStrength());
|
||||
}
|
||||
features.setApiLevel(7);
|
||||
assertTrue(features.hasModernSignalStrength());
|
||||
features.setApiLevel(8);
|
||||
assertTrue(features.hasModernSignalStrength());
|
||||
}
|
||||
|
||||
public void testGetApiPlatformAdapter() {
|
||||
assertNotNull(features.getApiPlatformAdapter());
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="src" path="gen"/>
|
||||
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
|
||||
<classpathentry kind="src" path="MyTracksLib_src"/>
|
||||
<classpathentry exported="true" kind="lib" path="/MyTracksLib/libs/protobuf-java-2.3.0-lite.jar"/>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
</classpath>
|
||||
@@ -0,0 +1,40 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>SignalStrengthSampler</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>com.android.ide.eclipse.adt.ApkBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>com.android.ide.eclipse.adt.AndroidNature</nature>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
</natures>
|
||||
<linkedResources>
|
||||
<link>
|
||||
<name>MyTracksLib_src</name>
|
||||
<type>2</type>
|
||||
<locationURI>_android_MyTracksLib_e2802071/src</locationURI>
|
||||
</link>
|
||||
</linkedResources>
|
||||
</projectDescription>
|
||||
@@ -0,0 +1,12 @@
|
||||
#Tue Nov 23 23:09:24 PST 2010
|
||||
eclipse.preferences.version=1
|
||||
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
|
||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
|
||||
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
|
||||
org.eclipse.jdt.core.compiler.compliance=1.6
|
||||
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
|
||||
org.eclipse.jdt.core.compiler.debug.localVariable=generate
|
||||
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
|
||||
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.source=1.6
|
||||
@@ -0,0 +1,61 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright 2010 Google Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.google.android.apps.mytracks.signalstrength"
|
||||
android:versionCode="1"
|
||||
android:versionName="1.0">
|
||||
<application android:icon="@drawable/icon"
|
||||
android:label="@string/app_name">
|
||||
<!-- Activity for configuring preferences -->
|
||||
<activity android:name=".SignalStrengthPreferences"
|
||||
android:label="@string/app_name">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<!-- Receiver to know when recording starts/stops and act on the service accordingly -->
|
||||
<receiver android:name=".RecordingStateReceiver">
|
||||
<intent-filter>
|
||||
<action android:name="com.google.android.apps.mytracks.TRACK_STARTED" />
|
||||
<action android:name="com.google.android.apps.mytracks.TRACK_PAUSED" />
|
||||
<action android:name="com.google.android.apps.mytracks.TRACK_RESUMED" />
|
||||
<action android:name="com.google.android.apps.mytracks.TRACK_STOPPED" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<!-- Service which listens for signal strength and writes waypoints -->
|
||||
<service android:name=".SignalStrengthService"
|
||||
android:label="Signal Strength Sampling Service"
|
||||
android:icon="@drawable/icon"
|
||||
android:enabled="true" />
|
||||
</application>
|
||||
|
||||
<!-- Requirements -->
|
||||
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
|
||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
||||
<uses-permission android:name="com.google.android.apps.mytracks.TRACK_NOTIFICATIONS" />
|
||||
<uses-permission android:name="com.google.android.apps.mytracks.WRITE_TRACK_DATA" />
|
||||
<uses-feature android:name="android.hardware.telephony" android:required="true"/>
|
||||
<uses-feature android:name="android.hardware.telephony.gsm" android:required="false"/>
|
||||
<uses-sdk android:minSdkVersion="3" />
|
||||
<supports-screens android:largeScreens="true"
|
||||
android:normalScreens="true"
|
||||
android:smallScreens="true"
|
||||
android:anyDensity="true" />
|
||||
</manifest>
|
||||
@@ -0,0 +1,12 @@
|
||||
# This file is automatically generated by Android Tools.
|
||||
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
|
||||
#
|
||||
# This file must be checked in Version Control Systems.
|
||||
#
|
||||
# To customize properties used by the Ant build system use,
|
||||
# "build.properties", and override values to adapt the script to your
|
||||
# project structure.
|
||||
|
||||
# Project target.
|
||||
target=Google Inc.:Google APIs:8
|
||||
android.library.reference.1=../MyTracksLib/
|
||||
@@ -0,0 +1,34 @@
|
||||
-optimizationpasses 5
|
||||
-dontusemixedcaseclassnames
|
||||
-dontskipnonpubliclibraryclasses
|
||||
-dontpreverify
|
||||
-verbose
|
||||
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
|
||||
|
||||
-keep public class * extends android.app.Activity
|
||||
-keep public class * extends android.app.Application
|
||||
-keep public class * extends android.app.Service
|
||||
-keep public class * extends android.content.BroadcastReceiver
|
||||
-keep public class * extends android.content.ContentProvider
|
||||
-keep public class com.android.vending.licensing.ILicensingService
|
||||
|
||||
-keepclasseswithmembernames class * {
|
||||
native <methods>;
|
||||
}
|
||||
|
||||
-keepclasseswithmembernames class * {
|
||||
public <init>(android.content.Context, android.util.AttributeSet);
|
||||
}
|
||||
|
||||
-keepclasseswithmembernames class * {
|
||||
public <init>(android.content.Context, android.util.AttributeSet, int);
|
||||
}
|
||||
|
||||
-keepclassmembers enum * {
|
||||
public static **[] values();
|
||||
public static ** valueOf(java.lang.String);
|
||||
}
|
||||
|
||||
-keep class * implements android.os.Parcelable {
|
||||
public static final android.os.Parcelable$Creator *;
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 2.5 KiB |
@@ -0,0 +1,41 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright 2010 Google Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<resources>
|
||||
<!-- Task frequency -->
|
||||
<string-array name="task_period_options">
|
||||
<item>As often as possible</item>
|
||||
<item>1 min</item>
|
||||
<item>2 min</item>
|
||||
<item>5 min</item>
|
||||
<item>10 min</item>
|
||||
<item>15 min</item>
|
||||
<item>30 min</item>
|
||||
<item>60 min</item>
|
||||
</string-array>
|
||||
|
||||
<!-- DO NOT TRANSLATE -->
|
||||
<string-array name="task_period_values">
|
||||
<item>-1</item>
|
||||
<item>1</item>
|
||||
<item>2</item>
|
||||
<item>5</item>
|
||||
<item>10</item>
|
||||
<item>15</item>
|
||||
<item>30</item>
|
||||
<item>60</item>
|
||||
</string-array>
|
||||
</resources>
|
||||
@@ -0,0 +1,54 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright 2010 Google Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<resources>
|
||||
<string name="app_name">Signal strength sampler for My Tracks</string>
|
||||
|
||||
<string name="settings_sampling">Sampling settings</string>
|
||||
<string name="settings_auto_start">Automatic start</string>
|
||||
<string name="settings_auto_start_summary_on">Automatically start inserting signal strength waypoints whenever My Tracks starts recording a track.</string>
|
||||
<string name="settings_auto_start_summary_off">You will need to manually start signal sampling using the controls below.</string>
|
||||
<string name="settings_auto_stop">Automatic stop</string>
|
||||
<string name="settings_auto_stop_summary_on">Automatically stop inserting signal strength waypoints whenever My Tracks stops recording a track.</string>
|
||||
<string name="settings_auto_stop_summary_off">You will need to manually stop signal sampling using the controls below.</string>
|
||||
<string name="settings_min_signal_sampling_period">Min. sampling period</string>
|
||||
<string name="settings_min_signal_sampling_period_summary">Minimum time between two recordings of the phone\'s signal strength</string>
|
||||
|
||||
<string name="settings_control">Sampling control</string>
|
||||
<string name="settings_control_start">Start sampling</string>
|
||||
<string name="settings_control_start_summary">Starts sampling signal strength immediately, if My Tracks is recording. Sampling will stop once My Tracks stops recording.</string>
|
||||
<string name="settings_control_stop">Stop sampling</string>
|
||||
<string name="settings_control_stop_summary">Stops sampling signal strength if sampling is currently active.</string>
|
||||
|
||||
<string name="started_sampling">Started sampling cell signal strength.</string>
|
||||
<string name="stopped_sampling">Stopped sampling cell signal strength.</string>
|
||||
<string name="unknown">-</string>
|
||||
|
||||
<!-- Signal Strength -->
|
||||
<string name="error_rate"> Error Rate: %1$d</string>
|
||||
<string name="signal_to_noise_ratio"> Signal to Noise Ratio: %1$d</string>
|
||||
<string name="ecio"> Ec/lo: %1$.1f dB</string>
|
||||
<string name="gsm_strength">GSM Strength: %1$d</string>
|
||||
<string name="cdma_strength">CDMA Strength: %1$d dBm</string>
|
||||
<string name="evdo_strength">EVDO Strength: %1$d dBm</string>
|
||||
|
||||
<!-- Non-translatable strings -->
|
||||
<string name="settings_auto_start_key">autoStartSampling</string>
|
||||
<string name="settings_auto_stop_key">autoStopSampling</string>
|
||||
<string name="settings_min_signal_sampling_period_key">signalSamplingFrequency</string>
|
||||
<string name="settings_control_start_key">startSamplingControl</string>
|
||||
<string name="settings_control_stop_key">stopSamplingControl</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,52 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright 2010 Google Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<PreferenceCategory android:title="@string/settings_sampling">
|
||||
<CheckBoxPreference android:key="@string/settings_auto_start_key"
|
||||
android:title="@string/settings_auto_start"
|
||||
android:summaryOn="@string/settings_auto_start_summary_on"
|
||||
android:summaryOff="@string/settings_auto_start_summary_off"
|
||||
android:defaultValue="false" />
|
||||
<CheckBoxPreference android:key="@string/settings_auto_stop_key"
|
||||
android:title="@string/settings_auto_stop"
|
||||
android:summaryOn="@string/settings_auto_stop_summary_on"
|
||||
android:summaryOff="@string/settings_auto_stop_summary_off"
|
||||
android:defaultValue="true" />
|
||||
|
||||
<ListPreference
|
||||
android:key="@string/settings_min_signal_sampling_period_key"
|
||||
android:title="@string/settings_min_signal_sampling_period"
|
||||
android:summary="@string/settings_min_signal_sampling_period_summary"
|
||||
android:entries="@array/task_period_options"
|
||||
android:entryValues="@array/task_period_values"
|
||||
android:defaultValue="-1" />
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory android:title="@string/settings_control">
|
||||
<Preference android:key="@string/settings_control_start_key"
|
||||
android:title="@string/settings_control_start"
|
||||
android:summary="@string/settings_control_start_summary"
|
||||
android:persistent="false" />
|
||||
|
||||
<Preference android:key="@string/settings_control_stop_key"
|
||||
android:title="@string/settings_control_stop"
|
||||
android:summary="@string/settings_control_stop_summary"
|
||||
android:persistent="false" />
|
||||
</PreferenceCategory>
|
||||
|
||||
</PreferenceScreen>
|
||||
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright 2010 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package com.google.android.apps.mytracks.signalstrength;
|
||||
|
||||
import static com.google.android.apps.mytracks.signalstrength.SignalStrengthConstants.*;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* Broadcast listener which gets notified when we start or stop recording a track.
|
||||
*
|
||||
* @author Rodrigo Damazio
|
||||
*/
|
||||
public class RecordingStateReceiver extends BroadcastReceiver {
|
||||
@Override
|
||||
public void onReceive(Context ctx, Intent intent) {
|
||||
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(ctx);
|
||||
|
||||
String action = intent.getAction();
|
||||
if (ctx.getString(R.string.track_started_broadcast_action).equals(action) ||
|
||||
ctx.getString(R.string.track_resumed_broadcast_action).equals(action)) {
|
||||
boolean autoStart = preferences.getBoolean(
|
||||
ctx.getString(R.string.settings_auto_start_key), false);
|
||||
if (!autoStart) {
|
||||
Log.d(TAG, "Not auto-starting signal sampling");
|
||||
return;
|
||||
}
|
||||
|
||||
startService(ctx);
|
||||
} else if (ctx.getString(R.string.track_stopped_broadcast_action).equals(action) ||
|
||||
ctx.getString(R.string.track_paused_broadcast_action).equals(action)) {
|
||||
boolean autoStop = preferences.getBoolean(
|
||||
ctx.getString(R.string.settings_auto_stop_key), true);
|
||||
if (!autoStop) {
|
||||
Log.d(TAG, "Not auto-stopping signal sampling");
|
||||
return;
|
||||
}
|
||||
|
||||
stopService(ctx);
|
||||
} else {
|
||||
Log.e(TAG, "Unknown action received: " + action);
|
||||
}
|
||||
}
|
||||
|
||||
// @VisibleForTesting
|
||||
protected void stopService(Context ctx) {
|
||||
SignalStrengthService.stopService(ctx);
|
||||
}
|
||||
|
||||
// @VisibleForTesting
|
||||
protected void startService(Context ctx) {
|
||||
SignalStrengthService.startService(ctx);
|
||||
}
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2010 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package com.google.android.apps.mytracks.signalstrength;
|
||||
|
||||
import android.os.Build;
|
||||
|
||||
/**
|
||||
* Constants for the signal sampler.
|
||||
*
|
||||
* @author Rodrigo Damazio
|
||||
*/
|
||||
public class SignalStrengthConstants {
|
||||
public static final String START_SAMPLING =
|
||||
"com.google.android.apps.mytracks.signalstrength.START";
|
||||
public static final String STOP_SAMPLING =
|
||||
"com.google.android.apps.mytracks.signalstrength.STOP";
|
||||
|
||||
public static final int ANDROID_API_LEVEL = Integer.parseInt(
|
||||
Build.VERSION.SDK);
|
||||
|
||||
public static final String TAG = "SignalStrengthSampler";
|
||||
|
||||
private SignalStrengthConstants() {}
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2010 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package com.google.android.apps.mytracks.signalstrength;
|
||||
|
||||
/**
|
||||
* Interface for the service that reads signal strength.
|
||||
*
|
||||
* @author Rodrigo Damazio
|
||||
*/
|
||||
public interface SignalStrengthListener {
|
||||
/**
|
||||
* Interface for getting notified about a new sampled signal strength.
|
||||
*/
|
||||
public interface SignalStrengthCallback {
|
||||
void onSignalStrengthSampled(
|
||||
String description,
|
||||
String icon);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts listening to signal strength.
|
||||
*/
|
||||
void register();
|
||||
|
||||
/**
|
||||
* Stops listening to signal strength.
|
||||
*/
|
||||
void unregister();
|
||||
}
|
||||
+28
-45
@@ -13,14 +13,11 @@
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package com.google.android.apps.mytracks.signalstrength;
|
||||
|
||||
package com.google.android.apps.mytracks.services;
|
||||
|
||||
import com.google.android.apps.mytracks.MyTracksConstants;
|
||||
import com.google.android.apps.mytracks.content.Waypoint;
|
||||
import static com.google.android.apps.mytracks.signalstrength.SignalStrengthConstants.*;
|
||||
|
||||
import android.content.Context;
|
||||
import android.location.Location;
|
||||
import android.telephony.CellLocation;
|
||||
import android.telephony.NeighboringCellInfo;
|
||||
import android.telephony.PhoneStateListener;
|
||||
@@ -31,67 +28,49 @@ import java.util.List;
|
||||
|
||||
/**
|
||||
* A class to monitor the network signal strength.
|
||||
*
|
||||
* TODO: i18n
|
||||
*
|
||||
* @author Sandor Dornbush
|
||||
*/
|
||||
public class SignalStrengthTask extends PhoneStateListener
|
||||
implements PeriodicTask {
|
||||
|
||||
public class SignalStrengthListenerCupcake extends PhoneStateListener
|
||||
implements SignalStrengthListener {
|
||||
private final Context context;
|
||||
private final SignalStrengthCallback callback;
|
||||
|
||||
private TelephonyManager manager;
|
||||
private int signalStrength = -1;
|
||||
|
||||
public SignalStrengthTask(Context c) {
|
||||
context = c;
|
||||
public SignalStrengthListenerCupcake(Context context, SignalStrengthCallback callback) {
|
||||
this.context = context;
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
manager =
|
||||
(TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
|
||||
public void register() {
|
||||
manager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
|
||||
if (manager == null) {
|
||||
Log.e(MyTracksConstants.TAG, "Cannot get telephony manager.");
|
||||
Log.e(TAG, "Cannot get telephony manager.");
|
||||
} else {
|
||||
manager.listen(this, getListenEvents());
|
||||
}
|
||||
}
|
||||
|
||||
protected int getListenEvents() {
|
||||
return PhoneStateListener.LISTEN_SIGNAL_STRENGTHS;
|
||||
return PhoneStateListener.LISTEN_SIGNAL_STRENGTH;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSignalStrengthChanged(int asu) {
|
||||
this.signalStrength = asu;
|
||||
Log.d(MyTracksConstants.TAG, "Signal Strength: " + signalStrength);
|
||||
public void onSignalStrengthChanged(int signalStrength) {
|
||||
Log.d(TAG, "Signal Strength: " + signalStrength);
|
||||
this.signalStrength = signalStrength;
|
||||
|
||||
notifySignalSampled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(TrackRecordingService service) {
|
||||
Log.d(MyTracksConstants.TAG, "Adding signal marker");
|
||||
Location location = service.getLastLocation();
|
||||
if (manager == null) {
|
||||
Log.d(MyTracksConstants.TAG, "Adding signal marker: marker null");
|
||||
return;
|
||||
}
|
||||
if (location == null) {
|
||||
Log.d(MyTracksConstants.TAG, "Adding signal marker: location null");
|
||||
return;
|
||||
}
|
||||
Waypoint wpt = new Waypoint();
|
||||
wpt.setName("Signal Strength");
|
||||
wpt.setType(Waypoint.TYPE_WAYPOINT);
|
||||
wpt.setTrackId(service.getRecordingTrackId());
|
||||
protected void notifySignalSampled() {
|
||||
int networkType = manager.getNetworkType();
|
||||
wpt.setIcon(getIcon(networkType));
|
||||
wpt.setLocation(location);
|
||||
wpt.setDescription(getDescription());
|
||||
long waypointId = service.insertWaypointMarker(wpt);
|
||||
if (waypointId >= 0) {
|
||||
Log.d(MyTracksConstants.TAG, "Added signal marker");
|
||||
} else {
|
||||
Log.e(MyTracksConstants.TAG, "Cannot insert waypoint marker?");
|
||||
}
|
||||
callback.onSignalStrengthSampled(getDescription(), getIcon(networkType));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -138,7 +117,7 @@ public class SignalStrengthTask extends PhoneStateListener
|
||||
sb.append('\n');
|
||||
|
||||
List<NeighboringCellInfo> infos = manager.getNeighboringCellInfo();
|
||||
Log.i(MyTracksConstants.TAG, "Found " + infos.size() + " cells.");
|
||||
Log.i(TAG, "Found " + infos.size() + " cells.");
|
||||
if (infos.size() > 0) {
|
||||
sb.append("Neighbors: ");
|
||||
for (NeighboringCellInfo info : infos) {
|
||||
@@ -178,7 +157,7 @@ public class SignalStrengthTask extends PhoneStateListener
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdown() {
|
||||
public void unregister() {
|
||||
if (manager != null) {
|
||||
manager.listen(this, PhoneStateListener.LISTEN_NONE);
|
||||
manager = null;
|
||||
@@ -192,4 +171,8 @@ public class SignalStrengthTask extends PhoneStateListener
|
||||
protected Context getContext() {
|
||||
return context;
|
||||
}
|
||||
|
||||
public SignalStrengthCallback getSignalStrengthCallback() {
|
||||
return callback;
|
||||
}
|
||||
}
|
||||
+14
-12
@@ -14,10 +14,9 @@
|
||||
* the License.
|
||||
*/
|
||||
|
||||
package com.google.android.apps.mytracks.services;
|
||||
package com.google.android.apps.mytracks.signalstrength;
|
||||
|
||||
import com.google.android.apps.mytracks.MyTracksConstants;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
import static com.google.android.apps.mytracks.signalstrength.SignalStrengthConstants.*;
|
||||
|
||||
import android.content.Context;
|
||||
import android.telephony.PhoneStateListener;
|
||||
@@ -27,15 +26,17 @@ import android.util.Log;
|
||||
|
||||
/**
|
||||
* A class to monitor the network signal strength.
|
||||
*
|
||||
* TODO: i18n
|
||||
*
|
||||
* @author Sandor Dornbush
|
||||
*/
|
||||
public class SignalStrengthTaskModern extends SignalStrengthTask {
|
||||
public class SignalStrengthListenerEclair extends SignalStrengthListenerCupcake {
|
||||
|
||||
private SignalStrength signalStrength = null;
|
||||
|
||||
public SignalStrengthTaskModern(Context c) {
|
||||
super(c);
|
||||
public SignalStrengthListenerEclair(Context ctx, SignalStrengthCallback callback) {
|
||||
super(ctx, callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -43,6 +44,13 @@ public class SignalStrengthTaskModern extends SignalStrengthTask {
|
||||
return PhoneStateListener.LISTEN_SIGNAL_STRENGTHS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSignalStrengthsChanged(SignalStrength signalStrength) {
|
||||
Log.d(TAG, "Signal Strength Modern: " + signalStrength);
|
||||
this.signalStrength = signalStrength;
|
||||
notifySignalSampled();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a human readable description for the network type.
|
||||
*
|
||||
@@ -146,10 +154,4 @@ public class SignalStrengthTaskModern extends SignalStrengthTask {
|
||||
sb.append(getContext().getString(signalFormat, signal));
|
||||
sb.append("\n");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSignalStrengthsChanged(SignalStrength signalStrength) {
|
||||
Log.d(MyTracksConstants.TAG, "Signal Strength Modern: " + signalStrength);
|
||||
this.signalStrength = signalStrength;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user