forked from upstream-mirrors/OpenTracks
Merging to head.
This commit is contained in:
@@ -7,3 +7,5 @@ syntax:glob
|
|||||||
MyTracksTest/annotations.log
|
MyTracksTest/annotations.log
|
||||||
**/*.pyc
|
**/*.pyc
|
||||||
**/*.pyo
|
**/*.pyo
|
||||||
|
syntax: glob
|
||||||
|
MyTracksTest/hs_err_pid*.log
|
||||||
|
|||||||
+9
-1
@@ -3,8 +3,16 @@
|
|||||||
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
|
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
|
||||||
<classpathentry kind="lib" path="libs/googleloginclient-helper.jar"/>
|
<classpathentry kind="lib" path="libs/googleloginclient-helper.jar"/>
|
||||||
<classpathentry kind="lib" path="libs/google-common.jar"/>
|
<classpathentry kind="lib" path="libs/google-common.jar"/>
|
||||||
<classpathentry kind="lib" path="libs/google-api-client-1.2.2-alpha.jar"/>
|
|
||||||
<classpathentry kind="lib" path="libs/libGoogleAnalytics.jar"/>
|
<classpathentry kind="lib" path="libs/libGoogleAnalytics.jar"/>
|
||||||
|
<classpathentry kind="lib" path="libs/google-api-client/commons-codec-1.3.jar"/>
|
||||||
|
<classpathentry kind="lib" path="libs/google-api-client/commons-logging-1.1.1.jar"/>
|
||||||
|
<classpathentry kind="lib" path="libs/google-api-client/google-api-client-1.5.0-beta.jar"/>
|
||||||
|
<classpathentry kind="lib" path="libs/google-api-client/google-http-client-1.5.0-beta.jar"/>
|
||||||
|
<classpathentry kind="lib" path="libs/google-api-client/google-oauth-client-1.5.0-beta.jar"/>
|
||||||
|
<classpathentry kind="lib" path="libs/google-api-client/gson-1.6.jar"/>
|
||||||
|
<classpathentry kind="lib" path="libs/google-api-client/guava-r09.jar"/>
|
||||||
|
<classpathentry kind="lib" path="libs/google-api-client/jackson-core-asl-1.6.7.jar"/>
|
||||||
|
<classpathentry kind="lib" path="libs/google-api-client/jsr305-1.3.9.jar"/>
|
||||||
<classpathentry kind="src" path="src"/>
|
<classpathentry kind="src" path="src"/>
|
||||||
<classpathentry kind="src" path="gen"/>
|
<classpathentry kind="src" path="gen"/>
|
||||||
<classpathentry exported="true" kind="lib" path="/MyTracksLib/libs/protobuf-java-2.3.0-lite.jar"/>
|
<classpathentry exported="true" kind="lib" path="/MyTracksLib/libs/protobuf-java-2.3.0-lite.jar"/>
|
||||||
|
|||||||
@@ -17,10 +17,11 @@ limitations under the License.
|
|||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
package="com.google.android.maps.mytracks"
|
package="com.google.android.maps.mytracks"
|
||||||
android:installLocation="auto"
|
android:installLocation="auto"
|
||||||
android:versionCode="32"
|
android:versionCode="33"
|
||||||
android:versionName="1.1.9">
|
android:versionName="1.1.10">
|
||||||
<application android:icon="@drawable/arrow_icon"
|
<application android:icon="@drawable/arrow_icon"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
|
android:name="com.google.android.apps.mytracks.MyTracksApplication"
|
||||||
android:backupAgent="com.google.android.apps.mytracks.io.backup.MyTracksBackupAgent">
|
android:backupAgent="com.google.android.apps.mytracks.io.backup.MyTracksBackupAgent">
|
||||||
<uses-library android:name="com.google.android.maps" />
|
<uses-library android:name="com.google.android.maps" />
|
||||||
|
|
||||||
@@ -177,6 +178,9 @@ limitations under the License.
|
|||||||
android:exported="true"
|
android:exported="true"
|
||||||
android:permission="com.google.android.apps.mytracks.WRITE_TRACK_DATA" />
|
android:permission="com.google.android.apps.mytracks.WRITE_TRACK_DATA" />
|
||||||
|
|
||||||
|
<service android:name="com.google.android.apps.mytracks.services.ControlRecordingService"
|
||||||
|
android:exported="false" />
|
||||||
|
|
||||||
<receiver android:name="com.google.android.apps.mytracks.BootReceiver">
|
<receiver android:name="com.google.android.apps.mytracks.BootReceiver">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||||
@@ -188,7 +192,6 @@ limitations under the License.
|
|||||||
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
|
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
|
||||||
<action android:name="com.google.android.apps.mytracks.TRACK_STARTED" />
|
<action android:name="com.google.android.apps.mytracks.TRACK_STARTED" />
|
||||||
<action android:name="com.google.android.apps.mytracks.TRACK_STOPPED" />
|
<action android:name="com.google.android.apps.mytracks.TRACK_STOPPED" />
|
||||||
<action android:name="com.google.android.apps.mytracks.TRACK_UPDATED" />
|
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
<meta-data android:name="android.appwidget.provider"
|
<meta-data android:name="android.appwidget.provider"
|
||||||
android:resource="@xml/track_widget_info" />
|
android:resource="@xml/track_widget_info" />
|
||||||
@@ -230,7 +233,7 @@ limitations under the License.
|
|||||||
android:permissionGroup="android.permission-group.LOCATION"
|
android:permissionGroup="android.permission-group.LOCATION"
|
||||||
android:label="@string/notification_permission_label"
|
android:label="@string/notification_permission_label"
|
||||||
android:description="@string/notification_permission_description"
|
android:description="@string/notification_permission_description"
|
||||||
android:protectionLevel="normal" />
|
android:protectionLevel="dangerous" />
|
||||||
<!-- Permission to read raw track data (points, etc.) -->
|
<!-- Permission to read raw track data (points, etc.) -->
|
||||||
<permission android:name="com.google.android.apps.mytracks.READ_TRACK_DATA"
|
<permission android:name="com.google.android.apps.mytracks.READ_TRACK_DATA"
|
||||||
android:permissionGroup="android.permission-group.LOCATION"
|
android:permissionGroup="android.permission-group.LOCATION"
|
||||||
@@ -244,10 +247,17 @@ limitations under the License.
|
|||||||
android:description="@string/write_tracks_permission_description"
|
android:description="@string/write_tracks_permission_description"
|
||||||
android:protectionLevel="dangerous" />
|
android:protectionLevel="dangerous" />
|
||||||
|
|
||||||
|
<!-- Permission to get MyTracks broadcasts. For internal MyTracks communication. -->
|
||||||
|
<permission android:name="com.google.android.apps.mytracks.MYTRACKS_NOTIFICATIONS"
|
||||||
|
android:permissionGroup="android.permission-group.LOCATION"
|
||||||
|
android:label="@string/mytracks_notifications_permission_label"
|
||||||
|
android:description="@string/mytracks_notifications_permission_description"
|
||||||
|
android:protectionLevel="signature" />
|
||||||
|
|
||||||
<!-- We read and write raw track data, obviously. -->
|
<!-- 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.READ_TRACK_DATA" />
|
||||||
<uses-permission android:name="com.google.android.apps.mytracks.WRITE_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" />
|
<uses-permission android:name="com.google.android.apps.mytracks.MYTRACKS_NOTIFICATIONS" />
|
||||||
|
|
||||||
<!-- Features required -->
|
<!-- Features required -->
|
||||||
<uses-feature android:name="android.hardware.location" android:required="true"/>
|
<uses-feature android:name="android.hardware.location" android:required="true"/>
|
||||||
|
|||||||
@@ -13,7 +13,5 @@ split.density=false
|
|||||||
target=Google Inc.:Google APIs:13
|
target=Google Inc.:Google APIs:13
|
||||||
android.library.reference.1=../MyTracksLib/
|
android.library.reference.1=../MyTracksLib/
|
||||||
|
|
||||||
# ProGuard is turned off while we investigate the removal of code that
|
# Enable proguard.
|
||||||
# isn't actually dead from Fusion Tables. See issue 303 for an example of
|
proguard.config=proguard.cfg
|
||||||
# the result of that removal.
|
|
||||||
#proguard.config=proguard.cfg
|
|
||||||
|
|||||||
@@ -3,12 +3,20 @@ own licenses, which allow their usage for the My Tracks application. Any other
|
|||||||
applications that wish to use these files should consult the appropriate
|
applications that wish to use these files should consult the appropriate
|
||||||
licenses or the JAR's authors.
|
licenses or the JAR's authors.
|
||||||
|
|
||||||
References are provided to the libraries:
|
google-api-client/
|
||||||
|
- see http://code.google.com/p/google-api-java-client/.
|
||||||
|
- contains Google API client library, google-api-client-1.5.0-beta.jar, and its
|
||||||
|
dependencies.
|
||||||
|
- google-api-client-1.5.0-beta.jar depends on protobuf-java-2.2.0.jar, however,
|
||||||
|
MyTracksLib already includes protobuf-java.2.3.0-lite.jar. Thus using the
|
||||||
|
newer version, protobuf-java.2.3.0-lite.jar.
|
||||||
|
- google-api-client-1.5.0-beta.jar also depends on xpp3-1.1.4c.jar, however,
|
||||||
|
some of its classes are already included in the android framework, thus not
|
||||||
|
including xpp3-1.1.4c.jar.
|
||||||
|
|
||||||
google-api-client-*.jar (GData client):
|
google-common.jar
|
||||||
http://code.google.com/p/google-api-java-client/
|
|
||||||
|
|
||||||
google-common.jar,
|
googleloginclient-helper.jar
|
||||||
googleloginclient-helper.jar,
|
|
||||||
libmymaps.jar (Google My Maps upload library):
|
libGoogleAnalytics.jar
|
||||||
Licensed exclusively for use in My Tracks and derived Android applications.
|
- see http://code.google.com/mobile/analytics/docs/.
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -14,6 +14,10 @@
|
|||||||
-dontwarn com.google.android.gsf.**
|
-dontwarn com.google.android.gsf.**
|
||||||
-dontwarn org.codehaus.**
|
-dontwarn org.codehaus.**
|
||||||
-dontwarn com.google.appengine.**
|
-dontwarn com.google.appengine.**
|
||||||
|
-dontwarn org.apache.avalon.framework.logger.**
|
||||||
|
-dontwarn org.apache.log.**
|
||||||
|
-dontwarn org.apache.log4j.**
|
||||||
|
-dontwarn javax.servlet.**
|
||||||
|
|
||||||
# Make our stack traces useful
|
# Make our stack traces useful
|
||||||
# Line numbers will be correct, file names will be replaced by "MT" since the
|
# Line numbers will be correct, file names will be replaced by "MT" since the
|
||||||
@@ -51,3 +55,21 @@
|
|||||||
-keep class * implements android.os.Parcelable {
|
-keep class * implements android.os.Parcelable {
|
||||||
public static final android.os.Parcelable$Creator *;
|
public static final android.os.Parcelable$Creator *;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Needed by google-api-client to keep generic types and @Key annotations accessed via reflection
|
||||||
|
|
||||||
|
-keepclassmembers class * {
|
||||||
|
@com.google.api.client.util.Key <fields>;
|
||||||
|
}
|
||||||
|
|
||||||
|
-keepattributes Signature,RuntimeVisibleAnnotations,AnnotationDefault
|
||||||
|
|
||||||
|
# Needed by Guava
|
||||||
|
|
||||||
|
-dontwarn sun.misc.Unsafe
|
||||||
|
|
||||||
|
# Keep services needed by ANT+ protocol
|
||||||
|
-keep public class com.dsi.ant.IAnt_6
|
||||||
|
-keep public class com.dsi.ant.IAnt
|
||||||
|
-keep public class com.dsi.ant.IServiceSettings
|
||||||
|
|
||||||
|
|||||||
@@ -40,7 +40,9 @@ limitations under the License.
|
|||||||
android:singleLine="true"
|
android:singleLine="true"
|
||||||
android:autoText="true"
|
android:autoText="true"
|
||||||
android:capitalize="words"
|
android:capitalize="words"
|
||||||
android:selectAllOnFocus="true"/>
|
android:selectAllOnFocus="true"
|
||||||
|
android:hint="@string/trackdetails_name_hint"
|
||||||
|
android:imeOptions="actionNext"/>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
<TextView android:text="@string/trackdetails_category"
|
<TextView android:text="@string/trackdetails_category"
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
@@ -48,7 +50,9 @@ limitations under the License.
|
|||||||
<AutoCompleteTextView android:id="@+id/trackdetails_category"
|
<AutoCompleteTextView android:id="@+id/trackdetails_category"
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:singleLine="true"/>
|
android:singleLine="true"
|
||||||
|
android:hint="@string/trackdetails_category_hint"
|
||||||
|
android:imeOptions="actionNext"/>
|
||||||
<TextView android:text="@string/trackdetails_description"
|
<TextView android:text="@string/trackdetails_description"
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="wrap_content"/>
|
android:layout_height="wrap_content"/>
|
||||||
@@ -61,7 +65,9 @@ limitations under the License.
|
|||||||
android:selectAllOnFocus="true"
|
android:selectAllOnFocus="true"
|
||||||
android:maxLines="50"
|
android:maxLines="50"
|
||||||
android:gravity="top"
|
android:gravity="top"
|
||||||
android:layout_weight="1"/>
|
android:layout_weight="1"
|
||||||
|
android:hint="@string/trackdetails_description_hint"
|
||||||
|
android:imeOptions="actionDone"/>
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
|
|||||||
@@ -127,26 +127,24 @@ limitations under the License.
|
|||||||
</TableLayout>
|
</TableLayout>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:orientation="horizontal"
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:background="@drawable/list_bar"
|
android:background="@drawable/list_bar"
|
||||||
android:padding="3dip">
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:paddingLeft="2dip"
|
||||||
|
android:paddingRight="2dip"
|
||||||
|
android:paddingTop="4dip">
|
||||||
|
<!-- left spacer -->
|
||||||
|
<LinearLayout style="@style/DialogButtonSpacer"/>
|
||||||
<Button android:id="@+id/sendtogoogle_cancel"
|
<Button android:id="@+id/sendtogoogle_cancel"
|
||||||
android:layout_width="wrap_content"
|
android:layout_gravity="left"
|
||||||
android:layout_height="48dip"
|
|
||||||
android:layout_gravity="right"
|
|
||||||
android:text="@string/cancel"
|
android:text="@string/cancel"
|
||||||
android:textSize="14dip"/>
|
style="@style/DialogButton"/>
|
||||||
<TextView
|
|
||||||
android:layout_width="0dip"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="1"/>
|
|
||||||
<Button android:id="@+id/sendtogoogle_send_now"
|
<Button android:id="@+id/sendtogoogle_send_now"
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="48dip"
|
|
||||||
android:layout_gravity="right"
|
android:layout_gravity="right"
|
||||||
android:text="@string/sendtogoogle_send_now"
|
android:text="@string/sendtogoogle_send_now"
|
||||||
android:textSize="14dip"/>
|
style="@style/DialogButton"/>
|
||||||
|
<!-- right spacer -->
|
||||||
|
<LinearLayout style="@style/DialogButtonSpacer"/>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|||||||
@@ -50,7 +50,9 @@ limitations under the License.
|
|||||||
android:singleLine="true"
|
android:singleLine="true"
|
||||||
android:autoText="true"
|
android:autoText="true"
|
||||||
android:capitalize="words"
|
android:capitalize="words"
|
||||||
android:selectAllOnFocus="true"/>
|
android:selectAllOnFocus="true"
|
||||||
|
android:hint="@string/waypointdetails_name_hint"
|
||||||
|
android:imeOptions="actionNext"/>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
<LinearLayout android:id="@+id/waypointdetails_description_layout"
|
<LinearLayout android:id="@+id/waypointdetails_description_layout"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
@@ -65,7 +67,9 @@ limitations under the License.
|
|||||||
<AutoCompleteTextView android:id="@+id/waypointdetails_category"
|
<AutoCompleteTextView android:id="@+id/waypointdetails_category"
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:singleLine="true"/>
|
android:singleLine="true"
|
||||||
|
android:hint="@string/waypointdetails_category_hint"
|
||||||
|
android:imeOptions="actionNext"/>
|
||||||
<TextView android:text="@string/waypointdetails_description"
|
<TextView android:text="@string/waypointdetails_description"
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="wrap_content"/>
|
android:layout_height="wrap_content"/>
|
||||||
@@ -79,7 +83,9 @@ limitations under the License.
|
|||||||
android:minLines="5"
|
android:minLines="5"
|
||||||
android:maxLines="50"
|
android:maxLines="50"
|
||||||
android:gravity="top"
|
android:gravity="top"
|
||||||
android:layout_weight="1"/>
|
android:layout_weight="1"
|
||||||
|
android:hint="@string/waypointdetails_description_hint"
|
||||||
|
android:imeOptions="actionDone"/>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<TableLayout android:id="@+id/waypoint_stats"
|
<TableLayout android:id="@+id/waypoint_stats"
|
||||||
|
|||||||
@@ -152,14 +152,20 @@ limitations under the License.
|
|||||||
<!-- MyTracks Details -->
|
<!-- MyTracks Details -->
|
||||||
<string name="trackdetails_title">Detalls de la ruta</string>
|
<string name="trackdetails_title">Detalls de la ruta</string>
|
||||||
<string name="trackdetails_name">Nom de la ruta</string>
|
<string name="trackdetails_name">Nom de la ruta</string>
|
||||||
|
<string name="trackdetails_name_hint">Nom de la ruta</string>
|
||||||
<string name="trackdetails_description">Descripció de la ruta</string>
|
<string name="trackdetails_description">Descripció de la ruta</string>
|
||||||
|
<string name="trackdetails_description_hint">Descripció de la ruta</string>
|
||||||
<string name="trackdetails_category">Tipus d\'activitat (p.e. senderisme, bicicleta, còrrer, escalada...)</string>
|
<string name="trackdetails_category">Tipus d\'activitat (p.e. senderisme, bicicleta, còrrer, escalada...)</string>
|
||||||
|
<string name="trackdetails_category_hint">Tipus d\'activitat</string>
|
||||||
|
|
||||||
<!-- MyTracks Waypoint Details -->
|
<!-- MyTracks Waypoint Details -->
|
||||||
<string name="waypointdetails_title">Detalls del marcador</string>
|
<string name="waypointdetails_title">Detalls del marcador</string>
|
||||||
<string name="waypointdetails_name">Nom del marcador</string>
|
<string name="waypointdetails_name">Nom del marcador</string>
|
||||||
|
<string name="waypointdetails_name_hint">Nom del marcador</string>
|
||||||
<string name="waypointdetails_description">Descripció del marcador</string>
|
<string name="waypointdetails_description">Descripció del marcador</string>
|
||||||
|
<string name="waypointdetails_description_hint">Descripció del marcador</string>
|
||||||
<string name="waypointdetails_category">Tipus de marcador (e.g. edifici, sot, vista...)</string>
|
<string name="waypointdetails_category">Tipus de marcador (e.g. edifici, sot, vista...)</string>
|
||||||
|
<string name="waypointdetails_category_hint">Tipus de marcador</string>
|
||||||
|
|
||||||
<!-- MyTracks Settings -->
|
<!-- MyTracks Settings -->
|
||||||
<string name="mytracks_settings">Paràmetres de My Tracks</string>
|
<string name="mytracks_settings">Paràmetres de My Tracks</string>
|
||||||
|
|||||||
@@ -154,14 +154,20 @@ limitations under the License.
|
|||||||
<!-- MyTracks Details -->
|
<!-- MyTracks Details -->
|
||||||
<string name="trackdetails_title">Trackdetails</string>
|
<string name="trackdetails_title">Trackdetails</string>
|
||||||
<string name="trackdetails_name">Name</string>
|
<string name="trackdetails_name">Name</string>
|
||||||
|
<string name="trackdetails_name_hint">Name</string>
|
||||||
<string name="trackdetails_description">Beschreibung</string>
|
<string name="trackdetails_description">Beschreibung</string>
|
||||||
|
<string name="trackdetails_description_hint">Beschreibung</string>
|
||||||
<string name="trackdetails_category">Aktivität (z. B. Wandern, Fahrradfahren, Laufen, Klettern…)</string>
|
<string name="trackdetails_category">Aktivität (z. B. Wandern, Fahrradfahren, Laufen, Klettern…)</string>
|
||||||
|
<string name="trackdetails_category_hint">Aktivität</string>
|
||||||
|
|
||||||
<!-- MyTracks Waypoint Details -->
|
<!-- MyTracks Waypoint Details -->
|
||||||
<string name="waypointdetails_title">Wegpunktdetails</string>
|
<string name="waypointdetails_title">Wegpunktdetails</string>
|
||||||
<string name="waypointdetails_name">Wegpunktname</string>
|
<string name="waypointdetails_name">Wegpunktname</string>
|
||||||
|
<string name="waypointdetails_name_hint">Wegpunktname</string>
|
||||||
<string name="waypointdetails_description">Wegpunktbeschreibung</string>
|
<string name="waypointdetails_description">Wegpunktbeschreibung</string>
|
||||||
|
<string name="waypointdetails_description_hint">Wegpunktbeschreibung</string>
|
||||||
<string name="waypointdetails_category">Art des Wegpunktes (z. B. Gebäude, Schlagloch, Sehenswürdigkeit…)</string>
|
<string name="waypointdetails_category">Art des Wegpunktes (z. B. Gebäude, Schlagloch, Sehenswürdigkeit…)</string>
|
||||||
|
<string name="waypointdetails_category_hint">Art des Wegpunktes</string>
|
||||||
|
|
||||||
<!-- MyTracks Settings -->
|
<!-- MyTracks Settings -->
|
||||||
<string name="mytracks_settings">Einstellungen für My Tracks</string>
|
<string name="mytracks_settings">Einstellungen für My Tracks</string>
|
||||||
|
|||||||
@@ -138,14 +138,20 @@ limitations under the License.
|
|||||||
<!-- MyTracks Details -->
|
<!-- MyTracks Details -->
|
||||||
<string name="trackdetails_title">Detalles del recorrido</string>
|
<string name="trackdetails_title">Detalles del recorrido</string>
|
||||||
<string name="trackdetails_name">Nombre del recorrido</string>
|
<string name="trackdetails_name">Nombre del recorrido</string>
|
||||||
|
<string name="trackdetails_name_hint">Nombre del recorrido</string>
|
||||||
<string name="trackdetails_description">Descripción del recorrido</string>
|
<string name="trackdetails_description">Descripción del recorrido</string>
|
||||||
|
<string name="trackdetails_description_hint">Descripción del recorrido</string>
|
||||||
<string name="trackdetails_category">Tipo de actividad (por ejemplo, ciclismo, alpinismo...)</string>
|
<string name="trackdetails_category">Tipo de actividad (por ejemplo, ciclismo, alpinismo...)</string>
|
||||||
|
<string name="trackdetails_category_hint">Tipo de actividad</string>
|
||||||
|
|
||||||
<!-- MyTracks Waypoint Details -->
|
<!-- MyTracks Waypoint Details -->
|
||||||
<string name="waypointdetails_title">Detalles de señal</string>
|
<string name="waypointdetails_title">Detalles de señal</string>
|
||||||
<string name="waypointdetails_name">Nombre de señal</string>
|
<string name="waypointdetails_name">Nombre de señal</string>
|
||||||
|
<string name="waypointdetails_name_hint">Nombre de señal</string>
|
||||||
<string name="waypointdetails_description">Descripción de señal</string>
|
<string name="waypointdetails_description">Descripción de señal</string>
|
||||||
|
<string name="waypointdetails_description_hint">Descripción de señal</string>
|
||||||
<string name="waypointdetails_category">Tipo de señal (por ejemplo, edificio, bache, atracción...)</string>
|
<string name="waypointdetails_category">Tipo de señal (por ejemplo, edificio, bache, atracción...)</string>
|
||||||
|
<string name="waypointdetails_category_hint">Tipo de señal</string>
|
||||||
|
|
||||||
<!-- MyTracks Settings -->
|
<!-- MyTracks Settings -->
|
||||||
<string name="mytracks_settings">Configuraciones de My Tracks</string>
|
<string name="mytracks_settings">Configuraciones de My Tracks</string>
|
||||||
|
|||||||
@@ -183,14 +183,20 @@ limitations under the License.
|
|||||||
<!-- MyTracks Details -->
|
<!-- MyTracks Details -->
|
||||||
<string name="trackdetails_title">Reitin tiedot</string>
|
<string name="trackdetails_title">Reitin tiedot</string>
|
||||||
<string name="trackdetails_name">Reitin nimi</string>
|
<string name="trackdetails_name">Reitin nimi</string>
|
||||||
|
<string name="trackdetails_name_hint">Reitin nimi</string>
|
||||||
<string name="trackdetails_description">Reitin kuvaus</string>
|
<string name="trackdetails_description">Reitin kuvaus</string>
|
||||||
|
<string name="trackdetails_description_hint">Reitin kuvaus</string>
|
||||||
<string name="trackdetails_category">Liikunnan muoto (esim. hölkkä, pyöräily, juoksu...)</string>
|
<string name="trackdetails_category">Liikunnan muoto (esim. hölkkä, pyöräily, juoksu...)</string>
|
||||||
|
<string name="trackdetails_category_hint">Liikunnan muoto</string>
|
||||||
|
|
||||||
<!-- MyTracks Waypoint Details -->
|
<!-- MyTracks Waypoint Details -->
|
||||||
<string name="waypointdetails_title">Merkinnän tiedot</string>
|
<string name="waypointdetails_title">Merkinnän tiedot</string>
|
||||||
<string name="waypointdetails_name">Merkinnän nimi</string>
|
<string name="waypointdetails_name">Merkinnän nimi</string>
|
||||||
|
<string name="waypointdetails_name_hint">Merkinnän nimi</string>
|
||||||
<string name="waypointdetails_description">Merkinnän kuvaus</string>
|
<string name="waypointdetails_description">Merkinnän kuvaus</string>
|
||||||
|
<string name="waypointdetails_description_hint">Merkinnän kuvaus</string>
|
||||||
<string name="waypointdetails_category">Merkinnän tyyppi (esim. rakennus, kuoppa, nähtävyys...)</string>
|
<string name="waypointdetails_category">Merkinnän tyyppi (esim. rakennus, kuoppa, nähtävyys...)</string>
|
||||||
|
<string name="waypointdetails_category_hint">Merkinnän tyyppi</string>
|
||||||
|
|
||||||
<!-- MyTracks Settings -->
|
<!-- MyTracks Settings -->
|
||||||
<string name="mytracks_settings">My Tracks Asetukset</string>
|
<string name="mytracks_settings">My Tracks Asetukset</string>
|
||||||
|
|||||||
@@ -144,14 +144,20 @@ limitations under the License.
|
|||||||
<!-- MyTracks Details -->
|
<!-- MyTracks Details -->
|
||||||
<string name="trackdetails_title">Détails parcours</string>
|
<string name="trackdetails_title">Détails parcours</string>
|
||||||
<string name="trackdetails_name">Nom du parcours</string>
|
<string name="trackdetails_name">Nom du parcours</string>
|
||||||
|
<string name="trackdetails_name_hint">Nom du parcours</string>
|
||||||
<string name="trackdetails_description">Description du parcours</string>
|
<string name="trackdetails_description">Description du parcours</string>
|
||||||
|
<string name="trackdetails_description_hint">Description du parcours</string>
|
||||||
<string name="trackdetails_category">Type d\'activité (randonnée, cyclisme, jogging, escalade...)</string>
|
<string name="trackdetails_category">Type d\'activité (randonnée, cyclisme, jogging, escalade...)</string>
|
||||||
|
<string name="trackdetails_category_hint">Type d\'activité</string>
|
||||||
|
|
||||||
<!-- MyTracks Waypoint Details -->
|
<!-- MyTracks Waypoint Details -->
|
||||||
<string name="waypointdetails_title">Details balise</string>
|
<string name="waypointdetails_title">Details balise</string>
|
||||||
<string name="waypointdetails_name">Nom de la balise</string>
|
<string name="waypointdetails_name">Nom de la balise</string>
|
||||||
|
<string name="waypointdetails_name_hint">Nom de la balise</string>
|
||||||
<string name="waypointdetails_description">Description balise</string>
|
<string name="waypointdetails_description">Description balise</string>
|
||||||
|
<string name="waypointdetails_description_hint">Description balise</string>
|
||||||
<string name="waypointdetails_category">Nom de balise (par ex.: immeuble, boutique, point de vue...)</string>
|
<string name="waypointdetails_category">Nom de balise (par ex.: immeuble, boutique, point de vue...)</string>
|
||||||
|
<string name="waypointdetails_category_hint">Nom de balise</string>
|
||||||
|
|
||||||
<!-- MyTracks Settings -->
|
<!-- MyTracks Settings -->
|
||||||
<string name="mytracks_settings">Paramètres My Tracks</string>
|
<string name="mytracks_settings">Paramètres My Tracks</string>
|
||||||
|
|||||||
@@ -147,14 +147,20 @@ limitations under the License.
|
|||||||
<!-- MyTracks Details -->
|
<!-- MyTracks Details -->
|
||||||
<string name="trackdetails_title">Dettagli del percorso</string>
|
<string name="trackdetails_title">Dettagli del percorso</string>
|
||||||
<string name="trackdetails_name">Nome del percorso</string>
|
<string name="trackdetails_name">Nome del percorso</string>
|
||||||
|
<string name="trackdetails_name_hint">Nome del percorso</string>
|
||||||
<string name="trackdetails_description">Descrizione del percorso</string>
|
<string name="trackdetails_description">Descrizione del percorso</string>
|
||||||
|
<string name="trackdetails_description_hint">Descrizione del percorso</string>
|
||||||
<string name="trackdetails_category">Tipo di attività (ad es. escursionismo, ciclismo, corsa, arrampicata...)</string>
|
<string name="trackdetails_category">Tipo di attività (ad es. escursionismo, ciclismo, corsa, arrampicata...)</string>
|
||||||
|
<string name="trackdetails_category_hint">Tipo di attività</string>
|
||||||
|
|
||||||
<!-- MyTracks Waypoint Details -->
|
<!-- MyTracks Waypoint Details -->
|
||||||
<string name="waypointdetails_title">Dettagli sul segnaposto</string>
|
<string name="waypointdetails_title">Dettagli sul segnaposto</string>
|
||||||
<string name="waypointdetails_name">Nome del segnaposto</string>
|
<string name="waypointdetails_name">Nome del segnaposto</string>
|
||||||
|
<string name="waypointdetails_name_hint">Nome del segnaposto</string>
|
||||||
<string name="waypointdetails_description">Descrizione del segnaposto</string>
|
<string name="waypointdetails_description">Descrizione del segnaposto</string>
|
||||||
|
<string name="waypointdetails_description_hint">Descrizione del segnaposto</string>
|
||||||
<string name="waypointdetails_category">Tipo di segnaposto (ad es. edificio, buca, vista...)</string>
|
<string name="waypointdetails_category">Tipo di segnaposto (ad es. edificio, buca, vista...)</string>
|
||||||
|
<string name="waypointdetails_category_hint">Tipo di segnaposto</string>
|
||||||
|
|
||||||
<!-- MyTracks Settings -->
|
<!-- MyTracks Settings -->
|
||||||
<string name="mytracks_settings">Impostazioni di My Tracks</string>
|
<string name="mytracks_settings">Impostazioni di My Tracks</string>
|
||||||
|
|||||||
@@ -176,14 +176,20 @@ limitations under the License.
|
|||||||
<!-- MyTracks Details -->
|
<!-- MyTracks Details -->
|
||||||
<string name="trackdetails_title">トラック詳細</string>
|
<string name="trackdetails_title">トラック詳細</string>
|
||||||
<string name="trackdetails_name">トラック名</string>
|
<string name="trackdetails_name">トラック名</string>
|
||||||
|
<string name="trackdetails_name_hint">トラック名</string>
|
||||||
<string name="trackdetails_description">トラック説明</string>
|
<string name="trackdetails_description">トラック説明</string>
|
||||||
|
<string name="trackdetails_description_hint">トラック説明</string>
|
||||||
<string name="trackdetails_category">活動タイプ(ハイキング, サイクリング、ランニング、登山...)</string>
|
<string name="trackdetails_category">活動タイプ(ハイキング, サイクリング、ランニング、登山...)</string>
|
||||||
|
<string name="trackdetails_category_hint">活動タイプ</string>
|
||||||
|
|
||||||
<!-- MyTracks Waypoint Details -->
|
<!-- MyTracks Waypoint Details -->
|
||||||
<string name="waypointdetails_title">マーカー詳細</string>
|
<string name="waypointdetails_title">マーカー詳細</string>
|
||||||
<string name="waypointdetails_name">マーカー名</string>
|
<string name="waypointdetails_name">マーカー名</string>
|
||||||
|
<string name="waypointdetails_name_hint">マーカー名</string>
|
||||||
<string name="waypointdetails_description">マーカー説明</string>
|
<string name="waypointdetails_description">マーカー説明</string>
|
||||||
|
<string name="waypointdetails_description_hint">マーカー説明</string>
|
||||||
<string name="waypointdetails_category">マーカータイプ(建物、洞穴、名所...)</string>
|
<string name="waypointdetails_category">マーカータイプ(建物、洞穴、名所...)</string>
|
||||||
|
<string name="waypointdetails_category_hint">マーカータイプ</string>
|
||||||
|
|
||||||
<!-- MyTracks Settings -->
|
<!-- MyTracks Settings -->
|
||||||
<string name="mytracks_settings">My Tracks設定</string>
|
<string name="mytracks_settings">My Tracks設定</string>
|
||||||
|
|||||||
@@ -149,14 +149,20 @@ limitations under the License.
|
|||||||
<!-- MyTracks Details -->
|
<!-- MyTracks Details -->
|
||||||
<string name="trackdetails_title">Szczegóły trasy</string>
|
<string name="trackdetails_title">Szczegóły trasy</string>
|
||||||
<string name="trackdetails_name">Nazwa trasy</string>
|
<string name="trackdetails_name">Nazwa trasy</string>
|
||||||
|
<string name="trackdetails_name_hint">Nazwa trasy</string>
|
||||||
<string name="trackdetails_description">Opis trasy</string>
|
<string name="trackdetails_description">Opis trasy</string>
|
||||||
|
<string name="trackdetails_description_hint">Opis trasy</string>
|
||||||
<string name="trackdetails_category">Typ aktywności (np. wspinanie, jazda rowerem, bieganie...)</string>
|
<string name="trackdetails_category">Typ aktywności (np. wspinanie, jazda rowerem, bieganie...)</string>
|
||||||
|
<string name="trackdetails_category_hint">Typ aktywności</string>
|
||||||
|
|
||||||
<!-- MyTracks Waypoint Details -->
|
<!-- MyTracks Waypoint Details -->
|
||||||
<string name="waypointdetails_title">Szczegóły znacznika</string>
|
<string name="waypointdetails_title">Szczegóły znacznika</string>
|
||||||
<string name="waypointdetails_name">Nazwa znacznika</string>
|
<string name="waypointdetails_name">Nazwa znacznika</string>
|
||||||
|
<string name="waypointdetails_name_hint">Nazwa znacznika</string>
|
||||||
<string name="waypointdetails_description">Opis znacznika</string>
|
<string name="waypointdetails_description">Opis znacznika</string>
|
||||||
|
<string name="waypointdetails_description_hint">Opis znacznika</string>
|
||||||
<string name="waypointdetails_category">Typ znacznika (np. budynek, jaskinia, punkt widokowy...)</string>
|
<string name="waypointdetails_category">Typ znacznika (np. budynek, jaskinia, punkt widokowy...)</string>
|
||||||
|
<string name="waypointdetails_category_hint">Typ znacznika</string>
|
||||||
|
|
||||||
<!-- MyTracks Settings -->
|
<!-- MyTracks Settings -->
|
||||||
<string name="mytracks_settings">Ustawienia My Tracks</string>
|
<string name="mytracks_settings">Ustawienia My Tracks</string>
|
||||||
|
|||||||
@@ -144,14 +144,20 @@ limitations under the License.
|
|||||||
<!-- MyTracks Details -->
|
<!-- MyTracks Details -->
|
||||||
<string name="trackdetails_title">Detalhes do Caminho</string>
|
<string name="trackdetails_title">Detalhes do Caminho</string>
|
||||||
<string name="trackdetails_name">Nome do Caminho</string>
|
<string name="trackdetails_name">Nome do Caminho</string>
|
||||||
|
<string name="trackdetails_name_hint">Nome do Caminho</string>
|
||||||
<string name="trackdetails_description">Descrição do Caminho</string>
|
<string name="trackdetails_description">Descrição do Caminho</string>
|
||||||
|
<string name="trackdetails_description_hint">Descrição do Caminho</string>
|
||||||
<string name="trackdetails_category">Tipo de Atividade (por ex. caminhada, ciclismo, escalada...)</string>
|
<string name="trackdetails_category">Tipo de Atividade (por ex. caminhada, ciclismo, escalada...)</string>
|
||||||
|
<string name="trackdetails_category_hint">Tipo de Atividade</string>
|
||||||
|
|
||||||
<!-- MyTracks Waypoint Details -->
|
<!-- MyTracks Waypoint Details -->
|
||||||
<string name="waypointdetails_title">Detalhes do Marcador</string>
|
<string name="waypointdetails_title">Detalhes do Marcador</string>
|
||||||
<string name="waypointdetails_name">Nome do Marcador</string>
|
<string name="waypointdetails_name">Nome do Marcador</string>
|
||||||
|
<string name="waypointdetails_name_hint">Nome do Marcador</string>
|
||||||
<string name="waypointdetails_description">Descrição do Marcador</string>
|
<string name="waypointdetails_description">Descrição do Marcador</string>
|
||||||
|
<string name="waypointdetails_description_hint">Descrição do Marcador</string>
|
||||||
<string name="waypointdetails_category">Tipo do Marcador (por ex. Prédio, Mirante, Cachoeira...)</string>
|
<string name="waypointdetails_category">Tipo do Marcador (por ex. Prédio, Mirante, Cachoeira...)</string>
|
||||||
|
<string name="waypointdetails_category_hint">Tipo do Marcador</string>
|
||||||
|
|
||||||
<!-- MyTracks Settings -->
|
<!-- MyTracks Settings -->
|
||||||
<string name="mytracks_settings">Configurações do My Tracks</string>
|
<string name="mytracks_settings">Configurações do My Tracks</string>
|
||||||
|
|||||||
@@ -179,14 +179,20 @@ limitations under the License.
|
|||||||
<!-- MyTracks Details -->
|
<!-- MyTracks Details -->
|
||||||
<string name="trackdetails_title">Трек детали</string>
|
<string name="trackdetails_title">Трек детали</string>
|
||||||
<string name="trackdetails_name">Название трека</string>
|
<string name="trackdetails_name">Название трека</string>
|
||||||
|
<string name="trackdetails_name_hint">Название трека</string>
|
||||||
<string name="trackdetails_description">Описание трека</string>
|
<string name="trackdetails_description">Описание трека</string>
|
||||||
|
<string name="trackdetails_description_hint">Описание трека</string>
|
||||||
<string name="trackdetails_category">Тип деятельности (например: пешая прогулка, велосипедная прогулка, бег, восхождение...)</string>
|
<string name="trackdetails_category">Тип деятельности (например: пешая прогулка, велосипедная прогулка, бег, восхождение...)</string>
|
||||||
|
<string name="trackdetails_category_hint">Тип деятельности</string>
|
||||||
|
|
||||||
<!-- MyTracks Waypoint Details -->
|
<!-- MyTracks Waypoint Details -->
|
||||||
<string name="waypointdetails_title">Маркер детали</string>
|
<string name="waypointdetails_title">Маркер детали</string>
|
||||||
<string name="waypointdetails_name">Имя маркера</string>
|
<string name="waypointdetails_name">Имя маркера</string>
|
||||||
|
<string name="waypointdetails_name_hint">Имя маркера</string>
|
||||||
<string name="waypointdetails_description">Описание маркера</string>
|
<string name="waypointdetails_description">Описание маркера</string>
|
||||||
|
<string name="waypointdetails_description_hint">Описание маркера</string>
|
||||||
<string name="waypointdetails_category">Тип маркера (например: здание, выбоина, достопримечательность...)</string>
|
<string name="waypointdetails_category">Тип маркера (например: здание, выбоина, достопримечательность...)</string>
|
||||||
|
<string name="waypointdetails_category_hint">Тип маркера</string>
|
||||||
|
|
||||||
<!-- MyTracks Settings -->
|
<!-- MyTracks Settings -->
|
||||||
<string name="mytracks_settings">Настройки My Tracks</string>
|
<string name="mytracks_settings">Настройки My Tracks</string>
|
||||||
|
|||||||
@@ -149,14 +149,20 @@ limitations under the License.
|
|||||||
<!-- MyTracks Details -->
|
<!-- MyTracks Details -->
|
||||||
<string name="trackdetails_title">Spårdetaljer</string>
|
<string name="trackdetails_title">Spårdetaljer</string>
|
||||||
<string name="trackdetails_name">Spårnamn</string>
|
<string name="trackdetails_name">Spårnamn</string>
|
||||||
|
<string name="trackdetails_name_hint">Spårnamn</string>
|
||||||
<string name="trackdetails_description">Spårbeskrivning</string>
|
<string name="trackdetails_description">Spårbeskrivning</string>
|
||||||
|
<string name="trackdetails_description_hint">Spårbeskrivning</string>
|
||||||
<string name="trackdetails_category">Aktivitetstyp (t ex vandring, cyckling, löpning, klättring...)</string>
|
<string name="trackdetails_category">Aktivitetstyp (t ex vandring, cyckling, löpning, klättring...)</string>
|
||||||
|
<string name="trackdetails_category_hint">Aktivitetstyp</string>
|
||||||
|
|
||||||
<!-- MyTracks Waypoint Details -->
|
<!-- MyTracks Waypoint Details -->
|
||||||
<string name="waypointdetails_title">Markördetaljer</string>
|
<string name="waypointdetails_title">Markördetaljer</string>
|
||||||
<string name="waypointdetails_name">Markörnamn</string>
|
<string name="waypointdetails_name">Markörnamn</string>
|
||||||
|
<string name="waypointdetails_name_hint">Markörnamn</string>
|
||||||
<string name="waypointdetails_description">Markörbeskrivning</string>
|
<string name="waypointdetails_description">Markörbeskrivning</string>
|
||||||
|
<string name="waypointdetails_description_hint">Markörbeskrivning</string>
|
||||||
<string name="waypointdetails_category">Markörtyp (e.g. byggnad, grop, sevärdhet...)</string>
|
<string name="waypointdetails_category">Markörtyp (e.g. byggnad, grop, sevärdhet...)</string>
|
||||||
|
<string name="waypointdetails_category_hint">Markörtyp</string>
|
||||||
|
|
||||||
<!-- MyTracks Settings -->
|
<!-- MyTracks Settings -->
|
||||||
<string name="mytracks_settings">My Tracks inställningar</string>
|
<string name="mytracks_settings">My Tracks inställningar</string>
|
||||||
|
|||||||
@@ -180,14 +180,20 @@ limitations under the License.
|
|||||||
<!-- MyTracks Details -->
|
<!-- MyTracks Details -->
|
||||||
<string name="trackdetails_title">轨迹详细信息</string>
|
<string name="trackdetails_title">轨迹详细信息</string>
|
||||||
<string name="trackdetails_name">轨迹名称</string>
|
<string name="trackdetails_name">轨迹名称</string>
|
||||||
|
<string name="trackdetails_name_hint">轨迹名称</string>
|
||||||
<string name="trackdetails_description">轨迹描述</string>
|
<string name="trackdetails_description">轨迹描述</string>
|
||||||
|
<string name="trackdetails_description_hint">轨迹描述</string>
|
||||||
<string name="trackdetails_category">活动类型 (例如: 徒步, 骑行, 跑步, 攀岩...)</string>
|
<string name="trackdetails_category">活动类型 (例如: 徒步, 骑行, 跑步, 攀岩...)</string>
|
||||||
|
<string name="trackdetails_category_hint">活动类型</string>
|
||||||
|
|
||||||
<!-- MyTracks Waypoint Details -->
|
<!-- MyTracks Waypoint Details -->
|
||||||
<string name="waypointdetails_title">标记详细信息</string>
|
<string name="waypointdetails_title">标记详细信息</string>
|
||||||
<string name="waypointdetails_name">标记名称</string>
|
<string name="waypointdetails_name">标记名称</string>
|
||||||
|
<string name="waypointdetails_name_hint">标记名称</string>
|
||||||
<string name="waypointdetails_description">标记描述</string>
|
<string name="waypointdetails_description">标记描述</string>
|
||||||
|
<string name="waypointdetails_description_hint">标记描述</string>
|
||||||
<string name="waypointdetails_category">标记类型 (例如: 建筑, 陷坑, 景点...)</string>
|
<string name="waypointdetails_category">标记类型 (例如: 建筑, 陷坑, 景点...)</string>
|
||||||
|
<string name="waypointdetails_category_hint">标记类型</string>
|
||||||
|
|
||||||
<!-- MyTracks Settings -->
|
<!-- MyTracks Settings -->
|
||||||
<string name="mytracks_settings">My Tracks 设置</string>
|
<string name="mytracks_settings">My Tracks 设置</string>
|
||||||
|
|||||||
@@ -118,4 +118,16 @@ limitations under the License.
|
|||||||
<item>@string/ant_sensor_type</item>
|
<item>@string/ant_sensor_type</item>
|
||||||
<item>@string/srm_ant_bridge_sensor_type</item>
|
<item>@string/srm_ant_bridge_sensor_type</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
|
<string-array name="track_color_mode_options">
|
||||||
|
<item>@string/track_color_mode_none</item>
|
||||||
|
<item>@string/track_color_mode_fixed</item>
|
||||||
|
<item>@string/track_color_mode_dynamic</item>
|
||||||
|
</string-array>
|
||||||
|
|
||||||
|
<string-array name="track_color_mode_values">
|
||||||
|
<item>@string/none</item>
|
||||||
|
<item>@string/track_color_mode_fixed</item>
|
||||||
|
<item>@string/track_color_mode_dynamic</item>
|
||||||
|
</string-array>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -51,4 +51,14 @@ limitations under the License.
|
|||||||
<!-- AppWidget colors -->
|
<!-- AppWidget colors -->
|
||||||
<color name="appwidget_text">#EDEDED</color>
|
<color name="appwidget_text">#EDEDED</color>
|
||||||
<color name="appwidget_hr">#99999999</color>
|
<color name="appwidget_hr">#99999999</color>
|
||||||
|
|
||||||
|
<!-- Colors for dynamic track drawing -->
|
||||||
|
<!-- Green -->
|
||||||
|
<color name="slow_path">#F774DF00</color>
|
||||||
|
|
||||||
|
<!-- Blue -->
|
||||||
|
<color name="normal_path">#F75858FA</color>
|
||||||
|
|
||||||
|
<!-- Red -->
|
||||||
|
<color name="fast_path">#F7DF0101</color>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -49,4 +49,12 @@ limitations under the License.
|
|||||||
|
|
||||||
<!-- Intent actions -->
|
<!-- Intent actions -->
|
||||||
<string name="save_intent_action">android.intent.action.SAVE</string>
|
<string name="save_intent_action">android.intent.action.SAVE</string>
|
||||||
|
<string name="open_settings_screen">android.intent.action.settings.OPEN</string>
|
||||||
|
<string name="start_new_track_action">com.google.android.apps.mytracks.START_NEW_TRACK</string>
|
||||||
|
<string name="end_current_track_action">com.google.android.apps.mytracks.END_CURRENT_TRACK
|
||||||
|
</string>
|
||||||
|
|
||||||
|
<!-- Permissions -->
|
||||||
|
<!-- Permission for MyTracks notifications. -->
|
||||||
|
<string name="mytracks_notifications_permission">com.google.android.apps.mytracks.MYTRACKS_NOTIFICATIONS</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -15,7 +15,8 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
-->
|
-->
|
||||||
<resources>
|
<resources>
|
||||||
<!-- Keys for application preferences - DO NOT TRANSLATE -->
|
<!-- Keys for application preferences. Sorted alphabetically. - DO NOT TRANSLATE -->
|
||||||
|
<string name="allow_access_key">allowAccess</string>
|
||||||
<string name="announcement_frequency_key">announcementFrequency</string>
|
<string name="announcement_frequency_key">announcementFrequency</string>
|
||||||
<string name="ant_heart_rate_sensor_id_key">antHeartRateSensorId</string>
|
<string name="ant_heart_rate_sensor_id_key">antHeartRateSensorId</string>
|
||||||
<string name="ant_power_sensor_id_key">antPowerSensorId</string>
|
<string name="ant_power_sensor_id_key">antPowerSensorId</string>
|
||||||
@@ -35,22 +36,34 @@ limitations under the License.
|
|||||||
<string name="report_speed_key">reportSpeed</string>
|
<string name="report_speed_key">reportSpeed</string>
|
||||||
<string name="send_stats_and_points_key">sendStatsAndPoints</string>
|
<string name="send_stats_and_points_key">sendStatsAndPoints</string>
|
||||||
<string name="send_to_docs_key">sendToDocs</string>
|
<string name="send_to_docs_key">sendToDocs</string>
|
||||||
<string name="send_to_my_maps_key">sendToMyMaps</string>
|
|
||||||
<string name="send_to_fusion_tables_key">sendToFusionTables</string>
|
<string name="send_to_fusion_tables_key">sendToFusionTables</string>
|
||||||
|
<string name="send_to_my_maps_key">sendToMyMaps</string>
|
||||||
<string name="sensor_type_key">sensorType</string>
|
<string name="sensor_type_key">sensorType</string>
|
||||||
<string name="share_url_only_key">shareUrlOnly</string>
|
<string name="share_url_only_key">shareUrlOnly</string>
|
||||||
<string name="split_frequency_key">splitFrequency</string>
|
<string name="split_frequency_key">splitFrequency</string>
|
||||||
<string name="timestamp_track_name_key">timestampTrackName</string>
|
<string name="timestamp_track_name_key">timestampTrackName</string>
|
||||||
|
<string name="track_color_mode_dynamic_speed_variation_key">trackColorModeDynamicVariation
|
||||||
|
</string>
|
||||||
|
<string name="track_color_mode_fixed_speed_medium_display_key">trackColorModeFixedMediumDisplay
|
||||||
|
</string>
|
||||||
|
<string name="track_color_mode_fixed_speed_medium_key">trackColorModeFixedMedium</string>
|
||||||
|
<string name="track_color_mode_fixed_speed_slow_display_key">trackColorModeFixedSlowDisplay
|
||||||
|
</string>
|
||||||
|
<string name="track_color_mode_fixed_speed_slow_key">trackColorModeFixedSlow</string>
|
||||||
|
<string name="track_color_mode_key">trackColorMode</string>
|
||||||
|
|
||||||
<!-- Preference keys which keep transient state (not user preferences) - DO NOT TRANSLATE -->
|
<!-- Preference keys which keep transient state (not user preferences). Sorted alphabetically.
|
||||||
|
- DO NOT TRANSLATE -->
|
||||||
<string name="auto_resume_track_current_retry_key">autoResumeTrackCurrentRetry</string>
|
<string name="auto_resume_track_current_retry_key">autoResumeTrackCurrentRetry</string>
|
||||||
<string name="recording_track_key">recordingTrack</string>
|
<string name="recording_track_key">recordingTrack</string>
|
||||||
<string name="selected_track_key">selectedTrack</string>
|
<string name="selected_track_key">selectedTrack</string>
|
||||||
|
|
||||||
<!-- Keys for non-persisted preferences - DO NOT TRANSLATE -->
|
<!-- Keys for non-persisted preferences. Sorted alphabetically. - DO NOT TRANSLATE -->
|
||||||
<string name="backup_to_sd_key">backupToSd</string>
|
|
||||||
<string name="restore_from_sd_key">restoreFromSd</string>
|
|
||||||
<string name="reset_key">resetToDefaults</string>
|
|
||||||
<string name="sensor_options_key">sensorOptions</string>
|
|
||||||
<string name="ant_options_key">antOptions</string>
|
<string name="ant_options_key">antOptions</string>
|
||||||
|
<string name="backup_to_sd_key">backupToSd</string>
|
||||||
|
<string name="display_settings_screen_key">displaySettingsScreen</string>
|
||||||
|
<string name="reset_key">resetToDefaults</string>
|
||||||
|
<string name="restore_from_sd_key">restoreFromSd</string>
|
||||||
|
<string name="sensor_options_key">sensorOptions</string>
|
||||||
|
<string name="track_color_mode_fixed_speed_options_key">trackColorModeFixedOptions</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -184,14 +184,20 @@ limitations under the License.
|
|||||||
<!-- MyTracks Details -->
|
<!-- MyTracks Details -->
|
||||||
<string name="trackdetails_title">Track Details</string>
|
<string name="trackdetails_title">Track Details</string>
|
||||||
<string name="trackdetails_name">Track Name</string>
|
<string name="trackdetails_name">Track Name</string>
|
||||||
|
<string name="trackdetails_name_hint">Track Name</string>
|
||||||
<string name="trackdetails_description">Track Description</string>
|
<string name="trackdetails_description">Track Description</string>
|
||||||
|
<string name="trackdetails_description_hint">Track Description</string>
|
||||||
<string name="trackdetails_category">Activity Type (e.g. hiking, cycling, running, climbing...)</string>
|
<string name="trackdetails_category">Activity Type (e.g. hiking, cycling, running, climbing...)</string>
|
||||||
|
<string name="trackdetails_category_hint">Activity Type</string>
|
||||||
|
|
||||||
<!-- MyTracks Waypoint Details -->
|
<!-- MyTracks Waypoint Details -->
|
||||||
<string name="waypointdetails_title">Marker Details</string>
|
<string name="waypointdetails_title">Marker Details</string>
|
||||||
<string name="waypointdetails_name">Marker Name</string>
|
<string name="waypointdetails_name">Marker Name</string>
|
||||||
|
<string name="waypointdetails_name_hint">Marker Name</string>
|
||||||
<string name="waypointdetails_description">Marker Description</string>
|
<string name="waypointdetails_description">Marker Description</string>
|
||||||
|
<string name="waypointdetails_description_hint">Marker Description</string>
|
||||||
<string name="waypointdetails_category">Marker Type (e.g. Building, Pothole, Sight...)</string>
|
<string name="waypointdetails_category">Marker Type (e.g. Building, Pothole, Sight...)</string>
|
||||||
|
<string name="waypointdetails_category_hint">Marker Type</string>
|
||||||
|
|
||||||
<!-- MyTracks Settings -->
|
<!-- MyTracks Settings -->
|
||||||
<string name="mytracks_settings">My Tracks Settings</string>
|
<string name="mytracks_settings">My Tracks Settings</string>
|
||||||
@@ -202,6 +208,15 @@ limitations under the License.
|
|||||||
<string name="settings_not_available_summary">Not available in your version of Android</string>
|
<string name="settings_not_available_summary">Not available in your version of Android</string>
|
||||||
<string name="settings_not_while_recording">Not available while recording a track</string>
|
<string name="settings_not_while_recording">Not available while recording a track</string>
|
||||||
|
|
||||||
|
<string name="settings_allow_access">Allow access</string>
|
||||||
|
<string name="settings_allow_access_summary_on">Other apps can read, write, start/stop recording
|
||||||
|
MyTracks data.</string>
|
||||||
|
<string name="settings_allow_access_summary_off">Other apps cannot read, write, start/stop
|
||||||
|
recording MyTracks data.</string>
|
||||||
|
<string name="settings_allow_access_dialog_message">Are you sure you want to allow other apps,
|
||||||
|
including future apps, to control and access MyTracks data? There will be no further
|
||||||
|
notification.</string>
|
||||||
|
|
||||||
<string name="settings_announcement_frequency">Announcement frequency</string>
|
<string name="settings_announcement_frequency">Announcement frequency</string>
|
||||||
<string name="settings_announcement_frequency_summary">Minimum time between two voice announcements</string>
|
<string name="settings_announcement_frequency_summary">Minimum time between two voice announcements</string>
|
||||||
|
|
||||||
@@ -262,6 +277,17 @@ limitations under the License.
|
|||||||
<string name="bluetooth_sensor_summary">The bluetooth sensor to connect to</string>
|
<string name="bluetooth_sensor_summary">The bluetooth sensor to connect to</string>
|
||||||
<string name="settings_modular_stats_display_title">Modular Stats Display</string>
|
<string name="settings_modular_stats_display_title">Modular Stats Display</string>
|
||||||
|
|
||||||
|
<string name="settings_track_color_mode">Track Color Mode</string>
|
||||||
|
<string name="settings_track_color_mode_summary">The way to color the track</string>
|
||||||
|
<string name="settings_track_color_mode_fixed">Fixed</string>
|
||||||
|
<string name="settings_track_color_mode_dynamic">Dynamic</string>
|
||||||
|
<string name="settings_track_color_mode_fixed_speed_slow">Fixed Speed Slow</string>
|
||||||
|
<string name="settings_track_color_mode_fixed_speed_slow_summary">Slow speed top value</string>
|
||||||
|
<string name="settings_track_color_mode_fixed_speed_medium">Fixed Speed Medium</string>
|
||||||
|
<string name="settings_track_color_mode_fixed_speed_medium_summary">Medium speed top value</string>
|
||||||
|
<string name="settings_track_color_mode_dynamic_speed_variation">Dynamic Speed Variation</string>
|
||||||
|
<string name="settings_track_color_mode_dynamic_speed_variation_summary">% Margin from average speed to consider medium speed</string>
|
||||||
|
|
||||||
<!-- Backups -->
|
<!-- Backups -->
|
||||||
<string name="settings_backup">Backup (BETA)</string>
|
<string name="settings_backup">Backup (BETA)</string>
|
||||||
<string name="settings_sd_backup">SD Card Backup</string>
|
<string name="settings_sd_backup">SD Card Backup</string>
|
||||||
@@ -477,6 +503,9 @@ limitations under the License.
|
|||||||
<string name="sensor_bluetooth_options_key">bluetoothSensorsEnabled</string>
|
<string name="sensor_bluetooth_options_key">bluetoothSensorsEnabled</string>
|
||||||
<string name="ant_options">ANT options</string>
|
<string name="ant_options">ANT options</string>
|
||||||
<string name="sensor_options">Sensor Options</string>
|
<string name="sensor_options">Sensor Options</string>
|
||||||
|
<string name="track_color_mode">Track Color Mode</string>
|
||||||
|
<string name="fixed_speed_options">Fixed Speed Options</string>
|
||||||
|
<string name="dynamic_speed_options">Dynamic Speed Options</string>
|
||||||
|
|
||||||
<!-- Bluetooth Sensor -->
|
<!-- Bluetooth Sensor -->
|
||||||
<string name="bluetooth_connected">Connected to %s</string>
|
<string name="bluetooth_connected">Connected to %s</string>
|
||||||
@@ -497,12 +526,19 @@ limitations under the License.
|
|||||||
<string name="sending">Sending</string>
|
<string name="sending">Sending</string>
|
||||||
|
|
||||||
<!-- Manifest description (not seen inside the app) -->
|
<!-- Manifest description (not seen inside the app) -->
|
||||||
<string name="notification_permission_label">receive track recording notifications</string>
|
<string name="notification_permission_label">receive MyTracks notifications</string>
|
||||||
<string name="read_tracks_permission_label">read recorded track data</string>
|
<string name="mytracks_notifications_permission_label">receive MyTracks notifications</string>
|
||||||
<string name="write_tracks_permission_label">write recorded track data, start/stop recording tracks</string>
|
<string name="read_tracks_permission_label">read MyTracks data</string>
|
||||||
<string name="notification_permission_description">Be notified when a track starts or stops being recorded.</string>
|
<string name="write_tracks_permission_label">write data to MyTracks and start/stop MyTracks
|
||||||
<string name="read_tracks_permission_description">Be able to read track data, such as points and waypoints.</string>
|
recording</string>
|
||||||
<string name="write_tracks_permission_description">Be able to write track data, such as starting recording or adding waypoints.</string>
|
<string name="notification_permission_description">Allows the application to receive notifications
|
||||||
|
when MyTracks starts or stops a recording.</string>
|
||||||
|
<string name="mytracks_notifications_permission_description">receive MyTracks notifications
|
||||||
|
</string>
|
||||||
|
<string name="read_tracks_permission_description">Allows the application to read MyTracks data.
|
||||||
|
</string>
|
||||||
|
<string name="write_tracks_permission_description">Allows the application to write data to
|
||||||
|
MyTracks and start/stop MyTracks recording.</string>
|
||||||
|
|
||||||
<!-- Sensor Type Options -->
|
<!-- Sensor Type Options -->
|
||||||
<string name="no_sensor_option">NONE</string>
|
<string name="no_sensor_option">NONE</string>
|
||||||
@@ -511,4 +547,8 @@ limitations under the License.
|
|||||||
<string name="polar_bt_sensor_option">Polar Bluetooth</string>
|
<string name="polar_bt_sensor_option">Polar Bluetooth</string>
|
||||||
<string name="zephyr_bt_sensor_option">Zephyr Bluetooth</string>
|
<string name="zephyr_bt_sensor_option">Zephyr Bluetooth</string>
|
||||||
|
|
||||||
|
<!-- Track Color Modes -->
|
||||||
|
<string name="track_color_mode_none">None</string>
|
||||||
|
<string name="track_color_mode_fixed">Fixed (BETA)</string>
|
||||||
|
<string name="track_color_mode_dynamic">Dynamic (BETA)</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -85,4 +85,22 @@ limitations under the License.
|
|||||||
<style name="WidgetText.Register">
|
<style name="WidgetText.Register">
|
||||||
<item name="android:width">160px</item>
|
<item name="android:width">160px</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<!-- The style for the buttons on the bottom of a dialog. -->
|
||||||
|
<style name="DialogButton">
|
||||||
|
<item name="android:layout_height">48dip</item>
|
||||||
|
<item name="android:layout_weight">1</item>
|
||||||
|
<item name="android:layout_width">0dip</item>
|
||||||
|
<item name="android:maxLines">2</item>
|
||||||
|
<item name="android:textSize">14dip</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<!-- The style for the spacer on the left and right of the dialog buttons. -->
|
||||||
|
<style name="DialogButtonSpacer">
|
||||||
|
<item name="android:layout_height">wrap_content</item>
|
||||||
|
<item name="android:layout_weight">0.25</item>
|
||||||
|
<item name="android:layout_width">0dip</item>
|
||||||
|
<item name="android:orientation">horizontal</item>
|
||||||
|
<item name="android:visibility">gone</item>
|
||||||
|
</style>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -18,7 +18,8 @@ limitations under the License.
|
|||||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
<!-- Display settings -->
|
<!-- Display settings -->
|
||||||
<PreferenceScreen android:title="@string/settings_display">
|
<PreferenceScreen android:title="@string/settings_display"
|
||||||
|
android:key="@string/display_settings_screen_key">
|
||||||
<CheckBoxPreference
|
<CheckBoxPreference
|
||||||
android:key="@string/metric_units_key"
|
android:key="@string/metric_units_key"
|
||||||
android:title="@string/settings_metric_units"
|
android:title="@string/settings_metric_units"
|
||||||
@@ -32,6 +33,58 @@ limitations under the License.
|
|||||||
android:summaryOn="@string/settings_report_speed_or_pace_summary_on"
|
android:summaryOn="@string/settings_report_speed_or_pace_summary_on"
|
||||||
android:summaryOff="@string/settings_report_speed_or_pace_summary_off"
|
android:summaryOff="@string/settings_report_speed_or_pace_summary_off"
|
||||||
android:defaultValue="true" />
|
android:defaultValue="true" />
|
||||||
|
|
||||||
|
<ListPreference android:key="@string/track_color_mode_key"
|
||||||
|
android:title="@string/settings_track_color_mode"
|
||||||
|
android:summary="@string/settings_track_color_mode_summary"
|
||||||
|
android:entries="@array/track_color_mode_options"
|
||||||
|
android:entryValues="@array/track_color_mode_values"
|
||||||
|
android:defaultValue="@string/none"/>
|
||||||
|
|
||||||
|
<PreferenceCategory android:title="@string/fixed_speed_options"
|
||||||
|
android:key="@string/track_color_mode_fixed_speed_options_key">
|
||||||
|
<EditTextPreference android:key="@string/track_color_mode_fixed_speed_slow_key"
|
||||||
|
android:title="@string/settings_track_color_mode_fixed_speed_slow"
|
||||||
|
android:summary="@string/settings_track_color_mode_fixed_speed_slow_summary"
|
||||||
|
android:defaultValue="9"
|
||||||
|
android:inputType="number"
|
||||||
|
android:maxLength="3">
|
||||||
|
</EditTextPreference>
|
||||||
|
|
||||||
|
<EditTextPreference android:key="@string/track_color_mode_fixed_speed_slow_display_key"
|
||||||
|
android:title="@string/settings_track_color_mode_fixed_speed_slow"
|
||||||
|
android:summary="@string/settings_track_color_mode_fixed_speed_slow_summary"
|
||||||
|
android:defaultValue="9"
|
||||||
|
android:inputType="number"
|
||||||
|
android:maxLength="3">
|
||||||
|
</EditTextPreference>
|
||||||
|
|
||||||
|
<EditTextPreference android:key="@string/track_color_mode_fixed_speed_medium_key"
|
||||||
|
android:title="@string/settings_track_color_mode_fixed_speed_medium"
|
||||||
|
android:summary="@string/settings_track_color_mode_fixed_speed_medium_summary"
|
||||||
|
android:defaultValue="15"
|
||||||
|
android:inputType="number"
|
||||||
|
android:maxLength="3">
|
||||||
|
</EditTextPreference>
|
||||||
|
|
||||||
|
<EditTextPreference android:key="@string/track_color_mode_fixed_speed_medium_display_key"
|
||||||
|
android:title="@string/settings_track_color_mode_fixed_speed_medium"
|
||||||
|
android:summary="@string/settings_track_color_mode_fixed_speed_medium_summary"
|
||||||
|
android:defaultValue="15"
|
||||||
|
android:inputType="number"
|
||||||
|
android:maxLength="3">
|
||||||
|
</EditTextPreference>
|
||||||
|
</PreferenceCategory>
|
||||||
|
|
||||||
|
<PreferenceCategory android:title="@string/dynamic_speed_options">
|
||||||
|
<EditTextPreference android:key="@string/track_color_mode_dynamic_speed_variation_key"
|
||||||
|
android:title="@string/settings_track_color_mode_dynamic_speed_variation"
|
||||||
|
android:summary="@string/settings_track_color_mode_dynamic_speed_variation_summary"
|
||||||
|
android:defaultValue="25"
|
||||||
|
android:inputType="number"
|
||||||
|
android:maxLength="2">
|
||||||
|
</EditTextPreference>
|
||||||
|
</PreferenceCategory>
|
||||||
</PreferenceScreen>
|
</PreferenceScreen>
|
||||||
|
|
||||||
<!-- Recording settings -->
|
<!-- Recording settings -->
|
||||||
@@ -156,6 +209,13 @@ limitations under the License.
|
|||||||
android:summaryOn="@string/settings_share_url_only_summary_on"
|
android:summaryOn="@string/settings_share_url_only_summary_on"
|
||||||
android:summaryOff="@string/settings_share_url_only_summary_off"
|
android:summaryOff="@string/settings_share_url_only_summary_off"
|
||||||
android:defaultValue="false" />
|
android:defaultValue="false" />
|
||||||
|
|
||||||
|
<CheckBoxPreference
|
||||||
|
android:key="@string/allow_access_key"
|
||||||
|
android:title="@string/settings_allow_access"
|
||||||
|
android:summaryOn="@string/settings_allow_access_summary_on"
|
||||||
|
android:summaryOff="@string/settings_allow_access_summary_off"
|
||||||
|
android:defaultValue="false" />
|
||||||
</PreferenceScreen>
|
</PreferenceScreen>
|
||||||
|
|
||||||
<!-- Backup settings -->
|
<!-- Backup settings -->
|
||||||
|
|||||||
@@ -20,11 +20,11 @@ import static com.google.android.apps.mytracks.Constants.TAG;
|
|||||||
import com.google.android.apps.mytracks.ChartView.Mode;
|
import com.google.android.apps.mytracks.ChartView.Mode;
|
||||||
import com.google.android.apps.mytracks.content.MyTracksLocation;
|
import com.google.android.apps.mytracks.content.MyTracksLocation;
|
||||||
import com.google.android.apps.mytracks.content.Sensor;
|
import com.google.android.apps.mytracks.content.Sensor;
|
||||||
import com.google.android.apps.mytracks.content.TrackDataHub;
|
|
||||||
import com.google.android.apps.mytracks.content.TrackDataListener;
|
|
||||||
import com.google.android.apps.mytracks.content.Sensor.SensorDataSet;
|
import com.google.android.apps.mytracks.content.Sensor.SensorDataSet;
|
||||||
import com.google.android.apps.mytracks.content.TrackDataHub.ListenerDataType;
|
|
||||||
import com.google.android.apps.mytracks.content.Track;
|
import com.google.android.apps.mytracks.content.Track;
|
||||||
|
import com.google.android.apps.mytracks.content.TrackDataHub;
|
||||||
|
import com.google.android.apps.mytracks.content.TrackDataHub.ListenerDataType;
|
||||||
|
import com.google.android.apps.mytracks.content.TrackDataListener;
|
||||||
import com.google.android.apps.mytracks.content.Waypoint;
|
import com.google.android.apps.mytracks.content.Waypoint;
|
||||||
import com.google.android.apps.mytracks.services.tasks.StatusAnnouncerFactory;
|
import com.google.android.apps.mytracks.services.tasks.StatusAnnouncerFactory;
|
||||||
import com.google.android.apps.mytracks.stats.DoubleBuffer;
|
import com.google.android.apps.mytracks.stats.DoubleBuffer;
|
||||||
@@ -148,7 +148,7 @@ public class ChartActivity extends Activity implements TrackDataListener {
|
|||||||
protected void onResume() {
|
protected void onResume() {
|
||||||
super.onResume();
|
super.onResume();
|
||||||
|
|
||||||
dataHub = TrackDataHub.getStartedInstance();
|
dataHub = ((MyTracksApplication) getApplication()).getTrackDataHub();
|
||||||
dataHub.registerTrackDataListener(this, EnumSet.of(
|
dataHub.registerTrackDataListener(this, EnumSet.of(
|
||||||
ListenerDataType.SELECTED_TRACK_CHANGED,
|
ListenerDataType.SELECTED_TRACK_CHANGED,
|
||||||
ListenerDataType.TRACK_UPDATES,
|
ListenerDataType.TRACK_UPDATES,
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import android.content.Context;
|
|||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
|
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -79,11 +80,13 @@ class CheckUnits {
|
|||||||
private static void accept(Context context, SharedPreferences preferences) {
|
private static void accept(Context context, SharedPreferences preferences) {
|
||||||
recordCheckPerformed(preferences);
|
recordCheckPerformed(preferences);
|
||||||
Intent startIntent = new Intent(context, SettingsActivity.class);
|
Intent startIntent = new Intent(context, SettingsActivity.class);
|
||||||
|
startIntent.putExtra(context.getString(R.string.open_settings_screen),
|
||||||
|
context.getString(R.string.display_settings_screen_key));
|
||||||
context.startActivity(startIntent);
|
context.startActivity(startIntent);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void recordCheckPerformed(SharedPreferences preferences) {
|
private static void recordCheckPerformed(SharedPreferences preferences) {
|
||||||
ApiFeatures.getInstance().getApiPlatformAdapter().applyPreferenceChanges(
|
ApiFeatures.getInstance().getApiAdapter().applyPreferenceChanges(
|
||||||
preferences.edit().putBoolean(PREFERENCE_UNITS_CHECKED, true));
|
preferences.edit().putBoolean(PREFERENCE_UNITS_CHECKED, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,62 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011 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 android.graphics.Paint;
|
||||||
|
import android.graphics.Path;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a colored {@code Path} to save its relative color for drawing.
|
||||||
|
* @author Vangelis S.
|
||||||
|
*/
|
||||||
|
public class ColoredPath {
|
||||||
|
private final Path path;
|
||||||
|
private final Paint pathPaint;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor for a ColoredPath by color.
|
||||||
|
*/
|
||||||
|
public ColoredPath(int color) {
|
||||||
|
path = new Path();
|
||||||
|
pathPaint = new Paint();
|
||||||
|
pathPaint.setColor(color);
|
||||||
|
pathPaint.setStrokeWidth(3);
|
||||||
|
pathPaint.setStyle(Paint.Style.STROKE);
|
||||||
|
pathPaint.setAntiAlias(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor for a ColoredPath by Paint.
|
||||||
|
*/
|
||||||
|
public ColoredPath(Paint paint) {
|
||||||
|
path = new Path();
|
||||||
|
pathPaint = paint;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the path
|
||||||
|
*/
|
||||||
|
public Path getPath() {
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the pathPaint
|
||||||
|
*/
|
||||||
|
public Paint getPathPaint() {
|
||||||
|
return pathPaint;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -65,7 +65,7 @@ public class DeleteAllTracks extends Handler {
|
|||||||
SharedPreferences.Editor editor = prefs.edit();
|
SharedPreferences.Editor editor = prefs.edit();
|
||||||
// TODO: Go through data manager
|
// TODO: Go through data manager
|
||||||
editor.putLong(context.getString(R.string.selected_track_key), -1);
|
editor.putLong(context.getString(R.string.selected_track_key), -1);
|
||||||
ApiFeatures.getInstance().getApiPlatformAdapter().applyPreferenceChanges(editor);
|
ApiFeatures.getInstance().getApiAdapter().applyPreferenceChanges(editor);
|
||||||
if (done != null) {
|
if (done != null) {
|
||||||
Handler h = new Handler();
|
Handler h = new Handler();
|
||||||
h.post(done);
|
h.post(done);
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ public class DeleteTrack extends Activity
|
|||||||
SharedPreferences preferences = getSharedPreferences(Constants.SETTINGS_NAME, 0);
|
SharedPreferences preferences = getSharedPreferences(Constants.SETTINGS_NAME, 0);
|
||||||
if (preferences.getLong(selectedKey, -1) == deleteTrackId) {
|
if (preferences.getLong(selectedKey, -1) == deleteTrackId) {
|
||||||
Editor editor = preferences.edit().putLong(selectedKey, -1);
|
Editor editor = preferences.edit().putLong(selectedKey, -1);
|
||||||
ApiFeatures.getInstance().getApiPlatformAdapter().applyPreferenceChanges(editor);
|
ApiFeatures.getInstance().getApiAdapter().applyPreferenceChanges(editor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ class Eula {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void accept(Activity activity, SharedPreferences preferences) {
|
private static void accept(Activity activity, SharedPreferences preferences) {
|
||||||
ApiFeatures.getInstance().getApiPlatformAdapter().applyPreferenceChanges(
|
ApiFeatures.getInstance().getApiAdapter().applyPreferenceChanges(
|
||||||
preferences.edit().putBoolean(PREFERENCE_EULA_ACCEPTED, true));
|
preferences.edit().putBoolean(PREFERENCE_EULA_ACCEPTED, true));
|
||||||
Intent startIntent = new Intent(activity, WelcomeActivity.class);
|
Intent startIntent = new Intent(activity, WelcomeActivity.class);
|
||||||
activity.startActivityForResult(startIntent, Constants.WELCOME);
|
activity.startActivityForResult(startIntent, Constants.WELCOME);
|
||||||
|
|||||||
@@ -185,7 +185,7 @@ public class MapActivity extends com.google.android.maps.MapActivity
|
|||||||
Log.d(TAG, "MapActivity.onResume");
|
Log.d(TAG, "MapActivity.onResume");
|
||||||
super.onResume();
|
super.onResume();
|
||||||
|
|
||||||
dataHub = TrackDataHub.getStartedInstance();
|
dataHub = ((MyTracksApplication) getApplication()).getTrackDataHub();
|
||||||
dataHub.registerTrackDataListener(this, EnumSet.of(
|
dataHub.registerTrackDataListener(this, EnumSet.of(
|
||||||
ListenerDataType.SELECTED_TRACK_CHANGED,
|
ListenerDataType.SELECTED_TRACK_CHANGED,
|
||||||
ListenerDataType.POINT_UPDATES,
|
ListenerDataType.POINT_UPDATES,
|
||||||
|
|||||||
@@ -18,6 +18,9 @@ package com.google.android.apps.mytracks;
|
|||||||
import static com.google.android.apps.mytracks.Constants.TAG;
|
import static com.google.android.apps.mytracks.Constants.TAG;
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.content.Waypoint;
|
import com.google.android.apps.mytracks.content.Waypoint;
|
||||||
|
import com.google.android.apps.mytracks.maps.TrackPathPainter;
|
||||||
|
import com.google.android.apps.mytracks.maps.TrackPathPainterFactory;
|
||||||
|
import com.google.android.apps.mytracks.maps.TrackPathUtilities;
|
||||||
import com.google.android.apps.mytracks.util.LocationUtils;
|
import com.google.android.apps.mytracks.util.LocationUtils;
|
||||||
import com.google.android.maps.GeoPoint;
|
import com.google.android.maps.GeoPoint;
|
||||||
import com.google.android.maps.MapView;
|
import com.google.android.maps.MapView;
|
||||||
@@ -27,10 +30,11 @@ import com.google.android.maps.mytracks.R;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
import android.graphics.Paint;
|
import android.graphics.Paint;
|
||||||
import android.graphics.Path;
|
|
||||||
import android.graphics.Point;
|
import android.graphics.Point;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
@@ -48,7 +52,7 @@ import java.util.concurrent.BlockingQueue;
|
|||||||
*
|
*
|
||||||
* @author Leif Hendrik Wilden
|
* @author Leif Hendrik Wilden
|
||||||
*/
|
*/
|
||||||
public class MapOverlay extends Overlay {
|
public class MapOverlay extends Overlay implements OnSharedPreferenceChangeListener {
|
||||||
|
|
||||||
private final Drawable[] arrows;
|
private final Drawable[] arrows;
|
||||||
private final int arrowWidth, arrowHeight;
|
private final int arrowWidth, arrowHeight;
|
||||||
@@ -57,7 +61,6 @@ public class MapOverlay extends Overlay {
|
|||||||
private final Drawable startMarker;
|
private final Drawable startMarker;
|
||||||
private final Drawable endMarker;
|
private final Drawable endMarker;
|
||||||
private final int markerWidth, markerHeight;
|
private final int markerWidth, markerHeight;
|
||||||
private final Paint selectedTrackPaint;
|
|
||||||
private final Paint errorCirclePaint;
|
private final Paint errorCirclePaint;
|
||||||
private final Context context;
|
private final Context context;
|
||||||
private final List<Waypoint> waypoints;
|
private final List<Waypoint> waypoints;
|
||||||
@@ -73,15 +76,18 @@ public class MapOverlay extends Overlay {
|
|||||||
|
|
||||||
private GeoPoint lastReferencePoint;
|
private GeoPoint lastReferencePoint;
|
||||||
private Rect lastViewRect;
|
private Rect lastViewRect;
|
||||||
private Path lastPath;
|
private boolean lastPathExists;
|
||||||
|
private Location lastLocation;
|
||||||
|
private TrackPathPainter trackPathPainter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a pre-processed {@code Location} to speed up drawing.
|
* Represents a pre-processed {@code Location} to speed up drawing.
|
||||||
* This class is more like a data object and doesn't provide accessors.
|
* This class is more like a data object and doesn't provide accessors.
|
||||||
*/
|
*/
|
||||||
private static class CachedLocation {
|
public static class CachedLocation {
|
||||||
public final boolean valid;
|
public final boolean valid;
|
||||||
public final GeoPoint geoPoint;
|
public final GeoPoint geoPoint;
|
||||||
|
public final int speed;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor for an invalid cached location.
|
* Constructor for an invalid cached location.
|
||||||
@@ -89,6 +95,7 @@ public class MapOverlay extends Overlay {
|
|||||||
public CachedLocation() {
|
public CachedLocation() {
|
||||||
this.valid = false;
|
this.valid = false;
|
||||||
this.geoPoint = null;
|
this.geoPoint = null;
|
||||||
|
this.speed = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -97,6 +104,7 @@ public class MapOverlay extends Overlay {
|
|||||||
public CachedLocation(Location location) {
|
public CachedLocation(Location location) {
|
||||||
this.valid = LocationUtils.isValidLocation(location);
|
this.valid = LocationUtils.isValidLocation(location);
|
||||||
this.geoPoint = valid ? LocationUtils.getGeoPoint(location) : null;
|
this.geoPoint = valid ? LocationUtils.getGeoPoint(location) : null;
|
||||||
|
this.speed = (int) Math.floor(location.getSpeed() * 3.6);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -151,18 +159,13 @@ public class MapOverlay extends Overlay {
|
|||||||
waypointMarker = resources.getDrawable(R.drawable.blue_pushpin);
|
waypointMarker = resources.getDrawable(R.drawable.blue_pushpin);
|
||||||
waypointMarker.setBounds(0, 0, markerWidth, markerHeight);
|
waypointMarker.setBounds(0, 0, markerWidth, markerHeight);
|
||||||
|
|
||||||
selectedTrackPaint = new Paint();
|
errorCirclePaint = TrackPathUtilities.getPaint(R.color.blue, context);
|
||||||
selectedTrackPaint.setColor(resources.getColor(R.color.red));
|
|
||||||
selectedTrackPaint.setStrokeWidth(3);
|
|
||||||
selectedTrackPaint.setStyle(Paint.Style.STROKE);
|
|
||||||
selectedTrackPaint.setAntiAlias(true);
|
|
||||||
|
|
||||||
errorCirclePaint = new Paint();
|
|
||||||
errorCirclePaint.setColor(resources.getColor(R.color.blue));
|
|
||||||
errorCirclePaint.setStyle(Paint.Style.STROKE);
|
|
||||||
errorCirclePaint.setStrokeWidth(3);
|
|
||||||
errorCirclePaint.setAlpha(127);
|
errorCirclePaint.setAlpha(127);
|
||||||
errorCirclePaint.setAntiAlias(true);
|
|
||||||
|
trackPathPainter = TrackPathPainterFactory.getTrackPathPainter(context);
|
||||||
|
|
||||||
|
context.getSharedPreferences(Constants.SETTINGS_NAME, 0)
|
||||||
|
.registerOnSharedPreferenceChangeListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -205,18 +208,19 @@ public class MapOverlay extends Overlay {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Visible for testing.
|
// Visible for testing.
|
||||||
int getNumWaypoints() {
|
public int getNumWaypoints() {
|
||||||
synchronized (waypoints) {
|
synchronized (waypoints) {
|
||||||
return waypoints.size();
|
return waypoints.size();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clearPoints() {
|
public void clearPoints() {
|
||||||
synchronized (points) {
|
synchronized (getPoints()) {
|
||||||
points.clear();
|
getPoints().clear();
|
||||||
pendingPoints.clear();
|
pendingPoints.clear();
|
||||||
lastPath = null;
|
lastPathExists = false;
|
||||||
lastViewRect = null;
|
lastViewRect = null;
|
||||||
|
trackPathPainter.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -254,6 +258,9 @@ public class MapOverlay extends Overlay {
|
|||||||
// Draw the selected track:
|
// Draw the selected track:
|
||||||
drawTrack(canvas, projection, viewRect);
|
drawTrack(canvas, projection, viewRect);
|
||||||
|
|
||||||
|
// Draw the "Start" and "End" markers:
|
||||||
|
drawMarkers(canvas, projection);
|
||||||
|
|
||||||
// Draw the waypoints:
|
// Draw the waypoints:
|
||||||
drawWaypoints(canvas, projection);
|
drawWaypoints(canvas, projection);
|
||||||
}
|
}
|
||||||
@@ -262,6 +269,28 @@ public class MapOverlay extends Overlay {
|
|||||||
drawMyLocation(canvas, projection);
|
drawMyLocation(canvas, projection);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void drawMarkers(Canvas canvas, Projection projection) {
|
||||||
|
// Draw the "End" marker.
|
||||||
|
if (showEndMarker) {
|
||||||
|
for (int i = getPoints().size() - 1; i >= 0; --i) {
|
||||||
|
if (getPoints().get(i).valid) {
|
||||||
|
drawElement(canvas, projection, getPoints().get(i).geoPoint, endMarker,
|
||||||
|
-markerWidth / 2, -markerHeight);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw the "Start" marker.
|
||||||
|
for (int i = 0; i < getPoints().size(); ++i) {
|
||||||
|
if (getPoints().get(i).valid) {
|
||||||
|
drawElement(canvas, projection, getPoints().get(i).geoPoint, startMarker,
|
||||||
|
-markerWidth / 2, -markerHeight);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Visible for testing.
|
// Visible for testing.
|
||||||
Projection getMapProjection(MapView mapView) {
|
Projection getMapProjection(MapView mapView) {
|
||||||
return mapView.getProjection();
|
return mapView.getProjection();
|
||||||
@@ -276,14 +305,14 @@ public class MapOverlay extends Overlay {
|
|||||||
return new Rect(cx - w / 2, cy - h / 2, cx + w / 2, cy + h / 2);
|
return new Rect(cx - w / 2, cy - h / 2, cx + w / 2, cy + h / 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Visible for testing.
|
// For use in testing only.
|
||||||
Path newPath() {
|
public TrackPathPainter getTrackPathPainter() {
|
||||||
return new Path();
|
return trackPathPainter;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Visible for testing.
|
// For use in testing only.
|
||||||
Path getLastPath() {
|
public void setTrackPathPainter(TrackPathPainter trackPathPainter) {
|
||||||
return lastPath;
|
this.trackPathPainter = trackPathPainter;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void drawWaypoints(Canvas canvas, Projection projection) {
|
private void drawWaypoints(Canvas canvas, Projection projection) {
|
||||||
@@ -311,96 +340,39 @@ public class MapOverlay extends Overlay {
|
|||||||
canvas.drawCircle(pt.x, pt.y, radius, errorCirclePaint);
|
canvas.drawCircle(pt.x, pt.y, radius, errorCirclePaint);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void drawTrack(Canvas canvas, Projection projection, Rect viewRect) {
|
private void drawTrack(Canvas canvas, Projection projection, Rect viewRect)
|
||||||
Path path;
|
{
|
||||||
|
boolean draw;
|
||||||
|
|
||||||
synchronized (points) {
|
synchronized (points) {
|
||||||
// Merge the pending points with the list of cached locations.
|
// Merge the pending points with the list of cached locations.
|
||||||
final GeoPoint referencePoint = projection.fromPixels(0, 0);
|
final GeoPoint referencePoint = projection.fromPixels(0, 0);
|
||||||
int newPoints = pendingPoints.drainTo(points);
|
int newPoints = pendingPoints.drainTo(points);
|
||||||
boolean newProjection = !viewRect.equals(lastViewRect) ||
|
boolean newProjection = !viewRect.equals(lastViewRect) ||
|
||||||
!referencePoint.equals(lastReferencePoint);
|
!referencePoint.equals(lastReferencePoint);
|
||||||
if (newPoints == 0 && lastPath != null && !newProjection) {
|
if (newPoints == 0 && lastPathExists && !newProjection) {
|
||||||
// No need to recreate path (same points and viewing area).
|
// No need to recreate path (same points and viewing area).
|
||||||
path = lastPath;
|
draw = true;
|
||||||
} else {
|
} else {
|
||||||
int numPoints = points.size();
|
int numPoints = points.size();
|
||||||
if (numPoints < 2) {
|
if (numPoints < 2) {
|
||||||
// Not enough points to draw a path.
|
// Not enough points to draw a path.
|
||||||
path = null;
|
draw = false;
|
||||||
} else if (lastPath != null && !newProjection) {
|
} else if (!trackPathPainter.needsRedraw() && lastPathExists && !newProjection) {
|
||||||
// Incremental update of the path, without repositioning the view.
|
// Incremental update of the path, without repositioning the view.
|
||||||
path = lastPath;
|
draw = true;
|
||||||
updatePath(projection, viewRect, path, numPoints - newPoints);
|
trackPathPainter.updatePath(projection, viewRect, numPoints - newPoints, alwaysVisible, points);
|
||||||
} else {
|
} else {
|
||||||
// The view has changed so we have to start from scratch.
|
// The view has changed so we have to start from scratch.
|
||||||
path = newPath();
|
draw = true;
|
||||||
path.incReserve(numPoints);
|
trackPathPainter.updatePath(projection, viewRect, 0, alwaysVisible, points);
|
||||||
updatePath(projection, viewRect, path, 0);
|
|
||||||
}
|
}
|
||||||
lastPath = path;
|
|
||||||
}
|
}
|
||||||
lastReferencePoint = referencePoint;
|
lastReferencePoint = referencePoint;
|
||||||
lastViewRect = viewRect;
|
lastViewRect = viewRect;
|
||||||
}
|
}
|
||||||
if (path != null) {
|
if (draw) {
|
||||||
canvas.drawPath(path, selectedTrackPaint);
|
trackPathPainter.drawTrack(canvas);
|
||||||
}
|
|
||||||
|
|
||||||
// Draw the "End" marker.
|
|
||||||
if (showEndMarker) {
|
|
||||||
for (int i = points.size() - 1; i >= 0; --i) {
|
|
||||||
if (points.get(i).valid) {
|
|
||||||
drawElement(canvas, projection, points.get(i).geoPoint, endMarker,
|
|
||||||
-markerWidth / 2, -markerHeight);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Draw the "Start" marker.
|
|
||||||
for (int i = 0; i < points.size(); ++i) {
|
|
||||||
if (points.get(i).valid) {
|
|
||||||
drawElement(canvas, projection, points.get(i).geoPoint, startMarker,
|
|
||||||
-markerWidth / 2, -markerHeight);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updatePath(Projection projection, Rect viewRect, Path path,
|
|
||||||
int startLocationIdx) {
|
|
||||||
// Whether to start a new segment on new valid and visible point.
|
|
||||||
boolean newSegment =
|
|
||||||
startLocationIdx > 0 ? !points.get(startLocationIdx - 1).valid : true;
|
|
||||||
boolean lastVisible = !newSegment;
|
|
||||||
final Point pt = new Point();
|
|
||||||
// Loop over track points.
|
|
||||||
for (int i = startLocationIdx; i < points.size(); ++i) {
|
|
||||||
CachedLocation loc = points.get(i);
|
|
||||||
// Check if valid, if not then indicate a new segment.
|
|
||||||
if (!loc.valid) {
|
|
||||||
newSegment = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
final GeoPoint geoPoint = loc.geoPoint;
|
|
||||||
// Check if this breaks the existing segment.
|
|
||||||
boolean visible = alwaysVisible || viewRect.contains(
|
|
||||||
geoPoint.getLongitudeE6(), geoPoint.getLatitudeE6());
|
|
||||||
if (!visible && !lastVisible) {
|
|
||||||
// This is a point outside view not connected to a visible one.
|
|
||||||
newSegment = true;
|
|
||||||
}
|
|
||||||
lastVisible = visible;
|
|
||||||
|
|
||||||
// Either move to beginning of a new segment or continue the old one.
|
|
||||||
projection.toPixels(geoPoint, pt);
|
|
||||||
if (newSegment) {
|
|
||||||
path.moveTo(pt.x, pt.y);
|
|
||||||
newSegment = false;
|
|
||||||
} else {
|
|
||||||
path.lineTo(pt.x, pt.y);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -479,4 +451,21 @@ public class MapOverlay extends Overlay {
|
|||||||
}
|
}
|
||||||
return super.onTap(p, mapView);
|
return super.onTap(p, mapView);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the points
|
||||||
|
*/
|
||||||
|
public List<CachedLocation> getPoints() {
|
||||||
|
return points;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
|
||||||
|
Log.d(TAG, "MapOverlay: onSharedPreferences changed " + key);
|
||||||
|
if (key != null) {
|
||||||
|
if (key.equals(context.getString(R.string.track_color_mode_key))) {
|
||||||
|
trackPathPainter = TrackPathPainterFactory.getTrackPathPainter(context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -134,7 +134,7 @@ public class MyTracks extends TabActivity implements OnTouchListener {
|
|||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
ApiFeatures apiFeatures = ApiFeatures.getInstance();
|
ApiFeatures apiFeatures = ApiFeatures.getInstance();
|
||||||
if (!SystemUtils.isRelease(this)) {
|
if (!SystemUtils.isRelease(this)) {
|
||||||
apiFeatures.getApiPlatformAdapter().enableStrictMode();
|
apiFeatures.getApiAdapter().enableStrictMode();
|
||||||
}
|
}
|
||||||
|
|
||||||
tracker = GoogleAnalyticsTracker.getInstance();
|
tracker = GoogleAnalyticsTracker.getInstance();
|
||||||
@@ -146,7 +146,7 @@ public class MyTracks extends TabActivity implements OnTouchListener {
|
|||||||
|
|
||||||
providerUtils = MyTracksProviderUtils.Factory.get(this);
|
providerUtils = MyTracksProviderUtils.Factory.get(this);
|
||||||
preferences = getSharedPreferences(Constants.SETTINGS_NAME, 0);
|
preferences = getSharedPreferences(Constants.SETTINGS_NAME, 0);
|
||||||
dataHub = TrackDataHub.newInstance(this);
|
dataHub = ((MyTracksApplication) getApplication()).getTrackDataHub();
|
||||||
menuManager = new MenuManager(this);
|
menuManager = new MenuManager(this);
|
||||||
serviceConnection = new TrackRecordingServiceConnection(this, serviceBindCallback);
|
serviceConnection = new TrackRecordingServiceConnection(this, serviceBindCallback);
|
||||||
|
|
||||||
@@ -249,7 +249,6 @@ public class MyTracks extends TabActivity implements OnTouchListener {
|
|||||||
protected void onDestroy() {
|
protected void onDestroy() {
|
||||||
Log.d(TAG, "MyTracks.onDestroy");
|
Log.d(TAG, "MyTracks.onDestroy");
|
||||||
serviceConnection.unbind();
|
serviceConnection.unbind();
|
||||||
|
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2008 Google Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
* use this file except in compliance with the License. You may obtain a copy of
|
||||||
|
* the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations under
|
||||||
|
* the License.
|
||||||
|
*/
|
||||||
|
package com.google.android.apps.mytracks;
|
||||||
|
|
||||||
|
import com.google.android.apps.mytracks.content.TrackDataHub;
|
||||||
|
|
||||||
|
import android.app.Application;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MyTracksApplication for keeping global state.
|
||||||
|
*
|
||||||
|
* @author jshih@google.com (Jimmy Shih)
|
||||||
|
*/
|
||||||
|
public class MyTracksApplication extends Application {
|
||||||
|
|
||||||
|
private TrackDataHub trackDataHub;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the application's TrackDataHub.
|
||||||
|
*
|
||||||
|
* Note: use synchronized to make sure only one instance is created per application.
|
||||||
|
*/
|
||||||
|
public synchronized TrackDataHub getTrackDataHub() {
|
||||||
|
if (trackDataHub == null) {
|
||||||
|
trackDataHub = TrackDataHub.newInstance(getApplicationContext());
|
||||||
|
}
|
||||||
|
return trackDataHub;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -20,6 +20,8 @@ import static com.google.android.apps.mytracks.Constants.TAG;
|
|||||||
import com.google.android.apps.mytracks.content.Sensor;
|
import com.google.android.apps.mytracks.content.Sensor;
|
||||||
import com.google.android.apps.mytracks.services.ITrackRecordingService;
|
import com.google.android.apps.mytracks.services.ITrackRecordingService;
|
||||||
import com.google.android.apps.mytracks.services.TrackRecordingServiceConnection;
|
import com.google.android.apps.mytracks.services.TrackRecordingServiceConnection;
|
||||||
|
import com.google.android.apps.mytracks.services.sensors.SensorManager;
|
||||||
|
import com.google.android.apps.mytracks.services.sensors.SensorManagerFactory;
|
||||||
import com.google.android.apps.mytracks.services.sensors.SensorUtils;
|
import com.google.android.apps.mytracks.services.sensors.SensorUtils;
|
||||||
import com.google.android.maps.mytracks.R;
|
import com.google.android.maps.mytracks.R;
|
||||||
import com.google.protobuf.InvalidProtocolBufferException;
|
import com.google.protobuf.InvalidProtocolBufferException;
|
||||||
@@ -55,7 +57,8 @@ public class SensorStateActivity extends Activity {
|
|||||||
|
|
||||||
private final Runnable stateUpdater = new Runnable() {
|
private final Runnable stateUpdater = new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
updateState();
|
if (isVisible) // only update when UI is visible
|
||||||
|
updateState();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -74,6 +77,23 @@ public class SensorStateActivity extends Activity {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A temporary sensor manager, when none is available.
|
||||||
|
*/
|
||||||
|
SensorManager tempSensorManager = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A state flag set to true when the activity is active/visible,
|
||||||
|
* i.e. after resume, and before pause
|
||||||
|
*
|
||||||
|
* Used to avoid updating after the pause event, because sometimes an update
|
||||||
|
* event occurs even after the timer is cancelled. In this case,
|
||||||
|
* it could cause the {@link #tempSensorManager} to be recreated, after it
|
||||||
|
* is destroyed at the pause event.
|
||||||
|
*/
|
||||||
|
boolean isVisible = false;
|
||||||
|
|
||||||
public SensorStateActivity() {
|
public SensorStateActivity() {
|
||||||
utils = new StatsUtilities(this);
|
utils = new StatsUtilities(this);
|
||||||
Log.w(TAG, "SensorStateActivity()");
|
Log.w(TAG, "SensorStateActivity()");
|
||||||
@@ -86,7 +106,6 @@ public class SensorStateActivity extends Activity {
|
|||||||
|
|
||||||
setContentView(R.layout.sensor_state);
|
setContentView(R.layout.sensor_state);
|
||||||
|
|
||||||
// TODO: Allow reading from sensors even if service is not running.
|
|
||||||
serviceConnection = new TrackRecordingServiceConnection(this, stateUpdater);
|
serviceConnection = new TrackRecordingServiceConnection(this, stateUpdater);
|
||||||
serviceConnection.bindIfRunning();
|
serviceConnection.bindIfRunning();
|
||||||
updateState();
|
updateState();
|
||||||
@@ -96,6 +115,8 @@ public class SensorStateActivity extends Activity {
|
|||||||
protected void onResume() {
|
protected void onResume() {
|
||||||
super.onResume();
|
super.onResume();
|
||||||
|
|
||||||
|
isVisible = true;
|
||||||
|
|
||||||
serviceConnection.bindIfRunning();
|
serviceConnection.bindIfRunning();
|
||||||
|
|
||||||
timer = new Timer();
|
timer = new Timer();
|
||||||
@@ -104,9 +125,12 @@ public class SensorStateActivity extends Activity {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onPause() {
|
protected void onPause() {
|
||||||
|
isVisible = false;
|
||||||
|
|
||||||
timer.cancel();
|
timer.cancel();
|
||||||
timer.purge();
|
timer.purge();
|
||||||
timer = null;
|
timer = null;
|
||||||
|
stopTempSensorManager();
|
||||||
super.onPause();
|
super.onPause();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,37 +141,108 @@ public class SensorStateActivity extends Activity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void updateState() {
|
protected void updateState() {
|
||||||
|
Log.d(TAG, "Updating SensorStateActivity");
|
||||||
|
|
||||||
ITrackRecordingService service = serviceConnection.getServiceIfBound();
|
ITrackRecordingService service = serviceConnection.getServiceIfBound();
|
||||||
if (service == null) {
|
|
||||||
Log.d(Constants.TAG, "Could not get track recording service.");
|
|
||||||
updateSensorState(Sensor.SensorState.NONE);
|
|
||||||
updateSensorData(null);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Sensor.SensorDataSet sds = null;
|
// Check if service is available, and recording.
|
||||||
try {
|
boolean isRecording = false;
|
||||||
byte[] buff = service.getSensorData();
|
if (service != null) {
|
||||||
if (buff != null) {
|
try {
|
||||||
sds = Sensor.SensorDataSet.parseFrom(buff);
|
isRecording = service.isRecording();
|
||||||
updateSensorData(sds);
|
} catch (RemoteException e) {
|
||||||
|
Log.e(TAG, "Unable to determine if service is recording.", e);
|
||||||
}
|
}
|
||||||
} catch (RemoteException e) {
|
|
||||||
Log.e(Constants.TAG, "Could not read sensor data.", e);
|
|
||||||
} catch (InvalidProtocolBufferException e) {
|
|
||||||
Log.e(Constants.TAG, "Could not read sensor data.", e);
|
|
||||||
}
|
}
|
||||||
updateSensorData(sds);
|
|
||||||
|
|
||||||
try {
|
// If either service isn't available, or not recording.
|
||||||
int i = service.getSensorState();
|
if (!isRecording) {
|
||||||
updateSensorState(Sensor.SensorState.valueOf(i));
|
updateFromTempSensorManager();
|
||||||
} catch (RemoteException e) {
|
} else {
|
||||||
Log.e(Constants.TAG, "Could not read sensor state.", e);
|
updateFromSysSensorManager();
|
||||||
updateSensorState(Sensor.SensorState.NONE);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updateFromTempSensorManager()
|
||||||
|
{
|
||||||
|
// Use variables to hold the sensor state and data set.
|
||||||
|
Sensor.SensorState currentState = null;
|
||||||
|
Sensor.SensorDataSet currentDataSet = null;
|
||||||
|
|
||||||
|
// If no temp sensor manager is present, create one, and start it.
|
||||||
|
if (tempSensorManager == null) {
|
||||||
|
tempSensorManager = SensorManagerFactory.getSensorManager(this);
|
||||||
|
if (tempSensorManager != null)
|
||||||
|
tempSensorManager.onStartTrack();
|
||||||
|
}
|
||||||
|
|
||||||
|
// If a temp sensor manager is available, use states from temp sensor
|
||||||
|
// manager.
|
||||||
|
if (tempSensorManager != null) {
|
||||||
|
currentState = tempSensorManager.getSensorState();
|
||||||
|
currentDataSet = tempSensorManager.getSensorDataSet();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the sensor state, and sensor data, using the variables.
|
||||||
|
updateSensorStateAndData(currentState, currentDataSet);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateFromSysSensorManager()
|
||||||
|
{
|
||||||
|
// Use variables to hold the sensor state and data set.
|
||||||
|
Sensor.SensorState currentState = null;
|
||||||
|
Sensor.SensorDataSet currentDataSet = null;
|
||||||
|
|
||||||
|
ITrackRecordingService service = serviceConnection.getServiceIfBound();
|
||||||
|
|
||||||
|
// If a temp sensor manager is present, shut it down,
|
||||||
|
// probably recording just started.
|
||||||
|
stopTempSensorManager();
|
||||||
|
|
||||||
|
// Get sensor details from the service.
|
||||||
|
if (service == null) {
|
||||||
|
Log.d(TAG, "Could not get track recording service.");
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
byte[] buff = service.getSensorData();
|
||||||
|
if (buff != null) {
|
||||||
|
currentDataSet = Sensor.SensorDataSet.parseFrom(buff);
|
||||||
|
}
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
Log.e(TAG, "Could not read sensor data.", e);
|
||||||
|
} catch (InvalidProtocolBufferException e) {
|
||||||
|
Log.e(TAG, "Could not read sensor data.", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
currentState = Sensor.SensorState.valueOf(service.getSensorState());
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
Log.e(TAG, "Could not read sensor state.", e);
|
||||||
|
currentState = Sensor.SensorState.NONE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the sensor state, and sensor data, using the variables.
|
||||||
|
updateSensorStateAndData(currentState, currentDataSet);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stops the temporary sensor manager, if one exists.
|
||||||
|
*/
|
||||||
|
private void stopTempSensorManager()
|
||||||
|
{
|
||||||
|
if (tempSensorManager != null) {
|
||||||
|
tempSensorManager.shutdown();
|
||||||
|
tempSensorManager = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateSensorStateAndData(Sensor.SensorState state, Sensor.SensorDataSet dataSet)
|
||||||
|
{
|
||||||
|
updateSensorState(state == null ? Sensor.SensorState.NONE : state);
|
||||||
|
updateSensorData(dataSet);
|
||||||
|
}
|
||||||
|
|
||||||
private void updateSensorState(Sensor.SensorState state) {
|
private void updateSensorState(Sensor.SensorState state) {
|
||||||
TextView sensorTime =
|
TextView sensorTime =
|
||||||
((TextView) findViewById(R.id.sensor_state_register));
|
((TextView) findViewById(R.id.sensor_state_register));
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import com.google.android.apps.mytracks.services.sensors.ant.AntUtils;
|
|||||||
import com.google.android.apps.mytracks.services.tasks.StatusAnnouncerFactory;
|
import com.google.android.apps.mytracks.services.tasks.StatusAnnouncerFactory;
|
||||||
import com.google.android.apps.mytracks.util.ApiFeatures;
|
import com.google.android.apps.mytracks.util.ApiFeatures;
|
||||||
import com.google.android.apps.mytracks.util.BluetoothDeviceUtils;
|
import com.google.android.apps.mytracks.util.BluetoothDeviceUtils;
|
||||||
|
import com.google.android.apps.mytracks.util.UnitConversions;
|
||||||
import com.google.android.maps.mytracks.R;
|
import com.google.android.maps.mytracks.R;
|
||||||
|
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
@@ -32,11 +33,13 @@ import android.content.Intent;
|
|||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.preference.CheckBoxPreference;
|
import android.preference.CheckBoxPreference;
|
||||||
|
import android.preference.EditTextPreference;
|
||||||
import android.preference.ListPreference;
|
import android.preference.ListPreference;
|
||||||
import android.preference.Preference;
|
import android.preference.Preference;
|
||||||
import android.preference.Preference.OnPreferenceChangeListener;
|
import android.preference.Preference.OnPreferenceChangeListener;
|
||||||
import android.preference.Preference.OnPreferenceClickListener;
|
import android.preference.Preference.OnPreferenceClickListener;
|
||||||
import android.preference.PreferenceActivity;
|
import android.preference.PreferenceActivity;
|
||||||
|
import android.preference.PreferenceCategory;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
import android.preference.PreferenceScreen;
|
import android.preference.PreferenceScreen;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
@@ -51,6 +54,10 @@ import java.util.Set;
|
|||||||
/**
|
/**
|
||||||
* An activity that let's the user see and edit the settings.
|
* An activity that let's the user see and edit the settings.
|
||||||
*
|
*
|
||||||
|
* This activity has two entry points, "root" and "display" preference screen.
|
||||||
|
* If bundle.getString("open_settings_screen") is set to "display_settings_screen_key", then
|
||||||
|
* the "display" preference screen is shown, otherwise, the "root" display preference is shown.
|
||||||
|
*
|
||||||
* @author Leif Hendrik Wilden
|
* @author Leif Hendrik Wilden
|
||||||
* @author Rodrigo Damazio
|
* @author Rodrigo Damazio
|
||||||
*/
|
*/
|
||||||
@@ -64,6 +71,16 @@ public class SettingsActivity extends PreferenceActivity {
|
|||||||
protected void onCreate(Bundle icicle) {
|
protected void onCreate(Bundle icicle) {
|
||||||
super.onCreate(icicle);
|
super.onCreate(icicle);
|
||||||
|
|
||||||
|
initActivityCommons();
|
||||||
|
|
||||||
|
// If we only need the display setting screen nothing else needs to load.
|
||||||
|
if (processIntent())
|
||||||
|
return;
|
||||||
|
|
||||||
|
initActivitySpecifics();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initActivityCommons() {
|
||||||
// The volume we want to control is the Text-To-Speech volume
|
// The volume we want to control is the Text-To-Speech volume
|
||||||
ApiFeatures apiFeatures = ApiFeatures.getInstance();
|
ApiFeatures apiFeatures = ApiFeatures.getInstance();
|
||||||
int volumeStream =
|
int volumeStream =
|
||||||
@@ -76,13 +93,26 @@ public class SettingsActivity extends PreferenceActivity {
|
|||||||
preferenceManager.setSharedPreferencesMode(0);
|
preferenceManager.setSharedPreferencesMode(0);
|
||||||
|
|
||||||
// Set up automatic preferences backup
|
// Set up automatic preferences backup
|
||||||
backupListener = BackupPreferencesListener.create(this, apiFeatures);
|
backupListener = apiFeatures.getApiAdapter().getBackupPreferencesListener(this);
|
||||||
preferences = preferenceManager.getSharedPreferences();
|
preferences = preferenceManager.getSharedPreferences();
|
||||||
preferences.registerOnSharedPreferenceChangeListener(backupListener);
|
preferences.registerOnSharedPreferenceChangeListener(backupListener);
|
||||||
|
|
||||||
// Load the preferences to be displayed
|
// Load the preferences to be displayed
|
||||||
addPreferencesFromResource(R.xml.preferences);
|
addPreferencesFromResource(R.xml.preferences);
|
||||||
|
|
||||||
|
// Disable TTS announcement preference if not available
|
||||||
|
if (!apiFeatures.hasTextToSpeech()) {
|
||||||
|
IntegerListPreference announcementFrequency =
|
||||||
|
(IntegerListPreference) findPreference(
|
||||||
|
getString(R.string.announcement_frequency_key));
|
||||||
|
announcementFrequency.setEnabled(false);
|
||||||
|
announcementFrequency.setValue("-1");
|
||||||
|
announcementFrequency.setSummary(
|
||||||
|
R.string.settings_not_available_summary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initActivitySpecifics() {
|
||||||
// Hook up switching of displayed list entries between metric and imperial
|
// Hook up switching of displayed list entries between metric and imperial
|
||||||
// units
|
// units
|
||||||
CheckBoxPreference metricUnitsPreference =
|
CheckBoxPreference metricUnitsPreference =
|
||||||
@@ -101,17 +131,7 @@ public class SettingsActivity extends PreferenceActivity {
|
|||||||
updatePreferenceUnits(metricUnitsPreference.isChecked());
|
updatePreferenceUnits(metricUnitsPreference.isChecked());
|
||||||
|
|
||||||
customizeSensorOptionsPreferences();
|
customizeSensorOptionsPreferences();
|
||||||
|
customizeTrackColorModePreferences();
|
||||||
// Disable TTS announcement preference if not available
|
|
||||||
if (!apiFeatures.hasTextToSpeech()) {
|
|
||||||
IntegerListPreference announcementFrequency =
|
|
||||||
(IntegerListPreference) findPreference(
|
|
||||||
getString(R.string.announcement_frequency_key));
|
|
||||||
announcementFrequency.setEnabled(false);
|
|
||||||
announcementFrequency.setValue("-1");
|
|
||||||
announcementFrequency.setSummary(
|
|
||||||
R.string.settings_not_available_summary);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hook up action for resetting all settings
|
// Hook up action for resetting all settings
|
||||||
Preference resetPreference = findPreference(getString(R.string.reset_key));
|
Preference resetPreference = findPreference(getString(R.string.reset_key));
|
||||||
@@ -122,6 +142,50 @@ public class SettingsActivity extends PreferenceActivity {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Add a confirmation dialog for the "Allow access" preference.
|
||||||
|
final CheckBoxPreference allowAccessPreference = (CheckBoxPreference) findPreference(
|
||||||
|
getString(R.string.allow_access_key));
|
||||||
|
allowAccessPreference.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
|
||||||
|
@Override
|
||||||
|
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||||
|
if ((Boolean) newValue) {
|
||||||
|
AlertDialog dialog = new AlertDialog.Builder(SettingsActivity.this)
|
||||||
|
.setCancelable(true)
|
||||||
|
.setTitle(getString(R.string.settings_allow_access))
|
||||||
|
.setMessage(getString(R.string.settings_allow_access_dialog_message))
|
||||||
|
.setPositiveButton(android.R.string.ok, new OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialogInterface, int button) {
|
||||||
|
allowAccessPreference.setChecked(true);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.setNegativeButton(android.R.string.cancel, null)
|
||||||
|
.create();
|
||||||
|
dialog.show();
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean processIntent() {
|
||||||
|
boolean showDisplaySettings = false;
|
||||||
|
Bundle bundle = getIntent().getExtras();
|
||||||
|
PreferenceScreen preferenceScreen;
|
||||||
|
String intentString = getString(R.string.open_settings_screen);
|
||||||
|
|
||||||
|
if (bundle != null) {
|
||||||
|
preferenceScreen = (PreferenceScreen) findPreference(bundle.getString(intentString));
|
||||||
|
if (preferenceScreen != null) {
|
||||||
|
showDisplaySettings = true;
|
||||||
|
setPreferenceScreen(preferenceScreen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return showDisplaySettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void customizeSensorOptionsPreferences() {
|
private void customizeSensorOptionsPreferences() {
|
||||||
@@ -171,10 +235,37 @@ public class SettingsActivity extends PreferenceActivity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void customizeTrackColorModePreferences() {
|
||||||
|
ListPreference trackColorModePreference =
|
||||||
|
(ListPreference) findPreference(getString(R.string.track_color_mode_key));
|
||||||
|
trackColorModePreference.setOnPreferenceChangeListener(
|
||||||
|
new OnPreferenceChangeListener() {
|
||||||
|
@Override
|
||||||
|
public boolean onPreferenceChange(Preference preference,
|
||||||
|
Object newValue) {
|
||||||
|
updateTrackColorModeSettings((String) newValue);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
updateTrackColorModeSettings(trackColorModePreference.getValue());
|
||||||
|
|
||||||
|
setTrackColorModePreferenceListeners();
|
||||||
|
|
||||||
|
PreferenceCategory speedOptionsCategory =
|
||||||
|
(PreferenceCategory) findPreference(getString(R.string.track_color_mode_fixed_speed_options_key));
|
||||||
|
|
||||||
|
speedOptionsCategory.removePreference(findPreference(getString(R.string.track_color_mode_fixed_speed_slow_key)));
|
||||||
|
speedOptionsCategory.removePreference(findPreference(getString(R.string.track_color_mode_fixed_speed_medium_key)));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onResume() {
|
protected void onResume() {
|
||||||
super.onResume();
|
super.onResume();
|
||||||
|
|
||||||
|
// If we only need the display setting screen nothing else needs to load.
|
||||||
|
if (processIntent())
|
||||||
|
return;
|
||||||
|
|
||||||
configureBluetoothPreferences();
|
configureBluetoothPreferences();
|
||||||
Preference backupNowPreference =
|
Preference backupNowPreference =
|
||||||
findPreference(getString(R.string.backup_to_sd_key));
|
findPreference(getString(R.string.backup_to_sd_key));
|
||||||
@@ -251,6 +342,18 @@ public class SettingsActivity extends PreferenceActivity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updateTrackColorModeSettings(String trackColorMode) {
|
||||||
|
boolean usesFixedSpeed = trackColorMode.equals(getString(R.string.track_color_mode_fixed));
|
||||||
|
boolean usesDynamicSpeed = trackColorMode.equals(getString(R.string.track_color_mode_dynamic));
|
||||||
|
|
||||||
|
findPreference(
|
||||||
|
getString(R.string.track_color_mode_fixed_speed_slow_display_key)).setEnabled(usesFixedSpeed);
|
||||||
|
findPreference(
|
||||||
|
getString(R.string.track_color_mode_fixed_speed_medium_display_key)).setEnabled(usesFixedSpeed);
|
||||||
|
findPreference(
|
||||||
|
getString(R.string.track_color_mode_dynamic_speed_variation_key)).setEnabled(usesDynamicSpeed);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates all the preferences which give options with distance units to use
|
* Updates all the preferences which give options with distance units to use
|
||||||
* the proper unit the user has selected.
|
* the proper unit the user has selected.
|
||||||
@@ -379,4 +482,84 @@ public class SettingsActivity extends PreferenceActivity {
|
|||||||
}
|
}
|
||||||
}.start();
|
}.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the given edit text preference text.
|
||||||
|
* If the units are not metric convert the value before displaying.
|
||||||
|
*/
|
||||||
|
private void viewTrackColorModeSettings(EditTextPreference preference, int id) {
|
||||||
|
CheckBoxPreference metricUnitsPreference = (CheckBoxPreference) findPreference(
|
||||||
|
getString(R.string.metric_units_key));
|
||||||
|
if(metricUnitsPreference.isChecked()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Convert miles/h to km/h
|
||||||
|
SharedPreferences prefs = getPreferenceManager().getSharedPreferences();
|
||||||
|
String metricspeed = prefs.getString(getString(id), null);
|
||||||
|
int englishspeed;
|
||||||
|
try {
|
||||||
|
englishspeed = (int) (Double.parseDouble(metricspeed) * UnitConversions.KMH_TO_MPH);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
englishspeed = 0;
|
||||||
|
}
|
||||||
|
preference.getEditText().setText(String.valueOf(englishspeed));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves the given edit text preference value.
|
||||||
|
* If the units are not metric convert the value before saving.
|
||||||
|
*/
|
||||||
|
private void validateTrackColorModeSettings(EditTextPreference preference,
|
||||||
|
String newValue, int id) {
|
||||||
|
CheckBoxPreference metricUnitsPreference = (CheckBoxPreference) findPreference(
|
||||||
|
getString(R.string.metric_units_key));
|
||||||
|
String metricspeed;
|
||||||
|
if(!metricUnitsPreference.isChecked()) {
|
||||||
|
// Convert miles/h to km/h
|
||||||
|
try {
|
||||||
|
metricspeed = String.valueOf((int) (Double.parseDouble(newValue) * UnitConversions.MPH_TO_KMH) + 1);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
metricspeed = "0";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
metricspeed = newValue;
|
||||||
|
}
|
||||||
|
SharedPreferences prefs = getPreferenceManager().getSharedPreferences();
|
||||||
|
prefs.edit().putString(getString(id), metricspeed).commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the TrackColorMode preference listeners.
|
||||||
|
*/
|
||||||
|
private void setTrackColorModePreferenceListeners() {
|
||||||
|
setTrackColorModePreferenceListener(R.string.track_color_mode_fixed_speed_slow_display_key,
|
||||||
|
R.string.track_color_mode_fixed_speed_slow_key);
|
||||||
|
setTrackColorModePreferenceListener(R.string.track_color_mode_fixed_speed_medium_display_key,
|
||||||
|
R.string.track_color_mode_fixed_speed_medium_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a TrackColorMode preference listener.
|
||||||
|
*/
|
||||||
|
private void setTrackColorModePreferenceListener(int displayKey, final int metricKey) {
|
||||||
|
EditTextPreference trackColorModePreference =
|
||||||
|
(EditTextPreference) findPreference(getString(displayKey));
|
||||||
|
trackColorModePreference.setOnPreferenceChangeListener(
|
||||||
|
new OnPreferenceChangeListener() {
|
||||||
|
@Override
|
||||||
|
public boolean onPreferenceChange(Preference preference,
|
||||||
|
Object newValue) {
|
||||||
|
validateTrackColorModeSettings((EditTextPreference) preference, (String) newValue, metricKey);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
trackColorModePreference.setOnPreferenceClickListener(
|
||||||
|
new OnPreferenceClickListener() {
|
||||||
|
@Override
|
||||||
|
public boolean onPreferenceClick(Preference preference) {
|
||||||
|
viewTrackColorModeSettings((EditTextPreference) preference, metricKey);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -137,7 +137,7 @@ public class StatsActivity extends Activity implements TrackDataListener {
|
|||||||
protected void onResume() {
|
protected void onResume() {
|
||||||
super.onResume();
|
super.onResume();
|
||||||
|
|
||||||
dataHub = TrackDataHub.getStartedInstance();
|
dataHub = ((MyTracksApplication) getApplication()).getTrackDataHub();
|
||||||
dataHub.registerTrackDataListener(this, EnumSet.of(
|
dataHub.registerTrackDataListener(this, EnumSet.of(
|
||||||
ListenerDataType.SELECTED_TRACK_CHANGED,
|
ListenerDataType.SELECTED_TRACK_CHANGED,
|
||||||
ListenerDataType.TRACK_UPDATES,
|
ListenerDataType.TRACK_UPDATES,
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import android.os.Bundle;
|
|||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.View.OnClickListener;
|
import android.view.View.OnClickListener;
|
||||||
|
import android.view.inputmethod.EditorInfo;
|
||||||
import android.widget.ArrayAdapter;
|
import android.widget.ArrayAdapter;
|
||||||
import android.widget.AutoCompleteTextView;
|
import android.widget.AutoCompleteTextView;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
@@ -139,6 +140,7 @@ public class WaypointDetails extends Activity
|
|||||||
utils.setAllStats(waypointStats);
|
utils.setAllStats(waypointStats);
|
||||||
utils.setAltitude(
|
utils.setAltitude(
|
||||||
R.id.elevation_register, waypoint.getLocation().getAltitude());
|
R.id.elevation_register, waypoint.getLocation().getAltitude());
|
||||||
|
name.setImeOptions(EditorInfo.IME_ACTION_DONE);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
icon.setImageDrawable(getResources().getDrawable(iconId));
|
icon.setImageDrawable(getResources().getDrawable(iconId));
|
||||||
|
|||||||
@@ -17,11 +17,13 @@ package com.google.android.apps.mytracks.content;
|
|||||||
|
|
||||||
import com.google.android.apps.mytracks.Constants;
|
import com.google.android.apps.mytracks.Constants;
|
||||||
import com.google.android.apps.mytracks.util.ApiFeatures;
|
import com.google.android.apps.mytracks.util.ApiFeatures;
|
||||||
|
import com.google.android.maps.mytracks.R;
|
||||||
|
|
||||||
import android.content.ContentProvider;
|
import android.content.ContentProvider;
|
||||||
import android.content.ContentUris;
|
import android.content.ContentUris;
|
||||||
import android.content.ContentValues;
|
import android.content.ContentValues;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
import android.content.UriMatcher;
|
import android.content.UriMatcher;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.database.SQLException;
|
import android.database.SQLException;
|
||||||
@@ -30,6 +32,8 @@ import android.database.sqlite.SQLiteException;
|
|||||||
import android.database.sqlite.SQLiteOpenHelper;
|
import android.database.sqlite.SQLiteOpenHelper;
|
||||||
import android.database.sqlite.SQLiteQueryBuilder;
|
import android.database.sqlite.SQLiteQueryBuilder;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
import android.os.Binder;
|
||||||
|
import android.os.Process;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
@@ -183,8 +187,22 @@ public class MyTracksProvider extends ContentProvider {
|
|||||||
"waypoints/#", WAYPOINTS_ID);
|
"waypoints/#", WAYPOINTS_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean canAccess() {
|
||||||
|
if (Binder.getCallingPid() == Process.myPid()) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
Context context = getContext();
|
||||||
|
SharedPreferences sharedPreferences = context.getSharedPreferences(
|
||||||
|
Constants.SETTINGS_NAME, 0);
|
||||||
|
return sharedPreferences.getBoolean(context.getString(R.string.allow_access_key), false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onCreate() {
|
public boolean onCreate() {
|
||||||
|
if (!canAccess()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
DatabaseHelper dbHelper = new DatabaseHelper(getContext());
|
DatabaseHelper dbHelper = new DatabaseHelper(getContext());
|
||||||
try {
|
try {
|
||||||
db = dbHelper.getWritableDatabase();
|
db = dbHelper.getWritableDatabase();
|
||||||
@@ -196,6 +214,9 @@ public class MyTracksProvider extends ContentProvider {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int delete(Uri url, String where, String[] selectionArgs) {
|
public int delete(Uri url, String where, String[] selectionArgs) {
|
||||||
|
if (!canAccess()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
String table;
|
String table;
|
||||||
boolean shouldVacuum = false;
|
boolean shouldVacuum = false;
|
||||||
switch (urlMatcher.match(url)) {
|
switch (urlMatcher.match(url)) {
|
||||||
@@ -228,6 +249,9 @@ public class MyTracksProvider extends ContentProvider {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getType(Uri url) {
|
public String getType(Uri url) {
|
||||||
|
if (!canAccess()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
switch (urlMatcher.match(url)) {
|
switch (urlMatcher.match(url)) {
|
||||||
case TRACKPOINTS:
|
case TRACKPOINTS:
|
||||||
return TrackPointsColumns.CONTENT_TYPE;
|
return TrackPointsColumns.CONTENT_TYPE;
|
||||||
@@ -248,6 +272,9 @@ public class MyTracksProvider extends ContentProvider {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Uri insert(Uri url, ContentValues initialValues) {
|
public Uri insert(Uri url, ContentValues initialValues) {
|
||||||
|
if (!canAccess()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
Log.d(MyTracksProvider.TAG, "MyTracksProvider.insert");
|
Log.d(MyTracksProvider.TAG, "MyTracksProvider.insert");
|
||||||
ContentValues values;
|
ContentValues values;
|
||||||
if (initialValues != null) {
|
if (initialValues != null) {
|
||||||
@@ -276,6 +303,9 @@ public class MyTracksProvider extends ContentProvider {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int bulkInsert(Uri url, ContentValues[] valuesBulk) {
|
public int bulkInsert(Uri url, ContentValues[] valuesBulk) {
|
||||||
|
if (!canAccess()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Log.d(MyTracksProvider.TAG, "MyTracksProvider.bulkInsert");
|
Log.d(MyTracksProvider.TAG, "MyTracksProvider.bulkInsert");
|
||||||
int numInserted = 0;
|
int numInserted = 0;
|
||||||
try {
|
try {
|
||||||
@@ -348,6 +378,9 @@ public class MyTracksProvider extends ContentProvider {
|
|||||||
public Cursor query(
|
public Cursor query(
|
||||||
Uri url, String[] projection, String selection, String[] selectionArgs,
|
Uri url, String[] projection, String selection, String[] selectionArgs,
|
||||||
String sort) {
|
String sort) {
|
||||||
|
if (!canAccess()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
|
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
|
||||||
int match = urlMatcher.match(url);
|
int match = urlMatcher.match(url);
|
||||||
String sortOrder = null;
|
String sortOrder = null;
|
||||||
@@ -399,6 +432,9 @@ public class MyTracksProvider extends ContentProvider {
|
|||||||
@Override
|
@Override
|
||||||
public int update(Uri url, ContentValues values, String where,
|
public int update(Uri url, ContentValues values, String where,
|
||||||
String[] selectionArgs) {
|
String[] selectionArgs) {
|
||||||
|
if (!canAccess()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
int count;
|
int count;
|
||||||
int match = urlMatcher.match(url);
|
int match = urlMatcher.match(url);
|
||||||
if (match == TRACKPOINTS) {
|
if (match == TRACKPOINTS) {
|
||||||
|
|||||||
@@ -195,15 +195,12 @@ public class TrackDataHub {
|
|||||||
private int lastSamplingFrequency;
|
private int lastSamplingFrequency;
|
||||||
private DoubleBufferedLocationFactory locationFactory;
|
private DoubleBufferedLocationFactory locationFactory;
|
||||||
|
|
||||||
private static TrackDataHub startedInstance;
|
private boolean started = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builds a new {@link TrackDataHub} instance.
|
* Builds a new {@link TrackDataHub} instance.
|
||||||
*/
|
*/
|
||||||
public synchronized static TrackDataHub newInstance(Context context) {
|
public synchronized static TrackDataHub newInstance(Context context) {
|
||||||
// Ensure our singleton is never bound to an activity, to avoid memory leaks.
|
|
||||||
context = context.getApplicationContext();
|
|
||||||
|
|
||||||
SharedPreferences preferences = context.getSharedPreferences(Constants.SETTINGS_NAME, 0);
|
SharedPreferences preferences = context.getSharedPreferences(Constants.SETTINGS_NAME, 0);
|
||||||
MyTracksProviderUtils providerUtils = MyTracksProviderUtils.Factory.get(context);
|
MyTracksProviderUtils providerUtils = MyTracksProviderUtils.Factory.get(context);
|
||||||
return new TrackDataHub(context,
|
return new TrackDataHub(context,
|
||||||
@@ -240,11 +237,11 @@ public class TrackDataHub {
|
|||||||
*/
|
*/
|
||||||
public void start() {
|
public void start() {
|
||||||
Log.i(TAG, "TrackDataHub.start");
|
Log.i(TAG, "TrackDataHub.start");
|
||||||
if (startedInstance != null) {
|
if (isStarted()) {
|
||||||
Log.w(TAG, "Already started, ignoring");
|
Log.w(TAG, "Already started, ignoring");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
startedInstance = this;
|
started = true;
|
||||||
|
|
||||||
listenerHandlerThread = new HandlerThread("trackDataContentThread");
|
listenerHandlerThread = new HandlerThread("trackDataContentThread");
|
||||||
listenerHandlerThread.start();
|
listenerHandlerThread.start();
|
||||||
@@ -266,20 +263,6 @@ public class TrackDataHub {
|
|||||||
return new DataSourcesWrapperImpl(context, preferences);
|
return new DataSourcesWrapperImpl(context, preferences);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* If there's an instance for which {@link start} has been called, returns it.
|
|
||||||
*
|
|
||||||
* @return the started instance
|
|
||||||
* @throws IllegalStateException if there isn't a started instance
|
|
||||||
*/
|
|
||||||
public static TrackDataHub getStartedInstance() {
|
|
||||||
if (startedInstance == null) {
|
|
||||||
throw new IllegalStateException("Data hub not started");
|
|
||||||
}
|
|
||||||
|
|
||||||
return startedInstance;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stops listening to data sources and reporting the data to external
|
* Stops listening to data sources and reporting the data to external
|
||||||
* listeners.
|
* listeners.
|
||||||
@@ -295,7 +278,7 @@ public class TrackDataHub {
|
|||||||
dataSourceManager.unregisterAllListeners();
|
dataSourceManager.unregisterAllListeners();
|
||||||
listenerHandlerThread.getLooper().quit();
|
listenerHandlerThread.getLooper().quit();
|
||||||
|
|
||||||
startedInstance = null;
|
started = false;
|
||||||
|
|
||||||
dataSources = null;
|
dataSources = null;
|
||||||
dataSourceManager = null;
|
dataSourceManager = null;
|
||||||
@@ -304,7 +287,7 @@ public class TrackDataHub {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean isStarted() {
|
private boolean isStarted() {
|
||||||
return startedInstance != null;
|
return started;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -415,7 +398,7 @@ public class TrackDataHub {
|
|||||||
|
|
||||||
// Save the selection to memory and flush.
|
// Save the selection to memory and flush.
|
||||||
selectedTrackId = trackId;
|
selectedTrackId = trackId;
|
||||||
ApiFeatures.getInstance().getApiPlatformAdapter().applyPreferenceChanges(
|
ApiFeatures.getInstance().getApiAdapter().applyPreferenceChanges(
|
||||||
preferences.edit().putLong(SELECTED_TRACK_KEY, trackId));
|
preferences.edit().putLong(SELECTED_TRACK_KEY, trackId));
|
||||||
|
|
||||||
// Force it to reload data from the beginning.
|
// Force it to reload data from the beginning.
|
||||||
|
|||||||
@@ -26,20 +26,21 @@ import com.google.android.apps.mytracks.io.gdata.GDataWrapper;
|
|||||||
import com.google.android.apps.mytracks.io.gdata.GDataWrapper.QueryFunction;
|
import com.google.android.apps.mytracks.io.gdata.GDataWrapper.QueryFunction;
|
||||||
import com.google.android.apps.mytracks.stats.DoubleBuffer;
|
import com.google.android.apps.mytracks.stats.DoubleBuffer;
|
||||||
import com.google.android.apps.mytracks.stats.TripStatistics;
|
import com.google.android.apps.mytracks.stats.TripStatistics;
|
||||||
|
import com.google.android.apps.mytracks.util.ApiFeatures;
|
||||||
import com.google.android.apps.mytracks.util.LocationUtils;
|
import com.google.android.apps.mytracks.util.LocationUtils;
|
||||||
import com.google.android.apps.mytracks.util.StringUtils;
|
import com.google.android.apps.mytracks.util.StringUtils;
|
||||||
import com.google.android.apps.mytracks.util.SystemUtils;
|
import com.google.android.apps.mytracks.util.SystemUtils;
|
||||||
import com.google.android.apps.mytracks.util.UnitConversions;
|
import com.google.android.apps.mytracks.util.UnitConversions;
|
||||||
import com.google.android.maps.mytracks.R;
|
import com.google.android.maps.mytracks.R;
|
||||||
import com.google.api.client.googleapis.GoogleHeaders;
|
import com.google.api.client.googleapis.GoogleHeaders;
|
||||||
import com.google.api.client.googleapis.MethodOverrideIntercepter;
|
import com.google.api.client.googleapis.MethodOverride;
|
||||||
import com.google.api.client.http.GenericUrl;
|
import com.google.api.client.http.GenericUrl;
|
||||||
import com.google.api.client.http.HttpRequest;
|
import com.google.api.client.http.HttpRequest;
|
||||||
|
import com.google.api.client.http.HttpRequestFactory;
|
||||||
import com.google.api.client.http.HttpResponse;
|
import com.google.api.client.http.HttpResponse;
|
||||||
import com.google.api.client.http.HttpResponseException;
|
import com.google.api.client.http.HttpResponseException;
|
||||||
import com.google.api.client.http.HttpTransport;
|
import com.google.api.client.http.HttpTransport;
|
||||||
import com.google.api.client.http.InputStreamContent;
|
import com.google.api.client.http.InputStreamContent;
|
||||||
import com.google.api.client.javanet.NetHttpTransport;
|
|
||||||
import com.google.api.client.util.Strings;
|
import com.google.api.client.util.Strings;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
@@ -64,6 +65,8 @@ import java.util.Vector;
|
|||||||
*/
|
*/
|
||||||
public class SendToFusionTables implements Runnable {
|
public class SendToFusionTables implements Runnable {
|
||||||
|
|
||||||
|
private static final String CONTENT_TYPE = "application/x-www-form-urlencoded";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Listener invoked when sending to fusion tables completes.
|
* Listener invoked when sending to fusion tables completes.
|
||||||
*/
|
*/
|
||||||
@@ -118,22 +121,15 @@ public class SendToFusionTables implements Runnable {
|
|||||||
private int totalLocations;
|
private int totalLocations;
|
||||||
private int totalSegmentsUploaded;
|
private int totalSegmentsUploaded;
|
||||||
|
|
||||||
private HttpTransport transport;
|
private HttpRequestFactory httpRequestFactory;
|
||||||
private String tableId;
|
private String tableId;
|
||||||
|
|
||||||
private static String MARKER_TYPE_START = "large_green";
|
private static String MARKER_TYPE_START = "large_green";
|
||||||
private static String MARKER_TYPE_END = "large_red";
|
private static String MARKER_TYPE_END = "large_red";
|
||||||
private static String MARKER_TYPE_WAYPOINT = "large_yellow";
|
private static String MARKER_TYPE_WAYPOINT = "large_yellow";
|
||||||
|
|
||||||
static {
|
public SendToFusionTables(Activity context, AuthManager auth, long trackId,
|
||||||
// We manually assign the transport to avoid having HttpTransport try to
|
ProgressIndicator progressIndicator, OnSendCompletedListener onCompletion) {
|
||||||
// load it via reflection (which breaks due to ProGuard).
|
|
||||||
HttpTransport.setLowLevelHttpTransport(new NetHttpTransport());
|
|
||||||
}
|
|
||||||
|
|
||||||
public SendToFusionTables(Activity context, AuthManager auth,
|
|
||||||
long trackId, ProgressIndicator progressIndicator,
|
|
||||||
OnSendCompletedListener onCompletion) {
|
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.auth = auth;
|
this.auth = auth;
|
||||||
this.trackId = trackId;
|
this.trackId = trackId;
|
||||||
@@ -142,13 +138,8 @@ public class SendToFusionTables implements Runnable {
|
|||||||
this.stringUtils = new StringUtils(context);
|
this.stringUtils = new StringUtils(context);
|
||||||
this.providerUtils = MyTracksProviderUtils.Factory.get(context);
|
this.providerUtils = MyTracksProviderUtils.Factory.get(context);
|
||||||
|
|
||||||
GoogleHeaders headers = new GoogleHeaders();
|
HttpTransport transport = ApiFeatures.getInstance().getApiAdapter().getHttpTransport();
|
||||||
headers.setApplicationName("Google-MyTracks-" + SystemUtils.getMyTracksVersion(context));
|
httpRequestFactory = transport.createRequestFactory(new MethodOverride());
|
||||||
headers.gdataVersion = GDATA_VERSION;
|
|
||||||
|
|
||||||
transport = new HttpTransport();
|
|
||||||
MethodOverrideIntercepter.setAsFirstFor(transport);
|
|
||||||
transport.defaultHeaders = headers;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -177,7 +168,6 @@ public class SendToFusionTables implements Runnable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void doUpload() {
|
private void doUpload() {
|
||||||
((GoogleHeaders) transport.defaultHeaders).setGoogleLogin(auth.getAuthToken());
|
|
||||||
int statusMessageId = R.string.error_sending_to_fusiontables;
|
int statusMessageId = R.string.error_sending_to_fusiontables;
|
||||||
boolean success = true;
|
boolean success = true;
|
||||||
try {
|
try {
|
||||||
@@ -280,7 +270,7 @@ public class SendToFusionTables implements Runnable {
|
|||||||
*
|
*
|
||||||
* @param name the marker name
|
* @param name the marker name
|
||||||
* @param description the marker description
|
* @param description the marker description
|
||||||
* @param the marker location
|
* @param location the marker location
|
||||||
* @return true in case of success.
|
* @return true in case of success.
|
||||||
*/
|
*/
|
||||||
private boolean createNewPoint(String name, String description, Location location,
|
private boolean createNewPoint(String name, String description, Location location,
|
||||||
@@ -306,7 +296,6 @@ public class SendToFusionTables implements Runnable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean uploadAllTrackPoints(final Track track, String originalDescription) {
|
private boolean uploadAllTrackPoints(final Track track, String originalDescription) {
|
||||||
|
|
||||||
SharedPreferences preferences = context.getSharedPreferences(Constants.SETTINGS_NAME, 0);
|
SharedPreferences preferences = context.getSharedPreferences(Constants.SETTINGS_NAME, 0);
|
||||||
boolean metricUnits = true;
|
boolean metricUnits = true;
|
||||||
if (preferences != null) {
|
if (preferences != null) {
|
||||||
@@ -440,10 +429,10 @@ public class SendToFusionTables implements Runnable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a KML Point tag for the given location.
|
* Returns a KML LineString.
|
||||||
*
|
*
|
||||||
* @param location The location.
|
* @param track the track.
|
||||||
* @return the kml.
|
* @return the KML LineString.
|
||||||
*/
|
*/
|
||||||
private String getKmlLineString(Track track) {
|
private String getKmlLineString(Track track) {
|
||||||
StringBuilder builder = new StringBuilder("<LineString><coordinates>");
|
StringBuilder builder = new StringBuilder("<LineString><coordinates>");
|
||||||
@@ -500,7 +489,7 @@ public class SendToFusionTables implements Runnable {
|
|||||||
* Prepares a buffer of locations for transmission to google fusion tables.
|
* Prepares a buffer of locations for transmission to google fusion tables.
|
||||||
*
|
*
|
||||||
* @param track the original track with meta data
|
* @param track the original track with meta data
|
||||||
* @param buffer a buffer of locations on the track
|
* @param locations locations on the track
|
||||||
* @return an array of tracks each with a sub section of the points in the
|
* @return an array of tracks each with a sub section of the points in the
|
||||||
* original buffer
|
* original buffer
|
||||||
*/
|
*/
|
||||||
@@ -665,33 +654,40 @@ public class SendToFusionTables implements Runnable {
|
|||||||
* @return true in case of success
|
* @return true in case of success
|
||||||
*/
|
*/
|
||||||
private boolean runUpdate(final String query) {
|
private boolean runUpdate(final String query) {
|
||||||
GDataWrapper<HttpTransport> wrapper = new GDataWrapper<HttpTransport>();
|
GDataWrapper<HttpRequestFactory> wrapper = new GDataWrapper<HttpRequestFactory>();
|
||||||
wrapper.setAuthManager(auth);
|
wrapper.setAuthManager(auth);
|
||||||
wrapper.setRetryOnAuthFailure(true);
|
wrapper.setRetryOnAuthFailure(true);
|
||||||
wrapper.setClient(transport);
|
wrapper.setClient(httpRequestFactory);
|
||||||
Log.d(Constants.TAG, "GData connection prepared: " + this.auth);
|
Log.d(Constants.TAG, "GData connection prepared: " + this.auth);
|
||||||
wrapper.runQuery(new QueryFunction<HttpTransport>() {
|
wrapper.runQuery(new QueryFunction<HttpRequestFactory>() {
|
||||||
@Override
|
@Override
|
||||||
public void query(HttpTransport client)
|
public void query(HttpRequestFactory factory)
|
||||||
throws IOException, GDataWrapper.ParseException, GDataWrapper.HttpException,
|
throws IOException, GDataWrapper.ParseException, GDataWrapper.HttpException,
|
||||||
GDataWrapper.AuthenticationException {
|
GDataWrapper.AuthenticationException {
|
||||||
HttpRequest request = transport.buildPostRequest();
|
|
||||||
request.headers.contentType = "application/x-www-form-urlencoded";
|
|
||||||
GenericUrl url = new GenericUrl(FUSIONTABLES_BASE_FEED_URL);
|
GenericUrl url = new GenericUrl(FUSIONTABLES_BASE_FEED_URL);
|
||||||
request.url = url;
|
|
||||||
InputStreamContent isc = new InputStreamContent();
|
|
||||||
String sql = "sql=" + URLEncoder.encode(query, "UTF-8");
|
String sql = "sql=" + URLEncoder.encode(query, "UTF-8");
|
||||||
isc.inputStream = new ByteArrayInputStream(Strings.toBytesUtf8(sql));
|
ByteArrayInputStream inputStream = new ByteArrayInputStream(Strings.toBytesUtf8(sql));
|
||||||
request.content = isc;
|
InputStreamContent isc = new InputStreamContent(null, inputStream );
|
||||||
|
|
||||||
|
HttpRequest request = factory.buildPostRequest(url, isc);
|
||||||
|
|
||||||
|
GoogleHeaders headers = new GoogleHeaders();
|
||||||
|
headers.setApplicationName("Google-MyTracks-" + SystemUtils.getMyTracksVersion(context));
|
||||||
|
headers.gdataVersion = GDATA_VERSION;
|
||||||
|
headers.setGoogleLogin(auth.getAuthToken());
|
||||||
|
headers.setContentType(CONTENT_TYPE);
|
||||||
|
request.setHeaders(headers);
|
||||||
|
|
||||||
Log.d(Constants.TAG, "Running update query " + url.toString() + ": " + sql);
|
Log.d(Constants.TAG, "Running update query " + url.toString() + ": " + sql);
|
||||||
HttpResponse response;
|
HttpResponse response;
|
||||||
try {
|
try {
|
||||||
response = request.execute();
|
response = request.execute();
|
||||||
} catch (HttpResponseException e) {
|
} catch (HttpResponseException e) {
|
||||||
throw new GDataWrapper.HttpException(e.response.statusCode, e.response.statusMessage);
|
throw new GDataWrapper.HttpException(e.getResponse().getStatusCode(),
|
||||||
|
e.getResponse().getStatusMessage());
|
||||||
}
|
}
|
||||||
boolean success = response.isSuccessStatusCode;
|
boolean success = response.isSuccessStatusCode();
|
||||||
if (success) {
|
if (success) {
|
||||||
byte[] result = new byte[1024];
|
byte[] result = new byte[1024];
|
||||||
int read = response.getContent().read(result);
|
int read = response.getContent().read(result);
|
||||||
@@ -704,9 +700,11 @@ public class SendToFusionTables implements Runnable {
|
|||||||
Log.w(Constants.TAG, "Unrecognized response: " + lines[0]);
|
Log.w(Constants.TAG, "Unrecognized response: " + lines[0]);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Log.d(Constants.TAG, "Query failed: " + response.statusMessage + " (" +
|
Log.d(Constants.TAG,
|
||||||
response.statusCode + ")");
|
"Query failed: " + response.getStatusMessage() + " ("
|
||||||
throw new GDataWrapper.HttpException(response.statusCode, response.statusMessage);
|
+ response.getStatusCode() + ")");
|
||||||
|
throw new GDataWrapper.HttpException(
|
||||||
|
response.getStatusCode(), response.getStatusMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
+1
-51
@@ -15,63 +15,13 @@
|
|||||||
*/
|
*/
|
||||||
package com.google.android.apps.mytracks.io.backup;
|
package com.google.android.apps.mytracks.io.backup;
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.util.ApiFeatures;
|
|
||||||
|
|
||||||
import android.app.backup.BackupManager;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.SharedPreferences;
|
|
||||||
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
|
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shared preferences listener which notifies the backup system about new data
|
* Shared preferences listener which notifies the backup system about new data
|
||||||
* being available for backup.
|
* being available for backup.
|
||||||
* This class is API-version-safe and will provide a dummy implementation if
|
|
||||||
* the device doesn't support backup services.
|
|
||||||
*
|
*
|
||||||
* @author Rodrigo Damazio
|
* @author Rodrigo Damazio
|
||||||
*/
|
*/
|
||||||
public abstract class BackupPreferencesListener
|
public interface BackupPreferencesListener extends OnSharedPreferenceChangeListener {
|
||||||
implements OnSharedPreferenceChangeListener {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Real implementation of the listener, which calls the {@link BackupManager}.
|
|
||||||
*/
|
|
||||||
private static class BackupPreferencesListenerImpl
|
|
||||||
extends BackupPreferencesListener {
|
|
||||||
private final BackupManager backupManager;
|
|
||||||
|
|
||||||
public BackupPreferencesListenerImpl(Context context) {
|
|
||||||
this.backupManager = new BackupManager(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onSharedPreferenceChanged(
|
|
||||||
SharedPreferences sharedPreferences, String key) {
|
|
||||||
backupManager.dataChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Dummy implementation of the listener which does nothing.
|
|
||||||
*/
|
|
||||||
private static class DummyBackupPreferencesListener
|
|
||||||
extends BackupPreferencesListener {
|
|
||||||
@Override
|
|
||||||
public void onSharedPreferenceChanged(
|
|
||||||
SharedPreferences sharedPreferences, String key) {
|
|
||||||
// Do nothing
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates and returns a proper instance of the listener for this device.
|
|
||||||
*/
|
|
||||||
public static BackupPreferencesListener create(
|
|
||||||
Context context, ApiFeatures apiFeatures) {
|
|
||||||
if (apiFeatures.hasBackup()) {
|
|
||||||
return new BackupPreferencesListenerImpl(context);
|
|
||||||
} else {
|
|
||||||
return new DummyBackupPreferencesListener();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
+40
@@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011 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 android.app.backup.BackupManager;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation of {@link BackupPreferencesListener} that calls the
|
||||||
|
* {@link BackupManager}.
|
||||||
|
*
|
||||||
|
* @author Jimmy Shih
|
||||||
|
*/
|
||||||
|
public class BackupPreferencesListenerImpl implements BackupPreferencesListener {
|
||||||
|
|
||||||
|
private final BackupManager backupManager;
|
||||||
|
|
||||||
|
public BackupPreferencesListenerImpl(Context context) {
|
||||||
|
this.backupManager = new BackupManager(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
|
||||||
|
backupManager.dataChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -34,6 +34,7 @@ import com.google.wireless.gdata.parser.ParseException;
|
|||||||
import com.google.wireless.gdata2.client.AuthenticationException;
|
import com.google.wireless.gdata2.client.AuthenticationException;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.text.format.DateFormat;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
@@ -44,7 +45,6 @@ import java.io.OutputStream;
|
|||||||
import java.io.OutputStreamWriter;
|
import java.io.OutputStreamWriter;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.net.URLConnection;
|
import java.net.URLConnection;
|
||||||
import java.text.DateFormat;
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
@@ -287,13 +287,16 @@ public class DocsHelper {
|
|||||||
String elevationUnit = context.getString(metricUnits ?
|
String elevationUnit = context.getString(metricUnits ?
|
||||||
R.string.meter : R.string.feet);
|
R.string.meter : R.string.feet);
|
||||||
|
|
||||||
DateFormat trackDateFormat = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT);
|
java.text.DateFormat dateFormat = DateFormat.getDateFormat(context);
|
||||||
|
java.text.DateFormat timeFormat = DateFormat.getTimeFormat(context);
|
||||||
|
Date startTime = new Date(stats.getStartTime());
|
||||||
|
String dateString = dateFormat.format(startTime) + " " + timeFormat.format(startTime);
|
||||||
|
|
||||||
// Prepare the Post-Text we are going to send.
|
// Prepare the Post-Text we are going to send.
|
||||||
DocsTagBuilder tagBuilder = new DocsTagBuilder(metricUnits)
|
DocsTagBuilder tagBuilder = new DocsTagBuilder(metricUnits)
|
||||||
.append("name", track.getName())
|
.append("name", track.getName())
|
||||||
.append("description", track.getDescription())
|
.append("description", track.getDescription())
|
||||||
.append("date", trackDateFormat.format(new Date(stats.getStartTime())))
|
.append("date", dateString)
|
||||||
.append("totaltime", StringUtils.formatTimeAlwaysShowingHours(
|
.append("totaltime", StringUtils.formatTimeAlwaysShowingHours(
|
||||||
stats.getTotalTime()))
|
stats.getTotalTime()))
|
||||||
.append("movingtime", StringUtils.formatTimeAlwaysShowingHours(
|
.append("movingtime", StringUtils.formatTimeAlwaysShowingHours(
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
package com.google.android.apps.mytracks.io.docs;
|
package com.google.android.apps.mytracks.io.docs;
|
||||||
|
|
||||||
|
import com.google.android.apps.mytracks.util.ApiFeatures;
|
||||||
import com.google.android.apps.mytracks.util.StringUtils;
|
import com.google.android.apps.mytracks.util.StringUtils;
|
||||||
import com.google.android.apps.mytracks.util.UnitConversions;
|
import com.google.android.apps.mytracks.util.UnitConversions;
|
||||||
|
|
||||||
@@ -45,8 +46,9 @@ import java.util.Locale;
|
|||||||
* @author Matthew Simmons
|
* @author Matthew Simmons
|
||||||
*/
|
*/
|
||||||
class DocsTagBuilder {
|
class DocsTagBuilder {
|
||||||
|
|
||||||
private static final DecimalFormatSymbols FORMAT_SYMBOLS =
|
private static final DecimalFormatSymbols FORMAT_SYMBOLS =
|
||||||
DecimalFormatSymbols.getInstance(Locale.ENGLISH);
|
ApiFeatures.getInstance().getApiAdapter().getDecimalFormatSymbols(Locale.ENGLISH);
|
||||||
private static final NumberFormat LARGE_UNIT_FORMAT =
|
private static final NumberFormat LARGE_UNIT_FORMAT =
|
||||||
new DecimalFormat("#,###,###.00", FORMAT_SYMBOLS);
|
new DecimalFormat("#,###,###.00", FORMAT_SYMBOLS);
|
||||||
private static final NumberFormat SMALL_UNIT_FORMAT =
|
private static final NumberFormat SMALL_UNIT_FORMAT =
|
||||||
|
|||||||
@@ -71,6 +71,11 @@ class WriteProgressController {
|
|||||||
this.onCompletionListener = onCompletionListener;
|
this.onCompletionListener = onCompletionListener;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// For testing purpose
|
||||||
|
OnCompletionListener getOnCompletionListener() {
|
||||||
|
return onCompletionListener;
|
||||||
|
}
|
||||||
|
|
||||||
public ProgressDialog createProgressDialog() {
|
public ProgressDialog createProgressDialog() {
|
||||||
dialog = new ProgressDialog(activity);
|
dialog = new ProgressDialog(activity);
|
||||||
dialog.setIcon(android.R.drawable.ic_dialog_info);
|
dialog.setIcon(android.R.drawable.ic_dialog_info);
|
||||||
|
|||||||
+129
@@ -0,0 +1,129 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011 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.maps;
|
||||||
|
|
||||||
|
import static com.google.android.apps.mytracks.Constants.TAG;
|
||||||
|
|
||||||
|
import com.google.android.apps.mytracks.Constants;
|
||||||
|
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
|
||||||
|
import com.google.android.apps.mytracks.content.Track;
|
||||||
|
import com.google.android.apps.mytracks.stats.TripStatistics;
|
||||||
|
import com.google.android.maps.mytracks.R;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A dynamic speed path descriptor.
|
||||||
|
*
|
||||||
|
* @author Vangelis S.
|
||||||
|
*/
|
||||||
|
public class DynamicSpeedTrackPathDescriptor
|
||||||
|
implements TrackPathDescriptor, OnSharedPreferenceChangeListener {
|
||||||
|
private int slowSpeed;
|
||||||
|
private int normalSpeed;
|
||||||
|
private int speedMargin;
|
||||||
|
private double averageMovingSpeed;
|
||||||
|
private final Context context;
|
||||||
|
|
||||||
|
public DynamicSpeedTrackPathDescriptor(Context context){
|
||||||
|
this.context = context;
|
||||||
|
SharedPreferences prefs = context.getSharedPreferences(Constants.SETTINGS_NAME, 0);
|
||||||
|
|
||||||
|
if (prefs == null) {
|
||||||
|
speedMargin = 25;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
prefs.registerOnSharedPreferenceChangeListener(this);
|
||||||
|
|
||||||
|
speedMargin = Integer.parseInt(prefs.getString(
|
||||||
|
context.getString(R.string.track_color_mode_dynamic_speed_variation_key), "25"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the slow speed calculated based on the % below the average speed.
|
||||||
|
* @return The speed limit considered as slow.
|
||||||
|
*/
|
||||||
|
public int getSlowSpeed()
|
||||||
|
{
|
||||||
|
slowSpeed = (int) (averageMovingSpeed - (averageMovingSpeed * speedMargin / 100));
|
||||||
|
return slowSpeed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the medium speed calculated based on the % above the average speed.
|
||||||
|
* @return The speed limit considered as normal.
|
||||||
|
*/
|
||||||
|
public int getNormalSpeed()
|
||||||
|
{
|
||||||
|
normalSpeed = (int) (averageMovingSpeed + (averageMovingSpeed * speedMargin / 100));
|
||||||
|
return normalSpeed;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
|
||||||
|
Log.d(TAG, "DynamicSpeedTrackPathDescriptor: onSharedPreferences changed " + key);
|
||||||
|
if (key == null
|
||||||
|
|| !key.equals(context.getString(R.string.track_color_mode_dynamic_speed_variation_key))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
SharedPreferences prefs = context.getSharedPreferences(Constants.SETTINGS_NAME, 0);
|
||||||
|
|
||||||
|
if (prefs == null) {
|
||||||
|
speedMargin = 25;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
speedMargin =
|
||||||
|
Integer.parseInt(
|
||||||
|
prefs.getString(
|
||||||
|
context.getString(R.string.track_color_mode_dynamic_speed_variation_key), "25"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean needsRedraw() {
|
||||||
|
SharedPreferences prefs = context.getSharedPreferences(Constants.SETTINGS_NAME, 0);
|
||||||
|
long currentTrackId = prefs.getLong(context.getString(R.string.selected_track_key), -1);
|
||||||
|
if(currentTrackId == -1) {
|
||||||
|
// Could not find track.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Track track = MyTracksProviderUtils.Factory.get(context).getTrack(currentTrackId);
|
||||||
|
TripStatistics stats = track.getStatistics();
|
||||||
|
double newaverageSpeed = (int) Math.floor(stats.getAverageMovingSpeed() * 3.6);
|
||||||
|
|
||||||
|
if(averageMovingSpeed == 0) {
|
||||||
|
averageMovingSpeed = newaverageSpeed;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
double difference = Math.max(averageMovingSpeed, newaverageSpeed);
|
||||||
|
|
||||||
|
if (difference == 0.0) {
|
||||||
|
difference = 0.0;
|
||||||
|
} else {
|
||||||
|
difference = Math.abs(averageMovingSpeed - newaverageSpeed) / difference * 100;
|
||||||
|
}
|
||||||
|
if(difference >= 20) {
|
||||||
|
averageMovingSpeed = newaverageSpeed;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,141 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011 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.maps;
|
||||||
|
|
||||||
|
import com.google.android.apps.mytracks.ColoredPath;
|
||||||
|
import com.google.android.apps.mytracks.MapOverlay.CachedLocation;
|
||||||
|
import com.google.android.maps.GeoPoint;
|
||||||
|
import com.google.android.maps.Projection;
|
||||||
|
import com.google.android.maps.mytracks.R;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.graphics.Canvas;
|
||||||
|
import android.graphics.Paint;
|
||||||
|
import android.graphics.Path;
|
||||||
|
import android.graphics.Point;
|
||||||
|
import android.graphics.Rect;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A path painter that varies the path colors based on fixed speeds or average speed margin
|
||||||
|
* depending of the TrackPathDescriptor passed to its constructor.
|
||||||
|
*
|
||||||
|
* @author Vangelis S.
|
||||||
|
*/
|
||||||
|
public class DynamicSpeedTrackPathPainter implements TrackPathPainter {
|
||||||
|
private final Paint selectedTrackPaintSlow;
|
||||||
|
private final Paint selectedTrackPaintMedium;
|
||||||
|
private final Paint selectedTrackPaintFast;
|
||||||
|
private final List<ColoredPath> coloredPaths;
|
||||||
|
private final TrackPathDescriptor trackPathDescriptor;
|
||||||
|
private int slowSpeed;
|
||||||
|
private int normalSpeed;
|
||||||
|
|
||||||
|
public DynamicSpeedTrackPathPainter (Context context, TrackPathDescriptor trackPathDescriptor) {
|
||||||
|
this.trackPathDescriptor = trackPathDescriptor;
|
||||||
|
|
||||||
|
selectedTrackPaintSlow = TrackPathUtilities.getPaint(R.color.slow_path, context);
|
||||||
|
selectedTrackPaintMedium = TrackPathUtilities.getPaint(R.color.normal_path, context);
|
||||||
|
selectedTrackPaintFast = TrackPathUtilities.getPaint(R.color.fast_path, context);
|
||||||
|
|
||||||
|
this.coloredPaths = new ArrayList<ColoredPath>();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void drawTrack(Canvas canvas) {
|
||||||
|
for(int i = 0; i < coloredPaths.size(); ++i) {
|
||||||
|
ColoredPath coloredPath = coloredPaths.get(i);
|
||||||
|
canvas.drawPath(coloredPath.getPath(), coloredPath.getPathPaint());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updatePath(Projection projection, Rect viewRect, int startLocationIdx,
|
||||||
|
Boolean alwaysVisible, List<CachedLocation> points) {
|
||||||
|
// Whether to start a new segment on new valid and visible point.
|
||||||
|
boolean newSegment = startLocationIdx <= 0 || !points.get(startLocationIdx - 1).valid;
|
||||||
|
boolean lastVisible = !newSegment;
|
||||||
|
final Point pt = new Point();
|
||||||
|
|
||||||
|
clear();
|
||||||
|
|
||||||
|
slowSpeed = trackPathDescriptor.getSlowSpeed();
|
||||||
|
normalSpeed = trackPathDescriptor.getNormalSpeed();
|
||||||
|
|
||||||
|
// Loop over track points.
|
||||||
|
for (int i = startLocationIdx; i < points.size(); ++i) {
|
||||||
|
CachedLocation loc = points.get(i);
|
||||||
|
|
||||||
|
// Check if valid, if not then indicate a new segment.
|
||||||
|
if (!loc.valid) {
|
||||||
|
newSegment = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
final GeoPoint geoPoint = loc.geoPoint;
|
||||||
|
// Check if this breaks the existing segment.
|
||||||
|
boolean visible = alwaysVisible || viewRect.contains(
|
||||||
|
geoPoint.getLongitudeE6(), geoPoint.getLatitudeE6());
|
||||||
|
if (!visible && !lastVisible) {
|
||||||
|
// This is a point outside view not connected to a visible one.
|
||||||
|
newSegment = true;
|
||||||
|
}
|
||||||
|
lastVisible = visible;
|
||||||
|
|
||||||
|
// Either move to beginning of a new segment or continue the old one.
|
||||||
|
if (newSegment) {
|
||||||
|
projection.toPixels(geoPoint, pt);
|
||||||
|
newSegment = false;
|
||||||
|
} else {
|
||||||
|
ColoredPath coloredPath;
|
||||||
|
if(loc.speed <= slowSpeed) {
|
||||||
|
coloredPath = new ColoredPath(selectedTrackPaintSlow);
|
||||||
|
}
|
||||||
|
else if(loc.speed <= normalSpeed) {
|
||||||
|
coloredPath = new ColoredPath(selectedTrackPaintMedium);
|
||||||
|
} else {
|
||||||
|
coloredPath = new ColoredPath(selectedTrackPaintFast);
|
||||||
|
}
|
||||||
|
coloredPath.getPath().moveTo(pt.x, pt.y);
|
||||||
|
projection.toPixels(geoPoint, pt);
|
||||||
|
coloredPath.getPath().lineTo(pt.x, pt.y);
|
||||||
|
coloredPaths.add(coloredPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clear()
|
||||||
|
{
|
||||||
|
coloredPaths.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean needsRedraw() {
|
||||||
|
return trackPathDescriptor.needsRedraw();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Path getLastPath() {
|
||||||
|
Path path = new Path();
|
||||||
|
for(int i = 0; i < coloredPaths.size(); ++i) {
|
||||||
|
path.addPath(coloredPaths.get(i).getPath());
|
||||||
|
}
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
}
|
||||||
+115
@@ -0,0 +1,115 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011 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.maps;
|
||||||
|
|
||||||
|
import static com.google.android.apps.mytracks.Constants.TAG;
|
||||||
|
|
||||||
|
import com.google.android.apps.mytracks.Constants;
|
||||||
|
import com.google.android.maps.mytracks.R;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A fixed speed path descriptor.
|
||||||
|
*
|
||||||
|
* @author Vangelis S.
|
||||||
|
*/
|
||||||
|
public class FixedSpeedTrackPathDescriptor implements TrackPathDescriptor, OnSharedPreferenceChangeListener {
|
||||||
|
private int slowSpeed;
|
||||||
|
private int normalSpeed;
|
||||||
|
private final Context context;
|
||||||
|
|
||||||
|
public FixedSpeedTrackPathDescriptor(Context context) {
|
||||||
|
|
||||||
|
this.context = context;
|
||||||
|
context.getSharedPreferences(Constants.SETTINGS_NAME, 0)
|
||||||
|
.registerOnSharedPreferenceChangeListener(this);
|
||||||
|
|
||||||
|
SharedPreferences prefs = context.getSharedPreferences(Constants.SETTINGS_NAME, 0);
|
||||||
|
if (prefs == null) {
|
||||||
|
slowSpeed = 9;
|
||||||
|
normalSpeed = 17;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
slowSpeed = Integer.parseInt(prefs.getString(context.getString(
|
||||||
|
R.string.track_color_mode_fixed_speed_slow_key), "9"));
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
slowSpeed = 9;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
normalSpeed = Integer.parseInt(prefs.getString(context.getString(
|
||||||
|
R.string.track_color_mode_fixed_speed_medium_key), "17"));
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
normalSpeed = 17;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the slow speed for reference.
|
||||||
|
* @return The speed limit considered as slow.
|
||||||
|
*/
|
||||||
|
public int getSlowSpeed() {
|
||||||
|
return slowSpeed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the normal speed for reference.
|
||||||
|
* @return The speed limit considered as normal.
|
||||||
|
*/
|
||||||
|
public int getNormalSpeed() {
|
||||||
|
return normalSpeed;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
|
||||||
|
Log.d(TAG, "FixedSpeedTrackPathDescriptor: onSharedPreferences changed " + key);
|
||||||
|
if (key == null
|
||||||
|
|| (!key.equals(context.getString(R.string.track_color_mode_fixed_speed_slow_key))
|
||||||
|
&& !key.equals(context.getString(R.string.track_color_mode_fixed_speed_medium_key)))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
SharedPreferences prefs = context.getSharedPreferences(Constants.SETTINGS_NAME, 0);
|
||||||
|
if (prefs == null) {
|
||||||
|
slowSpeed = 9;
|
||||||
|
normalSpeed = 17;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
slowSpeed = Integer.parseInt(prefs.getString(context.getString(
|
||||||
|
R.string.track_color_mode_fixed_speed_slow_key), "9"));
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
slowSpeed = 9;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
normalSpeed = Integer.parseInt(prefs.getString(context.getString(
|
||||||
|
R.string.track_color_mode_fixed_speed_medium_key), "17"));
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
normalSpeed = 17;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean needsRedraw() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,112 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011 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.maps;
|
||||||
|
|
||||||
|
import com.google.android.apps.mytracks.MapOverlay.CachedLocation;
|
||||||
|
import com.google.android.maps.GeoPoint;
|
||||||
|
import com.google.android.maps.Projection;
|
||||||
|
import com.google.android.maps.mytracks.R;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.graphics.Canvas;
|
||||||
|
import android.graphics.Paint;
|
||||||
|
import android.graphics.Path;
|
||||||
|
import android.graphics.Point;
|
||||||
|
import android.graphics.Rect;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A path painter that not variates the path colors.
|
||||||
|
*
|
||||||
|
* @author Vangelis S.
|
||||||
|
*/
|
||||||
|
public class SingleColorTrackPathPainter implements TrackPathPainter {
|
||||||
|
private final Paint selectedTrackPaint;
|
||||||
|
private Path path;
|
||||||
|
|
||||||
|
public SingleColorTrackPathPainter(Context context) {
|
||||||
|
selectedTrackPaint = TrackPathUtilities.getPaint(R.color.red, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void drawTrack(Canvas canvas) {
|
||||||
|
canvas.drawPath(path, selectedTrackPaint);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updatePath(Projection projection, Rect viewRect, int startLocationIdx,
|
||||||
|
Boolean alwaysVisible, List<CachedLocation> points) {
|
||||||
|
// Whether to start a new segment on new valid and visible point.
|
||||||
|
boolean newSegment = startLocationIdx <= 0 || !points.get(startLocationIdx - 1).valid;
|
||||||
|
boolean lastVisible = !newSegment;
|
||||||
|
final Point pt = new Point();
|
||||||
|
// Loop over track points.
|
||||||
|
int numPoints = points.size();
|
||||||
|
path = newPath();
|
||||||
|
path.incReserve(numPoints);
|
||||||
|
|
||||||
|
for (int i = startLocationIdx; i < numPoints ; ++i) {
|
||||||
|
CachedLocation loc = points.get(i);
|
||||||
|
|
||||||
|
// Check if valid, if not then indicate a new segment.
|
||||||
|
if (!loc.valid) {
|
||||||
|
newSegment = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
final GeoPoint geoPoint = loc.geoPoint;
|
||||||
|
// Check if this breaks the existing segment.
|
||||||
|
boolean visible = alwaysVisible
|
||||||
|
|| viewRect.contains(geoPoint.getLongitudeE6(), geoPoint.getLatitudeE6());
|
||||||
|
if (!visible && !lastVisible) {
|
||||||
|
// This is a point outside view not connected to a visible one.
|
||||||
|
newSegment = true;
|
||||||
|
}
|
||||||
|
lastVisible = visible;
|
||||||
|
|
||||||
|
// Either move to beginning of a new segment or continue the old one.
|
||||||
|
projection.toPixels(geoPoint, pt);
|
||||||
|
if (newSegment) {
|
||||||
|
path.moveTo(pt.x, pt.y);
|
||||||
|
newSegment = false;
|
||||||
|
} else {
|
||||||
|
path.lineTo(pt.x, pt.y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clear() {
|
||||||
|
path = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean needsRedraw() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Path getLastPath() {
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Visible for testing
|
||||||
|
public Path newPath() {
|
||||||
|
return new Path();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011 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.maps;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An interface for classes which describe how to draw a track path.
|
||||||
|
*
|
||||||
|
* @author Vangelis S.
|
||||||
|
*/
|
||||||
|
public interface TrackPathDescriptor {
|
||||||
|
/**
|
||||||
|
* @return The maximum speed which is considered slow.
|
||||||
|
*/
|
||||||
|
int getSlowSpeed();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The maximum speed which is considered normal.
|
||||||
|
*/
|
||||||
|
int getNormalSpeed();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return True if the path needs to be updated.
|
||||||
|
*/
|
||||||
|
boolean needsRedraw();
|
||||||
|
}
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011 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.maps;
|
||||||
|
|
||||||
|
import com.google.android.apps.mytracks.MapOverlay.CachedLocation;
|
||||||
|
import com.google.android.maps.Projection;
|
||||||
|
|
||||||
|
import android.graphics.Canvas;
|
||||||
|
import android.graphics.Path;
|
||||||
|
import android.graphics.Rect;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An interface for classes which paint the track path.
|
||||||
|
*
|
||||||
|
* @author Vangelis S.
|
||||||
|
*/
|
||||||
|
public interface TrackPathPainter {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears the related data.
|
||||||
|
*/
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draws the path to the canvas.
|
||||||
|
* @param canvas The Canvas to draw upon
|
||||||
|
*/
|
||||||
|
void drawTrack(Canvas canvas);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the path.
|
||||||
|
* @param projection The Canvas to draw upon.
|
||||||
|
* @param viewRect The Path to be drawn.
|
||||||
|
* @param startLocationIdx The start point from where update the path.
|
||||||
|
* @param alwaysVisible Flag for alwaysvisible.
|
||||||
|
* @param points The list of points used to update the path.
|
||||||
|
*/
|
||||||
|
void updatePath(Projection projection, Rect viewRect, int startLocationIdx,
|
||||||
|
Boolean alwaysVisible, List<CachedLocation> points);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return True if the path needs to be updated.
|
||||||
|
*/
|
||||||
|
boolean needsRedraw();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The path being used currently.
|
||||||
|
*/
|
||||||
|
Path getLastPath();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011 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.maps;
|
||||||
|
|
||||||
|
import static com.google.android.apps.mytracks.Constants.TAG;
|
||||||
|
|
||||||
|
import com.google.android.apps.mytracks.Constants;
|
||||||
|
import com.google.android.maps.mytracks.R;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A factory for TrackPathPainters.
|
||||||
|
*
|
||||||
|
* @author Vangelis S.
|
||||||
|
*/
|
||||||
|
public class TrackPathPainterFactory {
|
||||||
|
|
||||||
|
private TrackPathPainterFactory() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a new TrackPathPainter.
|
||||||
|
* @param context Context to fetch system preferences.
|
||||||
|
* @return The TrackPathPainter that corresponds to the track color mode setting.
|
||||||
|
*/
|
||||||
|
public static TrackPathPainter getTrackPathPainter(Context context) {
|
||||||
|
SharedPreferences prefs =
|
||||||
|
context.getSharedPreferences(Constants.SETTINGS_NAME, 0);
|
||||||
|
if (prefs == null) {
|
||||||
|
return new SingleColorTrackPathPainter(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
String colorMode = prefs.getString(context.getString(R.string.track_color_mode_key), null);
|
||||||
|
Log.i(TAG, "Creating track path painter of type: " + colorMode);
|
||||||
|
|
||||||
|
if (colorMode == null || colorMode.equals(context.getString(R.string.track_color_mode_none))) {
|
||||||
|
return new SingleColorTrackPathPainter(context);
|
||||||
|
} else if (colorMode.equals(context.getString(R.string.track_color_mode_fixed))) {
|
||||||
|
return new DynamicSpeedTrackPathPainter(context,
|
||||||
|
new FixedSpeedTrackPathDescriptor(context));
|
||||||
|
} else if (colorMode.equals(context.getString(R.string.track_color_mode_dynamic))) {
|
||||||
|
return new DynamicSpeedTrackPathPainter(context,
|
||||||
|
new DynamicSpeedTrackPathDescriptor(context));
|
||||||
|
} else {
|
||||||
|
Log.w(TAG, "Using default track path painter. Unrecognized painter: " + colorMode);
|
||||||
|
return new SingleColorTrackPathPainter(context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011 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.maps;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.graphics.Paint;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Various utility functions for TrackPath painting.
|
||||||
|
*
|
||||||
|
* @author Vangelis S.
|
||||||
|
*/
|
||||||
|
public class TrackPathUtilities {
|
||||||
|
|
||||||
|
public static Paint getPaint(int id, Context context) {
|
||||||
|
Paint paint = new Paint();
|
||||||
|
paint.setColor(context.getResources().getColor(id));
|
||||||
|
paint.setStrokeWidth(3);
|
||||||
|
paint.setStyle(Paint.Style.STROKE);
|
||||||
|
paint.setAntiAlias(true);
|
||||||
|
return paint;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,121 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011 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 static com.google.android.apps.mytracks.Constants.TAG;
|
||||||
|
|
||||||
|
import com.google.android.apps.mytracks.widgets.TrackWidgetProvider;
|
||||||
|
import com.google.android.maps.mytracks.R;
|
||||||
|
|
||||||
|
import android.app.IntentService;
|
||||||
|
import android.content.ComponentName;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.ServiceConnection;
|
||||||
|
import android.os.IBinder;
|
||||||
|
import android.os.RemoteException;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A service to control starting and stopping of a recording. This service,
|
||||||
|
* through the AndroidManifest.xml, is configured to only allow components of
|
||||||
|
* the same application to invoke it. Thus this service can be used my MyTracks
|
||||||
|
* app widget, {@link TrackWidgetProvider}, but not by other applications. This
|
||||||
|
* application delegates starting and stopping a recording to
|
||||||
|
* {@link TrackRecordingService} using RPC calls.
|
||||||
|
*
|
||||||
|
* @author jshih@google.com (Jimmy Shih)
|
||||||
|
*/
|
||||||
|
public class ControlRecordingService extends IntentService implements ServiceConnection {
|
||||||
|
|
||||||
|
private ITrackRecordingService trackRecordingService;
|
||||||
|
private boolean connected = false;
|
||||||
|
|
||||||
|
public ControlRecordingService() {
|
||||||
|
super(ControlRecordingService.class.getSimpleName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate() {
|
||||||
|
super.onCreate();
|
||||||
|
|
||||||
|
Intent newIntent = new Intent(this, TrackRecordingService.class);
|
||||||
|
startService(newIntent);
|
||||||
|
bindService(newIntent, this, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onServiceConnected(ComponentName name, IBinder service) {
|
||||||
|
trackRecordingService = ITrackRecordingService.Stub.asInterface(service);
|
||||||
|
notifyConnected();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onServiceDisconnected(ComponentName name) {
|
||||||
|
connected = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notifies all threads that connection to {@link TrackRecordingService} is
|
||||||
|
* available.
|
||||||
|
*/
|
||||||
|
private synchronized void notifyConnected() {
|
||||||
|
connected = true;
|
||||||
|
notifyAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Waits until the connection to {@link TrackRecordingService} is available.
|
||||||
|
*/
|
||||||
|
private synchronized void waitConnected() {
|
||||||
|
while (!connected) {
|
||||||
|
try {
|
||||||
|
wait();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
|
||||||
|
// can safely ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onHandleIntent(Intent intent) {
|
||||||
|
waitConnected();
|
||||||
|
String action = intent.getAction();
|
||||||
|
if (action != null) {
|
||||||
|
try {
|
||||||
|
if (action.equals(getString(R.string.start_new_track_action))) {
|
||||||
|
trackRecordingService.startNewTrack();
|
||||||
|
} else if (action.equals(getString(R.string.end_current_track_action))) {
|
||||||
|
trackRecordingService.endCurrentTrack();
|
||||||
|
}
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
Log.d(TAG, "ControlRecordingService onHandleIntent RemoteException", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unbindService(this);
|
||||||
|
connected = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDestroy() {
|
||||||
|
super.onDestroy();
|
||||||
|
if (connected) {
|
||||||
|
unbindService(this);
|
||||||
|
connected = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+106
-44
@@ -37,7 +37,7 @@ import com.google.android.apps.mytracks.services.tasks.StatusAnnouncerFactory;
|
|||||||
import com.google.android.apps.mytracks.stats.TripStatistics;
|
import com.google.android.apps.mytracks.stats.TripStatistics;
|
||||||
import com.google.android.apps.mytracks.stats.TripStatisticsBuilder;
|
import com.google.android.apps.mytracks.stats.TripStatisticsBuilder;
|
||||||
import com.google.android.apps.mytracks.util.ApiFeatures;
|
import com.google.android.apps.mytracks.util.ApiFeatures;
|
||||||
import com.google.android.apps.mytracks.util.ApiPlatformAdapter;
|
import com.google.android.apps.mytracks.util.ApiLevelAdapter;
|
||||||
import com.google.android.apps.mytracks.util.LocationUtils;
|
import com.google.android.apps.mytracks.util.LocationUtils;
|
||||||
import com.google.android.apps.mytracks.util.StringUtils;
|
import com.google.android.apps.mytracks.util.StringUtils;
|
||||||
import com.google.android.maps.mytracks.R;
|
import com.google.android.maps.mytracks.R;
|
||||||
@@ -56,11 +56,13 @@ import android.location.Location;
|
|||||||
import android.location.LocationListener;
|
import android.location.LocationListener;
|
||||||
import android.location.LocationManager;
|
import android.location.LocationManager;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
import android.os.Binder;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.os.PowerManager;
|
import android.os.PowerManager;
|
||||||
import android.os.PowerManager.WakeLock;
|
import android.os.PowerManager.WakeLock;
|
||||||
|
import android.os.Process;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import java.util.Timer;
|
import java.util.Timer;
|
||||||
@@ -153,6 +155,9 @@ public class TrackRecordingService extends Service {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onLocationChanged(final Location location) {
|
public void onLocationChanged(final Location location) {
|
||||||
|
if (executorService.isShutdown() || executorService.isTerminated()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
executorService.submit(
|
executorService.submit(
|
||||||
new Runnable() {
|
new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
@@ -226,6 +231,13 @@ public class TrackRecordingService extends Service {
|
|||||||
* Application lifetime events:
|
* Application lifetime events:
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Note that this service, through the AndroidManifest.xml, is configured to
|
||||||
|
* allow both MyTracks and third party apps to invoke it. For the onCreate
|
||||||
|
* callback, we cannot tell whether the caller is MyTracks or a third party
|
||||||
|
* app, thus it cannot start/stop a recording or write/update MyTracks
|
||||||
|
* database. However, it can resume a recording.
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void onCreate() {
|
public void onCreate() {
|
||||||
super.onCreate();
|
super.onCreate();
|
||||||
@@ -265,11 +277,25 @@ public class TrackRecordingService extends Service {
|
|||||||
showNotification();
|
showNotification();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Note that this service, through the AndroidManifest.xml, is configured to
|
||||||
|
* allow both MyTracks and third party apps to invoke it. For the onStart
|
||||||
|
* callback, we cannot tell whether the caller is MyTracks or a third party
|
||||||
|
* app, thus it cannot start/stop a recording or write/update MyTracks
|
||||||
|
* database. However, it can resume a recording.
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void onStart(Intent intent, int startId) {
|
public void onStart(Intent intent, int startId) {
|
||||||
handleStartCommand(intent, startId);
|
handleStartCommand(intent, startId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Note that this service, through the AndroidManifest.xml, is configured to
|
||||||
|
* allow both MyTracks and third party apps to invoke it. For the
|
||||||
|
* onStartCommand callback, we cannot tell whether the caller is MyTracks or a
|
||||||
|
* third party app, thus it cannot start/stop a recording or write/update
|
||||||
|
* MyTracks database. However, it can resume a recording.
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||||
handleStartCommand(intent, startId);
|
handleStartCommand(intent, startId);
|
||||||
@@ -277,28 +303,22 @@ public class TrackRecordingService extends Service {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void handleStartCommand(Intent intent, int startId) {
|
private void handleStartCommand(Intent intent, int startId) {
|
||||||
Log.d(TAG,
|
Log.d(TAG, "TrackRecordingService.handleStartCommand: " + startId);
|
||||||
"TrackRecordingService.handleStartCommand: " + startId);
|
|
||||||
|
if (intent == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Check if called on phone reboot with resume intent.
|
// Check if called on phone reboot with resume intent.
|
||||||
if (intent != null) {
|
if (intent.getBooleanExtra(RESUME_TRACK_EXTRA_NAME, false)) {
|
||||||
if (intent.getBooleanExtra(RESUME_TRACK_EXTRA_NAME, false)) {
|
resumeTrack(startId);
|
||||||
resumeTrack(startId);
|
|
||||||
} else {
|
|
||||||
// Process actions for controlling the service.
|
|
||||||
String action = intent.getAction();
|
|
||||||
if (getString(R.string.start_new_track_action).equals(action)) {
|
|
||||||
startNewTrack();
|
|
||||||
if (intent.getBooleanExtra(getString(R.string.select_new_track_extra), false)) {
|
|
||||||
prefManager.setSelectedTrack(recordingTrackId);
|
|
||||||
}
|
|
||||||
} else if (getString(R.string.end_current_track_action).equals(action)) {
|
|
||||||
endCurrentTrack();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isTrackInProgress() {
|
||||||
|
return recordingTrackId != -1 || isRecording;
|
||||||
|
}
|
||||||
|
|
||||||
private void resumeTrack(int startId) {
|
private void resumeTrack(int startId) {
|
||||||
Log.d(TAG, "TrackRecordingService: requested resume");
|
Log.d(TAG, "TrackRecordingService: requested resume");
|
||||||
|
|
||||||
@@ -342,7 +362,6 @@ public class TrackRecordingService extends Service {
|
|||||||
timer.purge();
|
timer.purge();
|
||||||
unregisterLocationListener();
|
unregisterLocationListener();
|
||||||
shutdownTaskExecutors();
|
shutdownTaskExecutors();
|
||||||
executorService.shutdown();
|
|
||||||
if (sensorManager != null) {
|
if (sensorManager != null) {
|
||||||
sensorManager.shutdown();
|
sensorManager.shutdown();
|
||||||
sensorManager = null;
|
sensorManager = null;
|
||||||
@@ -358,6 +377,8 @@ public class TrackRecordingService extends Service {
|
|||||||
// This should be the last operation.
|
// This should be the last operation.
|
||||||
releaseWakeLock();
|
releaseWakeLock();
|
||||||
|
|
||||||
|
// Shutdown the executor service last to avoid sending events to a dead executor.
|
||||||
|
executorService.shutdown();
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -464,8 +485,8 @@ public class TrackRecordingService extends Service {
|
|||||||
* Shows the notification message and icon in the notification bar.
|
* Shows the notification message and icon in the notification bar.
|
||||||
*/
|
*/
|
||||||
private void showNotification() {
|
private void showNotification() {
|
||||||
final ApiPlatformAdapter apiPlatformAdapter =
|
final ApiLevelAdapter apiLevelAdapter =
|
||||||
ApiFeatures.getInstance().getApiPlatformAdapter();
|
ApiFeatures.getInstance().getApiAdapter();
|
||||||
if (isRecording) {
|
if (isRecording) {
|
||||||
Notification notification = new Notification(
|
Notification notification = new Notification(
|
||||||
R.drawable.arrow_320, null /* tickerText */,
|
R.drawable.arrow_320, null /* tickerText */,
|
||||||
@@ -476,10 +497,10 @@ public class TrackRecordingService extends Service {
|
|||||||
notification.setLatestEventInfo(this, getString(R.string.app_name),
|
notification.setLatestEventInfo(this, getString(R.string.app_name),
|
||||||
getString(R.string.recording_your_track), contentIntent);
|
getString(R.string.recording_your_track), contentIntent);
|
||||||
notification.flags += Notification.FLAG_NO_CLEAR;
|
notification.flags += Notification.FLAG_NO_CLEAR;
|
||||||
apiPlatformAdapter.startForeground(this, notificationManager, 1,
|
apiLevelAdapter.startForeground(this, notificationManager, 1,
|
||||||
notification);
|
notification);
|
||||||
} else {
|
} else {
|
||||||
apiPlatformAdapter.stopForeground(this, notificationManager, 1);
|
apiLevelAdapter.stopForeground(this, notificationManager, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -543,10 +564,10 @@ public class TrackRecordingService extends Service {
|
|||||||
* Recording lifecycle.
|
* Recording lifecycle.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public long startNewTrack() {
|
private long startNewTrack() {
|
||||||
Log.d(TAG, "TrackRecordingService.startNewTrack");
|
Log.d(TAG, "TrackRecordingService.startNewTrack");
|
||||||
if (recordingTrackId != -1 || isRecording) {
|
if (isTrackInProgress()) {
|
||||||
throw new IllegalStateException("A track is already in progress!");
|
return -1L;
|
||||||
}
|
}
|
||||||
|
|
||||||
long startTime = System.currentTimeMillis();
|
long startTime = System.currentTimeMillis();
|
||||||
@@ -954,8 +975,7 @@ public class TrackRecordingService extends Service {
|
|||||||
* Build a statistics marker.
|
* Build a statistics marker.
|
||||||
* A statistics marker holds the stats for the* last segment up to this marker.
|
* A statistics marker holds the stats for the* last segment up to this marker.
|
||||||
*
|
*
|
||||||
* @param Waypoint The waypoint which will be populated with stats data.
|
* @param waypoint The waypoint which will be populated with stats data.
|
||||||
* @return the unique id of the inserted marker
|
|
||||||
*/
|
*/
|
||||||
private void buildStatisticsMarker(Waypoint waypoint) {
|
private void buildStatisticsMarker(Waypoint waypoint) {
|
||||||
StringUtils utils = new StringUtils(TrackRecordingService.this);
|
StringUtils utils = new StringUtils(TrackRecordingService.this);
|
||||||
@@ -983,8 +1003,8 @@ public class TrackRecordingService extends Service {
|
|||||||
|
|
||||||
private void endCurrentTrack() {
|
private void endCurrentTrack() {
|
||||||
Log.d(TAG, "TrackRecordingService.endCurrentTrack");
|
Log.d(TAG, "TrackRecordingService.endCurrentTrack");
|
||||||
if (recordingTrackId == -1 || !isRecording) {
|
if (!isTrackInProgress()) {
|
||||||
throw new IllegalStateException("No recording track in progress!");
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
announcementExecutor.shutdown();
|
announcementExecutor.shutdown();
|
||||||
@@ -1025,12 +1045,15 @@ public class TrackRecordingService extends Service {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void sendTrackBroadcast(int actionResId, long trackId) {
|
private void sendTrackBroadcast(int actionResId, long trackId) {
|
||||||
Intent broadcastIntent =
|
Intent broadcastIntent = new Intent()
|
||||||
new Intent()
|
.setAction(getString(actionResId))
|
||||||
.setAction(getString(actionResId))
|
.putExtra(getString(R.string.track_id_broadcast_extra), trackId);
|
||||||
.putExtra(getString(R.string.track_id_broadcast_extra), trackId);
|
sendBroadcast(broadcastIntent, getString(R.string.mytracks_notifications_permission));
|
||||||
sendBroadcast(broadcastIntent,
|
|
||||||
getString(R.string.broadcast_notifications_permission));
|
SharedPreferences sharedPreferences = getSharedPreferences(Constants.SETTINGS_NAME, 0);
|
||||||
|
if (sharedPreferences.getBoolean(getString(R.string.allow_access_key), false)) {
|
||||||
|
sendBroadcast(broadcastIntent, getString(R.string.broadcast_notifications_permission));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1162,29 +1185,58 @@ public class TrackRecordingService extends Service {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the service is available. If not, throws an
|
||||||
|
* {@link IllegalStateException}.
|
||||||
|
*/
|
||||||
private void checkService() {
|
private void checkService() {
|
||||||
if (service == null) {
|
if (service == null) {
|
||||||
throw new IllegalStateException("The service has been already detached!");
|
throw new IllegalStateException("The service has been already detached!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the RPC caller is from the same application or if the
|
||||||
|
* "Allow access" setting indicates that another app can invoke this service's
|
||||||
|
* RPCs.
|
||||||
|
*/
|
||||||
|
private boolean canAccess() {
|
||||||
|
|
||||||
|
// As a precondition for access, must check if the service is available.
|
||||||
|
checkService();
|
||||||
|
|
||||||
|
if (Process.myPid() == Binder.getCallingPid()) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
SharedPreferences sharedPreferences = service.getSharedPreferences(
|
||||||
|
Constants.SETTINGS_NAME, 0);
|
||||||
|
return sharedPreferences.getBoolean(service.getString(R.string.allow_access_key), false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Service method delegates.
|
// Service method delegates.
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isRecording() {
|
public boolean isRecording() {
|
||||||
checkService();
|
if (!canAccess()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
return service.isRecording();
|
return service.isRecording();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getRecordingTrackId() {
|
public long getRecordingTrackId() {
|
||||||
checkService();
|
if (!canAccess()) {
|
||||||
|
return -1L;
|
||||||
|
}
|
||||||
return service.recordingTrackId;
|
return service.recordingTrackId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long startNewTrack() {
|
public long startNewTrack() {
|
||||||
checkService();
|
if (!canAccess()) {
|
||||||
|
return -1L;
|
||||||
|
}
|
||||||
return service.startNewTrack();
|
return service.startNewTrack();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1195,25 +1247,33 @@ public class TrackRecordingService extends Service {
|
|||||||
* @return the unique ID of the inserted marker
|
* @return the unique ID of the inserted marker
|
||||||
*/
|
*/
|
||||||
public long insertWaypoint(WaypointCreationRequest request) {
|
public long insertWaypoint(WaypointCreationRequest request) {
|
||||||
checkService();
|
if (!canAccess()) {
|
||||||
|
return -1L;
|
||||||
|
}
|
||||||
return service.insertWaypoint(request);
|
return service.insertWaypoint(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void endCurrentTrack() {
|
public void endCurrentTrack() {
|
||||||
checkService();
|
if (!canAccess()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
service.endCurrentTrack();
|
service.endCurrentTrack();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void recordLocation(Location loc) {
|
public void recordLocation(Location loc) {
|
||||||
checkService();
|
if (!canAccess()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
service.locationListener.onLocationChanged(loc);
|
service.locationListener.onLocationChanged(loc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte[] getSensorData() {
|
public byte[] getSensorData() {
|
||||||
checkService();
|
if (!canAccess()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
if (service.sensorManager == null) {
|
if (service.sensorManager == null) {
|
||||||
Log.d(TAG, "No sensor manager for data.");
|
Log.d(TAG, "No sensor manager for data.");
|
||||||
return null;
|
return null;
|
||||||
@@ -1227,7 +1287,9 @@ public class TrackRecordingService extends Service {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getSensorState() {
|
public int getSensorState() {
|
||||||
checkService();
|
if (!canAccess()) {
|
||||||
|
return Sensor.SensorState.NONE.getNumber();
|
||||||
|
}
|
||||||
if (service.sensorManager == null) {
|
if (service.sensorManager == null) {
|
||||||
Log.d(TAG, "No sensor manager for data.");
|
Log.d(TAG, "No sensor manager for data.");
|
||||||
return Sensor.SensorState.NONE.getNumber();
|
return Sensor.SensorState.NONE.getNumber();
|
||||||
|
|||||||
+24
-16
@@ -18,6 +18,7 @@ package com.google.android.apps.mytracks.services.sensors;
|
|||||||
|
|
||||||
import com.google.android.apps.mytracks.Constants;
|
import com.google.android.apps.mytracks.Constants;
|
||||||
import com.google.android.apps.mytracks.content.Sensor;
|
import com.google.android.apps.mytracks.content.Sensor;
|
||||||
|
import com.google.android.apps.mytracks.util.ApiFeatures;
|
||||||
|
|
||||||
import android.bluetooth.BluetoothAdapter;
|
import android.bluetooth.BluetoothAdapter;
|
||||||
import android.bluetooth.BluetoothDevice;
|
import android.bluetooth.BluetoothDevice;
|
||||||
@@ -261,22 +262,29 @@ public class BluetoothConnectionManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private BluetoothSocket getSocket() throws IOException {
|
private BluetoothSocket getSocket() throws IOException {
|
||||||
try {
|
if (ApiFeatures.getInstance().hasBluetoothDeviceCreateInsecureRfcommSocketToServiceRecord()) {
|
||||||
Class<? extends BluetoothDevice> c = device.getClass();
|
try {
|
||||||
Method insecure = c.getMethod("createInsecureRfcommSocket",
|
return device.createInsecureRfcommSocketToServiceRecord(SPP_UUID);
|
||||||
Integer.class);
|
} catch (IOException e) {
|
||||||
insecure.setAccessible(true);
|
Log.e(Constants.TAG, "Unable to get insecure connect.", e);
|
||||||
return (BluetoothSocket) insecure.invoke(device, 1);
|
}
|
||||||
} catch (SecurityException e) {
|
} else {
|
||||||
Log.e(Constants.TAG, "Unable to get insecure connect.", e);
|
try {
|
||||||
} catch (NoSuchMethodException e) {
|
Class<? extends BluetoothDevice> c = device.getClass();
|
||||||
Log.e(Constants.TAG, "Unable to get insecure connect.", e);
|
Method insecure = c.getMethod("createInsecureRfcommSocket", Integer.class);
|
||||||
} catch (IllegalArgumentException e) {
|
insecure.setAccessible(true);
|
||||||
Log.e(Constants.TAG, "Unable to get insecure connect.", e);
|
return (BluetoothSocket) insecure.invoke(device, 1);
|
||||||
} catch (IllegalAccessException e) {
|
} catch (SecurityException e) {
|
||||||
Log.e(Constants.TAG, "Unable to get insecure connect.", e);
|
Log.e(Constants.TAG, "Unable to get insecure connect.", e);
|
||||||
} catch (InvocationTargetException e) {
|
} catch (NoSuchMethodException e) {
|
||||||
Log.e(Constants.TAG, "Unable to get insecure connect.", e);
|
Log.e(Constants.TAG, "Unable to get insecure connect.", e);
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
Log.e(Constants.TAG, "Unable to get insecure connect.", e);
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
Log.e(Constants.TAG, "Unable to get insecure connect.", e);
|
||||||
|
} catch (InvocationTargetException e) {
|
||||||
|
Log.e(Constants.TAG, "Unable to get insecure connect.", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return device.createRfcommSocketToServiceRecord(SPP_UUID);
|
return device.createRfcommSocketToServiceRecord(SPP_UUID);
|
||||||
}
|
}
|
||||||
|
|||||||
+51
-4
@@ -15,6 +15,8 @@
|
|||||||
*/
|
*/
|
||||||
package com.google.android.apps.mytracks.services.sensors;
|
package com.google.android.apps.mytracks.services.sensors;
|
||||||
|
|
||||||
|
import static com.google.android.apps.mytracks.Constants.TAG;
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.Constants;
|
import com.google.android.apps.mytracks.Constants;
|
||||||
import com.google.android.apps.mytracks.content.Sensor;
|
import com.google.android.apps.mytracks.content.Sensor;
|
||||||
import com.google.android.maps.mytracks.R;
|
import com.google.android.maps.mytracks.R;
|
||||||
@@ -24,10 +26,13 @@ import android.bluetooth.BluetoothDevice;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
|
import android.os.Looper;
|
||||||
import android.os.Message;
|
import android.os.Message;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manage the connection to a bluetooth sensor.
|
* Manage the connection to a bluetooth sensor.
|
||||||
*
|
*
|
||||||
@@ -36,7 +41,7 @@ import android.widget.Toast;
|
|||||||
public class BluetoothSensorManager extends SensorManager {
|
public class BluetoothSensorManager extends SensorManager {
|
||||||
|
|
||||||
// Local Bluetooth adapter
|
// Local Bluetooth adapter
|
||||||
private BluetoothAdapter bluetoothAdapter = null;
|
private static final BluetoothAdapter bluetoothAdapter = getDefaultBluetoothAdapter();
|
||||||
|
|
||||||
// Member object for the sensor threads and connections.
|
// Member object for the sensor threads and connections.
|
||||||
private BluetoothConnectionManager connectionManager = null;
|
private BluetoothConnectionManager connectionManager = null;
|
||||||
@@ -54,8 +59,6 @@ public class BluetoothSensorManager extends SensorManager {
|
|||||||
Context context, MessageParser parser) {
|
Context context, MessageParser parser) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.parser = parser;
|
this.parser = parser;
|
||||||
// Get local Bluetooth adapter
|
|
||||||
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
|
|
||||||
// If BT is not available or not enabled quit.
|
// If BT is not available or not enabled quit.
|
||||||
if (!isEnabled()) {
|
if (!isEnabled()) {
|
||||||
return;
|
return;
|
||||||
@@ -71,6 +74,50 @@ public class BluetoothSensorManager extends SensorManager {
|
|||||||
connectionManager = new BluetoothConnectionManager(messageHandler, parser);
|
connectionManager = new BluetoothConnectionManager(messageHandler, parser);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Code for assigning the local bluetooth adapter
|
||||||
|
*
|
||||||
|
* @return The default bluetooth adapter, if one is available, NULL if it isn't.
|
||||||
|
*/
|
||||||
|
private static BluetoothAdapter getDefaultBluetoothAdapter() {
|
||||||
|
// Check if the calling thread is the main application thread,
|
||||||
|
// if it is, do it directly.
|
||||||
|
if (Thread.currentThread().equals(Looper.getMainLooper().getThread())) {
|
||||||
|
return BluetoothAdapter.getDefaultAdapter();
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the calling thread, isn't the main application thread,
|
||||||
|
// then get the main application thread to return the default adapter.
|
||||||
|
final ArrayList<BluetoothAdapter> adapters = new ArrayList<BluetoothAdapter>(1);
|
||||||
|
final Object mutex = new Object();
|
||||||
|
|
||||||
|
Handler handler = new Handler(Looper.getMainLooper());
|
||||||
|
handler.post(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
adapters.add(BluetoothAdapter.getDefaultAdapter());
|
||||||
|
synchronized (mutex) {
|
||||||
|
mutex.notify();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
while (adapters.isEmpty()) {
|
||||||
|
synchronized (mutex) {
|
||||||
|
try {
|
||||||
|
mutex.wait(1000L);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
Log.e(TAG, "Interrupted while waiting for default bluetooth adapter", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (adapters.get(0) == null) {
|
||||||
|
Log.w(TAG, "No bluetooth adapter found!");
|
||||||
|
}
|
||||||
|
return adapters.get(0);
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isEnabled() {
|
public boolean isEnabled() {
|
||||||
return bluetoothAdapter != null && bluetoothAdapter.isEnabled();
|
return bluetoothAdapter != null && bluetoothAdapter.isEnabled();
|
||||||
}
|
}
|
||||||
@@ -125,7 +172,7 @@ public class BluetoothSensorManager extends SensorManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// The Handler that gets information back from the BluetoothSensorService
|
// The Handler that gets information back from the BluetoothSensorService
|
||||||
private final Handler messageHandler = new Handler() {
|
private final Handler messageHandler = new Handler(Looper.getMainLooper()) {
|
||||||
@Override
|
@Override
|
||||||
public void handleMessage(Message msg) {
|
public void handleMessage(Message msg) {
|
||||||
switch (msg.what) {
|
switch (msg.what) {
|
||||||
|
|||||||
+4
-3
@@ -16,6 +16,7 @@
|
|||||||
package com.google.android.apps.mytracks.services.sensors;
|
package com.google.android.apps.mytracks.services.sensors;
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.content.Sensor;
|
import com.google.android.apps.mytracks.content.Sensor;
|
||||||
|
import com.google.android.apps.mytracks.util.ApiFeatures;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
@@ -23,7 +24,7 @@ import java.util.Arrays;
|
|||||||
* An implementation of a Sensor MessageParser for Zephyr.
|
* An implementation of a Sensor MessageParser for Zephyr.
|
||||||
*
|
*
|
||||||
* @author Sandor Dornbush
|
* @author Sandor Dornbush
|
||||||
* @author Dominik Ršttsches
|
* @author Dominik Rttsches
|
||||||
*/
|
*/
|
||||||
public class ZephyrMessageParser implements MessageParser {
|
public class ZephyrMessageParser implements MessageParser {
|
||||||
|
|
||||||
@@ -61,8 +62,8 @@ public class ZephyrMessageParser implements MessageParser {
|
|||||||
// 0x1A00316550003162 produces erroneous values for Cadence and needs
|
// 0x1A00316550003162 produces erroneous values for Cadence and needs
|
||||||
// a workaround based on the stride counter.
|
// a workaround based on the stride counter.
|
||||||
// Firmware values range from field 3 to 10 (inclusive) of the byte buffer.
|
// Firmware values range from field 3 to 10 (inclusive) of the byte buffer.
|
||||||
byte[] hardwareFirmwareId = Arrays.copyOfRange(buffer, 3, 11);
|
byte[] hardwareFirmwareId = ApiFeatures.getInstance().getApiAdapter()
|
||||||
|
.copyByteArray(buffer, 3, 11);
|
||||||
Sensor.SensorData.Builder cadence = Sensor.SensorData.newBuilder();
|
Sensor.SensorData.Builder cadence = Sensor.SensorData.newBuilder();
|
||||||
|
|
||||||
if (Arrays.equals(hardwareFirmwareId, CADENCE_BUG_FW_ID)) {
|
if (Arrays.equals(hardwareFirmwareId, CADENCE_BUG_FW_ID)) {
|
||||||
|
|||||||
+11
-7
@@ -22,6 +22,7 @@ import com.dsi.ant.AntInterface;
|
|||||||
import com.dsi.ant.AntInterfaceIntent;
|
import com.dsi.ant.AntInterfaceIntent;
|
||||||
import com.dsi.ant.AntMesg;
|
import com.dsi.ant.AntMesg;
|
||||||
import com.dsi.ant.exception.AntInterfaceException;
|
import com.dsi.ant.exception.AntInterfaceException;
|
||||||
|
import com.dsi.ant.exception.AntServiceNotConnectedException;
|
||||||
import com.google.android.apps.mytracks.content.Sensor;
|
import com.google.android.apps.mytracks.content.Sensor;
|
||||||
import com.google.android.apps.mytracks.content.Sensor.SensorDataSet;
|
import com.google.android.apps.mytracks.content.Sensor.SensorDataSet;
|
||||||
import com.google.android.apps.mytracks.services.sensors.SensorManager;
|
import com.google.android.apps.mytracks.services.sensors.SensorManager;
|
||||||
@@ -142,13 +143,16 @@ public abstract class AntSensorManager extends SensorManager {
|
|||||||
Log.w(TAG, "Failed to unregister ANT data receiver", e);
|
Log.w(TAG, "Failed to unregister ANT data receiver", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
if (antReceiver != null) {
|
||||||
antReceiver.releaseInterface();
|
try {
|
||||||
} catch (AntInterfaceException e) {
|
antReceiver.releaseInterface();
|
||||||
Log.e(TAG, "failed to release ANT interface", e);
|
} catch (AntServiceNotConnectedException e) {
|
||||||
|
Log.i(TAG, "ANT service not connected", e);
|
||||||
|
} catch (AntInterfaceException e) {
|
||||||
|
Log.e(TAG, "failed to release ANT interface", e);
|
||||||
|
}
|
||||||
|
antReceiver.destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
antReceiver.destroy();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -236,7 +240,7 @@ public abstract class AntSensorManager extends SensorManager {
|
|||||||
/**
|
/**
|
||||||
* Process a raw ANT message.
|
* Process a raw ANT message.
|
||||||
* @param antMessage the ANT message, including the size and message ID bytes
|
* @param antMessage the ANT message, including the size and message ID bytes
|
||||||
* @deprecated Use {@link #handleMessage(int, byte[])} instead.
|
* @deprecated Use {@link #handleMessage(byte, byte[])} instead.
|
||||||
*/
|
*/
|
||||||
protected void handleMessage(byte[] antMessage) {
|
protected void handleMessage(byte[] antMessage) {
|
||||||
int len = antMessage[0];
|
int len = antMessage[0];
|
||||||
|
|||||||
+1
-5
@@ -37,11 +37,7 @@ public class StatusAnnouncerFactory implements PeriodicTaskFactory {
|
|||||||
@Override
|
@Override
|
||||||
public PeriodicTask create(Context context) {
|
public PeriodicTask create(Context context) {
|
||||||
if (hasTts) {
|
if (hasTts) {
|
||||||
if (ApiFeatures.getInstance().isAudioFocusSupported()) {
|
return ApiFeatures.getInstance().getApiAdapter().getStatusAnnouncerTask(context);
|
||||||
return new FroyoStatusAnnouncerTask(context);
|
|
||||||
} else {
|
|
||||||
return new StatusAnnouncerTask(context);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,17 +29,17 @@ import android.util.Log;
|
|||||||
public class ApiFeatures {
|
public class ApiFeatures {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The API level of the Android version we're being run under.
|
* The API level of the Android version we are being run under.
|
||||||
*/
|
*/
|
||||||
public static final int ANDROID_API_LEVEL = Integer.parseInt(
|
private static final int ANDROID_API_LEVEL = Integer.parseInt(
|
||||||
Build.VERSION.SDK);
|
Build.VERSION.SDK);
|
||||||
|
|
||||||
private static ApiFeatures instance;
|
private static ApiFeatures instance;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The API platform adapter supported by this system.
|
* The API level adapter for the Android version we are being run under.
|
||||||
*/
|
*/
|
||||||
private ApiPlatformAdapter apiPlatformAdapter;
|
private ApiLevelAdapter apiLevelAdapter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the singleton instance of this class.
|
* Returns the singleton instance of this class.
|
||||||
@@ -66,51 +66,32 @@ public class ApiFeatures {
|
|||||||
// It is safe to import unsupported classes as long as we only actually
|
// It is safe to import unsupported classes as long as we only actually
|
||||||
// load the class when supported.
|
// load the class when supported.
|
||||||
if (getApiLevel() >= 9) {
|
if (getApiLevel() >= 9) {
|
||||||
apiPlatformAdapter = new GingerbreadPlatformAdapter();
|
apiLevelAdapter = new ApiLevel9Adapter();
|
||||||
|
} else if (getApiLevel() >= 8) {
|
||||||
|
apiLevelAdapter = new ApiLevel8Adapter();
|
||||||
} else if (getApiLevel() >= 5) {
|
} else if (getApiLevel() >= 5) {
|
||||||
apiPlatformAdapter = new EclairPlatformAdapter();
|
apiLevelAdapter = new ApiLevel5Adapter();
|
||||||
} else {
|
} else {
|
||||||
apiPlatformAdapter = new CupcakePlatformAdapter();
|
apiLevelAdapter = new ApiLevel3Adapter();
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.i(Constants.TAG, "Using platform adapter " + apiPlatformAdapter.getClass());
|
Log.i(Constants.TAG, "Using API level adapter " + apiLevelAdapter.getClass());
|
||||||
}
|
}
|
||||||
|
|
||||||
public ApiPlatformAdapter getApiPlatformAdapter() {
|
public ApiLevelAdapter getApiAdapter() {
|
||||||
return apiPlatformAdapter;
|
return apiLevelAdapter;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// API Level 4 Changes
|
||||||
* Returns whether cloud backup (a.k.a. Froyo backup) is available.
|
|
||||||
*/
|
|
||||||
public boolean hasBackup() {
|
|
||||||
return getApiLevel() >= 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether text-to-speech is available.
|
* Returns whether text-to-speech is available.
|
||||||
*/
|
*/
|
||||||
public boolean hasTextToSpeech() {
|
public boolean hasTextToSpeech() {
|
||||||
if (getApiLevel() < 4) return false;
|
return getApiLevel() >= 4;
|
||||||
|
|
||||||
try {
|
|
||||||
Class.forName("android.speech.tts.TextToSpeech");
|
|
||||||
} catch (ClassNotFoundException ex) {
|
|
||||||
return false;
|
|
||||||
} catch (LinkageError er) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasStrictMode() {
|
// API Level 5 Changes
|
||||||
return getApiLevel() >= 9;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isAudioFocusSupported() {
|
|
||||||
return getApiLevel() >= 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* There's a bug (#1587) in Cupcake and Donut which prevents you from
|
* There's a bug (#1587) in Cupcake and Donut which prevents you from
|
||||||
@@ -121,7 +102,17 @@ public class ApiFeatures {
|
|||||||
* up. Specifically, it'll add extra parens which don't belong.
|
* up. Specifically, it'll add extra parens which don't belong.
|
||||||
*/
|
*/
|
||||||
public boolean canReuseSQLiteQueryBuilder() {
|
public boolean canReuseSQLiteQueryBuilder() {
|
||||||
return getApiLevel() > 4;
|
return getApiLevel() >= 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
// API Level 10 changes
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if BluetoothDevice.createInsecureRfcommSocketToServiceRecord
|
||||||
|
* is available.
|
||||||
|
*/
|
||||||
|
public boolean hasBluetoothDeviceCreateInsecureRfcommSocketToServiceRecord() {
|
||||||
|
return getApiLevel() >= 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Visible for testing.
|
// Visible for testing.
|
||||||
|
|||||||
+45
-3
@@ -17,22 +17,31 @@ package com.google.android.apps.mytracks.util;
|
|||||||
|
|
||||||
import static com.google.android.apps.mytracks.Constants.TAG;
|
import static com.google.android.apps.mytracks.Constants.TAG;
|
||||||
|
|
||||||
|
import com.google.android.apps.mytracks.io.backup.BackupPreferencesListener;
|
||||||
|
import com.google.android.apps.mytracks.services.tasks.PeriodicTask;
|
||||||
|
import com.google.android.apps.mytracks.services.tasks.StatusAnnouncerTask;
|
||||||
|
import com.google.api.client.http.HttpTransport;
|
||||||
|
import com.google.api.client.http.apache.ApacheHttpTransport;
|
||||||
|
|
||||||
import android.app.Notification;
|
import android.app.Notification;
|
||||||
import android.app.NotificationManager;
|
import android.app.NotificationManager;
|
||||||
import android.app.Service;
|
import android.app.Service;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
import android.content.SharedPreferences.Editor;
|
import android.content.SharedPreferences.Editor;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
import java.text.DecimalFormatSymbols;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Cupcake (API level 3) specific implementation of the
|
* API level 3 specific implementation of the {@link ApiLevelAdapter}.
|
||||||
* {@link ApiPlatformAdapter}.
|
|
||||||
*
|
*
|
||||||
* @author Bartlomiej Niechwiej
|
* @author Bartlomiej Niechwiej
|
||||||
*/
|
*/
|
||||||
public class CupcakePlatformAdapter implements ApiPlatformAdapter {
|
public class ApiLevel3Adapter implements ApiLevelAdapter {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void startForeground(Service service,
|
public void startForeground(Service service,
|
||||||
@@ -52,6 +61,21 @@ public class CupcakePlatformAdapter implements ApiPlatformAdapter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PeriodicTask getStatusAnnouncerTask(Context context) {
|
||||||
|
return new StatusAnnouncerTask(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BackupPreferencesListener getBackupPreferencesListener(Context context) {
|
||||||
|
return new BackupPreferencesListener() {
|
||||||
|
@Override
|
||||||
|
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
|
||||||
|
// Do nothing
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
private void setServiceForeground(Service service, boolean foreground) {
|
private void setServiceForeground(Service service, boolean foreground) {
|
||||||
// setForeground has been completely removed in API level 11, so we use reflection.
|
// setForeground has been completely removed in API level 11, so we use reflection.
|
||||||
try {
|
try {
|
||||||
@@ -79,4 +103,22 @@ public class CupcakePlatformAdapter implements ApiPlatformAdapter {
|
|||||||
public void enableStrictMode() {
|
public void enableStrictMode() {
|
||||||
// Not supported
|
// Not supported
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] copyByteArray(byte[] input, int start, int end) {
|
||||||
|
int length = end - start;
|
||||||
|
byte[] output = new byte[length];
|
||||||
|
System.arraycopy(input, start, output, 0, length);
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DecimalFormatSymbols getDecimalFormatSymbols(Locale locale) {
|
||||||
|
return new DecimalFormatSymbols(locale);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HttpTransport getHttpTransport() {
|
||||||
|
return new ApacheHttpTransport();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+2
-14
@@ -18,15 +18,13 @@ package com.google.android.apps.mytracks.util;
|
|||||||
import android.app.Notification;
|
import android.app.Notification;
|
||||||
import android.app.NotificationManager;
|
import android.app.NotificationManager;
|
||||||
import android.app.Service;
|
import android.app.Service;
|
||||||
import android.content.SharedPreferences.Editor;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Eclair (API level 5) specific implementation of the
|
* API level 5 specific implementation of the {@link ApiLevelAdapter}.
|
||||||
* {@link ApiPlatformAdapter}.
|
|
||||||
*
|
*
|
||||||
* @author Bartlomiej Niechwiej
|
* @author Bartlomiej Niechwiej
|
||||||
*/
|
*/
|
||||||
public class EclairPlatformAdapter implements ApiPlatformAdapter {
|
public class ApiLevel5Adapter extends ApiLevel3Adapter {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void startForeground(Service service,
|
public void startForeground(Service service,
|
||||||
@@ -40,14 +38,4 @@ public class EclairPlatformAdapter implements ApiPlatformAdapter {
|
|||||||
NotificationManager notificationManager, int id) {
|
NotificationManager notificationManager, int id) {
|
||||||
service.stopForeground(id != -1);
|
service.stopForeground(id != -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void applyPreferenceChanges(Editor editor) {
|
|
||||||
editor.commit();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void enableStrictMode() {
|
|
||||||
// Not supported
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package com.google.android.apps.mytracks.util;
|
||||||
|
|
||||||
|
import com.google.android.apps.mytracks.io.backup.BackupPreferencesListener;
|
||||||
|
import com.google.android.apps.mytracks.io.backup.BackupPreferencesListenerImpl;
|
||||||
|
import com.google.android.apps.mytracks.services.tasks.FroyoStatusAnnouncerTask;
|
||||||
|
import com.google.android.apps.mytracks.services.tasks.PeriodicTask;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* API level 8 specific implementation of the {@link ApiLevelAdapter}.
|
||||||
|
*
|
||||||
|
* @author Jimmy Shih
|
||||||
|
*/
|
||||||
|
public class ApiLevel8Adapter extends ApiLevel5Adapter {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PeriodicTask getStatusAnnouncerTask(Context context) {
|
||||||
|
return new FroyoStatusAnnouncerTask(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BackupPreferencesListener getBackupPreferencesListener(Context context) {
|
||||||
|
return new BackupPreferencesListenerImpl(context);
|
||||||
|
}
|
||||||
|
}
|
||||||
+24
-3
@@ -1,18 +1,24 @@
|
|||||||
package com.google.android.apps.mytracks.util;
|
package com.google.android.apps.mytracks.util;
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.Constants;
|
import com.google.android.apps.mytracks.Constants;
|
||||||
|
import com.google.api.client.http.HttpTransport;
|
||||||
|
import com.google.api.client.http.javanet.NetHttpTransport;
|
||||||
|
|
||||||
import android.content.SharedPreferences.Editor;
|
import android.content.SharedPreferences.Editor;
|
||||||
import android.os.StrictMode;
|
import android.os.StrictMode;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
import java.text.DecimalFormatSymbols;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Gingerbread (API level 9) specific implememntation of the
|
* API level 9 specific implementation of the {@link ApiLevelAdapter}.
|
||||||
* {@link ApiPlatformAdapter}.
|
|
||||||
*
|
*
|
||||||
* @author Rodrigo Damazio
|
* @author Rodrigo Damazio
|
||||||
*/
|
*/
|
||||||
public class GingerbreadPlatformAdapter extends EclairPlatformAdapter {
|
public class ApiLevel9Adapter extends ApiLevel8Adapter {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void applyPreferenceChanges(Editor editor) {
|
public void applyPreferenceChanges(Editor editor) {
|
||||||
// Apply asynchronously
|
// Apply asynchronously
|
||||||
@@ -32,4 +38,19 @@ public class GingerbreadPlatformAdapter extends EclairPlatformAdapter {
|
|||||||
.penaltyLog()
|
.penaltyLog()
|
||||||
.build());
|
.build());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] copyByteArray(byte[] input, int start, int end) {
|
||||||
|
return Arrays.copyOfRange(input, start, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DecimalFormatSymbols getDecimalFormatSymbols(Locale locale) {
|
||||||
|
return DecimalFormatSymbols.getInstance(locale);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HttpTransport getHttpTransport() {
|
||||||
|
return new NetHttpTransport();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+65
-2
@@ -15,21 +15,31 @@
|
|||||||
*/
|
*/
|
||||||
package com.google.android.apps.mytracks.util;
|
package com.google.android.apps.mytracks.util;
|
||||||
|
|
||||||
|
import com.google.android.apps.mytracks.io.backup.BackupPreferencesListener;
|
||||||
|
import com.google.android.apps.mytracks.services.tasks.PeriodicTask;
|
||||||
|
import com.google.api.client.http.HttpTransport;
|
||||||
|
|
||||||
import android.app.Notification;
|
import android.app.Notification;
|
||||||
import android.app.NotificationManager;
|
import android.app.NotificationManager;
|
||||||
import android.app.Service;
|
import android.app.Service;
|
||||||
|
import android.content.Context;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
|
|
||||||
|
import java.text.DecimalFormatSymbols;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A set of methods that may be implemented in a platform specific way.
|
* A set of methods that may be implemented differently depending on the Android API level.
|
||||||
*
|
*
|
||||||
* @author Bartlomiej Niechwiej
|
* @author Bartlomiej Niechwiej
|
||||||
*/
|
*/
|
||||||
public interface ApiPlatformAdapter {
|
public interface ApiLevelAdapter {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Puts the specified service into foreground.
|
* Puts the specified service into foreground.
|
||||||
*
|
*
|
||||||
|
* Due to changes in API level 5.
|
||||||
|
*
|
||||||
* @param service the service to be put in foreground.
|
* @param service the service to be put in foreground.
|
||||||
* @param notificationManager the notification manager used to post the given
|
* @param notificationManager the notification manager used to post the given
|
||||||
* notification.
|
* notification.
|
||||||
@@ -41,6 +51,9 @@ public interface ApiPlatformAdapter {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Puts the given service into background.
|
* Puts the given service into background.
|
||||||
|
*
|
||||||
|
* Due to changes in API level 5.
|
||||||
|
*
|
||||||
* @param service the service to put into background.
|
* @param service the service to put into background.
|
||||||
* @param notificationManager the notification manager to user when removing
|
* @param notificationManager the notification manager to user when removing
|
||||||
* notifications.
|
* notifications.
|
||||||
@@ -50,14 +63,64 @@ public interface ApiPlatformAdapter {
|
|||||||
void stopForeground(Service service, NotificationManager notificationManager,
|
void stopForeground(Service service, NotificationManager notificationManager,
|
||||||
int id);
|
int id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a status announcer task.
|
||||||
|
*
|
||||||
|
* Due to changes in API level 8.
|
||||||
|
*/
|
||||||
|
PeriodicTask getStatusAnnouncerTask(Context context);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a {@link BackupPreferencesListener}.
|
||||||
|
*
|
||||||
|
* Due to changes in API level 8.
|
||||||
|
*/
|
||||||
|
BackupPreferencesListener getBackupPreferencesListener(Context context);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Applies all changes done to the given preferences editor.
|
* Applies all changes done to the given preferences editor.
|
||||||
* Changes may or may not be applied immediately.
|
* Changes may or may not be applied immediately.
|
||||||
|
*
|
||||||
|
* Due to changes in API level 9.
|
||||||
*/
|
*/
|
||||||
void applyPreferenceChanges(SharedPreferences.Editor editor);
|
void applyPreferenceChanges(SharedPreferences.Editor editor);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enables strict mode where supported, only if this is a development build.
|
* Enables strict mode where supported, only if this is a development build.
|
||||||
|
*
|
||||||
|
* Due to changes in API level 9.
|
||||||
*/
|
*/
|
||||||
void enableStrictMode();
|
void enableStrictMode();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copies elements from the input byte array into a new byte array, from
|
||||||
|
* indexes start (inclusive) to end (exclusive). The end index must be less
|
||||||
|
* than or equal to input.length.
|
||||||
|
*
|
||||||
|
* Due to changes in API level 9.
|
||||||
|
*
|
||||||
|
* @param input the input byte array
|
||||||
|
* @param start the start index
|
||||||
|
* @param end the end index
|
||||||
|
* @return a new array containing elements from the input byte array
|
||||||
|
*/
|
||||||
|
byte[] copyByteArray(byte[] input, int start, int end);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets an instance of {@link DecimalFormatSymbols} for a locale.
|
||||||
|
*
|
||||||
|
* Due to changes in API level 9.
|
||||||
|
*
|
||||||
|
* @param locale the locale
|
||||||
|
* @return a new instance of {@link DecimalFormatSymbols}
|
||||||
|
*/
|
||||||
|
DecimalFormatSymbols getDecimalFormatSymbols(Locale locale);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a {@link HttpTransport}.
|
||||||
|
*
|
||||||
|
* Due to changes in API level 9.
|
||||||
|
*/
|
||||||
|
HttpTransport getHttpTransport();
|
||||||
}
|
}
|
||||||
@@ -28,6 +28,7 @@ public abstract class UnitConversions {
|
|||||||
public static final double MI_TO_FEET = 5280.0;
|
public static final double MI_TO_FEET = 5280.0;
|
||||||
public static final double KMH_TO_MPH = 1000 * M_TO_FT / MI_TO_FEET;
|
public static final double KMH_TO_MPH = 1000 * M_TO_FT / MI_TO_FEET;
|
||||||
public static final double TO_RADIANS = Math.PI / 180.0;
|
public static final double TO_RADIANS = Math.PI / 180.0;
|
||||||
|
public static final double MPH_TO_KMH = 1.609344;
|
||||||
|
|
||||||
protected UnitConversions() {
|
protected UnitConversions() {
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,16 @@ package com.google.android.apps.mytracks.widgets;
|
|||||||
import static com.google.android.apps.mytracks.Constants.SETTINGS_NAME;
|
import static com.google.android.apps.mytracks.Constants.SETTINGS_NAME;
|
||||||
import static com.google.android.apps.mytracks.Constants.TAG;
|
import static com.google.android.apps.mytracks.Constants.TAG;
|
||||||
|
|
||||||
|
import com.google.android.apps.mytracks.MyTracks;
|
||||||
|
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
|
||||||
|
import com.google.android.apps.mytracks.content.Track;
|
||||||
|
import com.google.android.apps.mytracks.content.TracksColumns;
|
||||||
|
import com.google.android.apps.mytracks.services.ControlRecordingService;
|
||||||
|
import com.google.android.apps.mytracks.stats.TripStatistics;
|
||||||
|
import com.google.android.apps.mytracks.util.StringUtils;
|
||||||
|
import com.google.android.apps.mytracks.util.UnitConversions;
|
||||||
|
import com.google.android.maps.mytracks.R;
|
||||||
|
|
||||||
import android.app.PendingIntent;
|
import android.app.PendingIntent;
|
||||||
import android.appwidget.AppWidgetManager;
|
import android.appwidget.AppWidgetManager;
|
||||||
import android.appwidget.AppWidgetProvider;
|
import android.appwidget.AppWidgetProvider;
|
||||||
@@ -32,16 +42,6 @@ import android.os.Handler;
|
|||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.widget.RemoteViews;
|
import android.widget.RemoteViews;
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.MyTracks;
|
|
||||||
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
|
|
||||||
import com.google.android.apps.mytracks.content.Track;
|
|
||||||
import com.google.android.apps.mytracks.content.TracksColumns;
|
|
||||||
import com.google.android.apps.mytracks.services.TrackRecordingService;
|
|
||||||
import com.google.android.apps.mytracks.stats.TripStatistics;
|
|
||||||
import com.google.android.apps.mytracks.util.StringUtils;
|
|
||||||
import com.google.android.apps.mytracks.util.UnitConversions;
|
|
||||||
import com.google.android.maps.mytracks.R;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An AppWidgetProvider for displaying key track statistics (distance, time,
|
* An AppWidgetProvider for displaying key track statistics (distance, time,
|
||||||
* speed) from the current or most recent track.
|
* speed) from the current or most recent track.
|
||||||
@@ -175,14 +175,12 @@ public class TrackWidgetProvider
|
|||||||
// If a new track is started by this appwidget or elsewhere,
|
// If a new track is started by this appwidget or elsewhere,
|
||||||
// toggle the button to active and have it disable the track if pressed.
|
// toggle the button to active and have it disable the track if pressed.
|
||||||
setButtonIntent(
|
setButtonIntent(
|
||||||
views, context, R.string.end_current_track_action, R.drawable.appwidget_button_enabled,
|
views, context, R.string.end_current_track_action, R.drawable.appwidget_button_enabled);
|
||||||
-1);
|
|
||||||
} else {
|
} else {
|
||||||
// If a track is stopped by this appwidget or elsewhere,
|
// If a track is stopped by this appwidget or elsewhere,
|
||||||
// toggle the button to inactive and have it start a new track if pressed.
|
// toggle the button to inactive and have it start a new track if pressed.
|
||||||
setButtonIntent(
|
setButtonIntent(
|
||||||
views, context, R.string.start_new_track_action, R.drawable.appwidget_button_disabled,
|
views, context, R.string.start_new_track_action, R.drawable.appwidget_button_disabled);
|
||||||
R.string.select_new_track_extra);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -193,15 +191,11 @@ public class TrackWidgetProvider
|
|||||||
* @param context The widget context
|
* @param context The widget context
|
||||||
* @param action The resource id of the action to fire when the button is pressed
|
* @param action The resource id of the action to fire when the button is pressed
|
||||||
* @param icon The resource id of the icon to show for the button
|
* @param icon The resource id of the icon to show for the button
|
||||||
* @param extra Optional resource id of a boolean extra on the intent
|
|
||||||
*/
|
*/
|
||||||
private void setButtonIntent(
|
private void setButtonIntent(
|
||||||
RemoteViews views, Context context, int action, int icon, int extra) {
|
RemoteViews views, Context context, int action, int icon) {
|
||||||
Intent intent = new Intent(context, TrackRecordingService.class);
|
Intent intent = new Intent(context, ControlRecordingService.class);
|
||||||
intent.setAction(context.getString(action));
|
intent.setAction(context.getString(action));
|
||||||
if (extra != -1) {
|
|
||||||
intent.putExtra(context.getString(extra), true);
|
|
||||||
}
|
|
||||||
PendingIntent pendingIntent = PendingIntent.getService(context, 0,
|
PendingIntent pendingIntent = PendingIntent.getService(context, 0,
|
||||||
intent, PendingIntent.FLAG_UPDATE_CURRENT);
|
intent, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||||
views.setOnClickPendingIntent(R.id.appwidget_button, pendingIntent);
|
views.setOnClickPendingIntent(R.id.appwidget_button, pendingIntent);
|
||||||
|
|||||||
@@ -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="lib" path="/MyTracksLib/libs/protobuf-java-2.3.0-lite.jar"/>
|
||||||
|
<classpathentry kind="src" path="MyTracksLib_src"/>
|
||||||
|
<classpathentry kind="output" path="bin"/>
|
||||||
|
</classpath>
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<projectDescription>
|
||||||
|
<name>MyTracksApiSample</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,282 @@
|
|||||||
|
#Thu Oct 13 15:26:00 PDT 2011
|
||||||
|
eclipse.preferences.version=1
|
||||||
|
org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
|
||||||
|
org.eclipse.jdt.core.formatter.alignment_for_annotations_on_local_variable=569
|
||||||
|
org.eclipse.jdt.core.formatter.alignment_for_annotations_on_member=569
|
||||||
|
org.eclipse.jdt.core.formatter.alignment_for_annotations_on_package_declaration=569
|
||||||
|
org.eclipse.jdt.core.formatter.alignment_for_annotations_on_parameter=24
|
||||||
|
org.eclipse.jdt.core.formatter.alignment_for_annotations_on_type_declaration=569
|
||||||
|
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
|
||||||
|
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=16
|
||||||
|
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
|
||||||
|
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16
|
||||||
|
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16
|
||||||
|
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
|
||||||
|
org.eclipse.jdt.core.formatter.alignment_for_assignment=0
|
||||||
|
org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16
|
||||||
|
org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
|
||||||
|
org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
|
||||||
|
org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
|
||||||
|
org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
|
||||||
|
org.eclipse.jdt.core.formatter.alignment_for_field_declaration=16
|
||||||
|
org.eclipse.jdt.core.formatter.alignment_for_for_statement=16
|
||||||
|
org.eclipse.jdt.core.formatter.alignment_for_generic_type_arguments=16
|
||||||
|
org.eclipse.jdt.core.formatter.alignment_for_local_variable_declaration=16
|
||||||
|
org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
|
||||||
|
org.eclipse.jdt.core.formatter.alignment_for_new_anonymous_class=0
|
||||||
|
org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16
|
||||||
|
org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16
|
||||||
|
org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16
|
||||||
|
org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16
|
||||||
|
org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16
|
||||||
|
org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16
|
||||||
|
org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16
|
||||||
|
org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16
|
||||||
|
org.eclipse.jdt.core.formatter.blank_lines_after_imports=1
|
||||||
|
org.eclipse.jdt.core.formatter.blank_lines_after_package=1
|
||||||
|
org.eclipse.jdt.core.formatter.blank_lines_before_field=0
|
||||||
|
org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0
|
||||||
|
org.eclipse.jdt.core.formatter.blank_lines_before_imports=1
|
||||||
|
org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1
|
||||||
|
org.eclipse.jdt.core.formatter.blank_lines_before_method=1
|
||||||
|
org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1
|
||||||
|
org.eclipse.jdt.core.formatter.blank_lines_before_package=0
|
||||||
|
org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1
|
||||||
|
org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1
|
||||||
|
org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line
|
||||||
|
org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line
|
||||||
|
org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line
|
||||||
|
org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line
|
||||||
|
org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line
|
||||||
|
org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line
|
||||||
|
org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line
|
||||||
|
org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line
|
||||||
|
org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line
|
||||||
|
org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
|
||||||
|
org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line
|
||||||
|
org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false
|
||||||
|
org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false
|
||||||
|
org.eclipse.jdt.core.formatter.comment.format_block_comments=true
|
||||||
|
org.eclipse.jdt.core.formatter.comment.format_header=false
|
||||||
|
org.eclipse.jdt.core.formatter.comment.format_html=true
|
||||||
|
org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true
|
||||||
|
org.eclipse.jdt.core.formatter.comment.format_line_comments=true
|
||||||
|
org.eclipse.jdt.core.formatter.comment.format_source_code=true
|
||||||
|
org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true
|
||||||
|
org.eclipse.jdt.core.formatter.comment.indent_root_tags=true
|
||||||
|
org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
|
||||||
|
org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=insert
|
||||||
|
org.eclipse.jdt.core.formatter.comment.line_length=80
|
||||||
|
org.eclipse.jdt.core.formatter.comment_new_line_at_start_of_html_paragraph=true
|
||||||
|
org.eclipse.jdt.core.formatter.compact_else_if=true
|
||||||
|
org.eclipse.jdt.core.formatter.continuation_indentation=2
|
||||||
|
org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2
|
||||||
|
org.eclipse.jdt.core.formatter.force_if_else_statement_brace=false
|
||||||
|
org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
|
||||||
|
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
|
||||||
|
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
|
||||||
|
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
|
||||||
|
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
|
||||||
|
org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
|
||||||
|
org.eclipse.jdt.core.formatter.indent_empty_lines=false
|
||||||
|
org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
|
||||||
|
org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
|
||||||
|
org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
|
||||||
|
org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false
|
||||||
|
org.eclipse.jdt.core.formatter.indentation.size=4
|
||||||
|
org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
|
||||||
|
org.eclipse.jdt.core.formatter.join_lines_in_comments=true
|
||||||
|
org.eclipse.jdt.core.formatter.join_wrapped_lines=true
|
||||||
|
org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
|
||||||
|
org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
|
||||||
|
org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
|
||||||
|
org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
|
||||||
|
org.eclipse.jdt.core.formatter.lineSplit=80
|
||||||
|
org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
|
||||||
|
org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
|
||||||
|
org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
|
||||||
|
org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1
|
||||||
|
org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true
|
||||||
|
org.eclipse.jdt.core.formatter.sort_local_variable_annotations=false
|
||||||
|
org.eclipse.jdt.core.formatter.sort_member_annotations=false
|
||||||
|
org.eclipse.jdt.core.formatter.sort_package_annotations=false
|
||||||
|
org.eclipse.jdt.core.formatter.sort_parameter_annotations=false
|
||||||
|
org.eclipse.jdt.core.formatter.sort_type_annotations=false
|
||||||
|
org.eclipse.jdt.core.formatter.tabulation.char=mixed
|
||||||
|
org.eclipse.jdt.core.formatter.tabulation.size=8
|
||||||
|
org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
|
||||||
|
org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
|
||||||
|
org.eclipse.jdt.core.formatter.wrap_comment_inline_tags=false
|
||||||
|
org.eclipse.jdt.core.formatter.wrap_non_simple_local_variable_annotation=true
|
||||||
|
org.eclipse.jdt.core.formatter.wrap_non_simple_member_annotation=true
|
||||||
|
org.eclipse.jdt.core.formatter.wrap_non_simple_package_annotation=true
|
||||||
|
org.eclipse.jdt.core.formatter.wrap_non_simple_parameter_annotation=false
|
||||||
|
org.eclipse.jdt.core.formatter.wrap_non_simple_type_annotation=true
|
||||||
|
org.eclipse.jdt.core.formatter.wrap_prefer_two_fragments=false
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
#Thu Oct 13 15:26:00 PDT 2011
|
||||||
|
eclipse.preferences.version=1
|
||||||
|
formatter_profile=org.eclipse.jdt.ui.default.sun_profile
|
||||||
|
formatter_settings_version=11
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
package="com.google.android.apps.mytracks.samples.api"
|
||||||
|
android:versionCode="1"
|
||||||
|
android:versionName="1.0">
|
||||||
|
<uses-sdk android:minSdkVersion="10" />
|
||||||
|
|
||||||
|
<application android:icon="@drawable/icon"
|
||||||
|
android:label="@string/app_name">
|
||||||
|
<activity android:label="@string/app_name"
|
||||||
|
android:name=".MainActivity">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
|
<receiver android:exported="true"
|
||||||
|
android:name=".MyTracksReceiver">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="com.google.android.apps.mytracks.TRACK_STARTED" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="com.google.android.apps.mytracks.TRACK_STOPPED" />
|
||||||
|
</intent-filter>
|
||||||
|
</receiver>
|
||||||
|
</application>
|
||||||
|
|
||||||
|
<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" />
|
||||||
|
</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:10
|
||||||
|
android.library.reference.1=../MyTracksLib
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
-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 * extends android.app.backup.BackupAgentHelper
|
||||||
|
-keep public class * extends android.preference.Preference
|
||||||
|
-keep public class com.android.vending.licensing.ILicensingService
|
||||||
|
|
||||||
|
-keepclasseswithmembernames class * {
|
||||||
|
native <methods>;
|
||||||
|
}
|
||||||
|
|
||||||
|
-keepclasseswithmembers class * {
|
||||||
|
public <init>(android.content.Context, android.util.AttributeSet);
|
||||||
|
}
|
||||||
|
|
||||||
|
-keepclasseswithmembers class * {
|
||||||
|
public <init>(android.content.Context, android.util.AttributeSet, int);
|
||||||
|
}
|
||||||
|
|
||||||
|
-keepclassmembers class * extends android.app.Activity {
|
||||||
|
public void *(android.view.View);
|
||||||
|
}
|
||||||
|
|
||||||
|
-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: 4.0 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.7 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 2.5 KiB |
@@ -0,0 +1,26 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:orientation="vertical"
|
||||||
|
>
|
||||||
|
<Button android:id="@+id/start_recording_button"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:text="@string/start_recording"
|
||||||
|
/>
|
||||||
|
<Button android:id="@+id/stop_recording_button"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:text="@string/stop_recording"
|
||||||
|
/>
|
||||||
|
<Button android:id="@+id/add_waypoints_button"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:text="@string/add_waypoints"
|
||||||
|
/>
|
||||||
|
<TextView android:id="@+id/output"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
/>
|
||||||
|
</LinearLayout>
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<string name="add_waypoints">Add a waypoint to all the tracks</string>
|
||||||
|
<string name="app_name">MyTracksApiSample</string>
|
||||||
|
<string name="start_recording">Start recording</string>
|
||||||
|
<string name="stop_recording">Stop recording</string>
|
||||||
|
</resources>
|
||||||
@@ -0,0 +1,162 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011 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.samples.api;
|
||||||
|
|
||||||
|
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
|
||||||
|
import com.google.android.apps.mytracks.content.Track;
|
||||||
|
import com.google.android.apps.mytracks.content.Waypoint;
|
||||||
|
import com.google.android.apps.mytracks.services.ITrackRecordingService;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.content.ComponentName;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.ServiceConnection;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.os.IBinder;
|
||||||
|
import android.os.RemoteException;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.Button;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An activity to access MyTracks content provider and service.
|
||||||
|
*
|
||||||
|
* Note you must first install MyTracks before installing this app.
|
||||||
|
*
|
||||||
|
* You also need to enable third party application access inside MyTracks
|
||||||
|
* MyTracks -> menu -> Settings -> Sharing -> Allow access
|
||||||
|
*
|
||||||
|
* @author Jimmy Shih
|
||||||
|
*/
|
||||||
|
public class MainActivity extends Activity {
|
||||||
|
|
||||||
|
private static final String TAG = MainActivity.class.getSimpleName();
|
||||||
|
|
||||||
|
// utils to access the MyTracks content provider
|
||||||
|
private MyTracksProviderUtils myTracksProviderUtils;
|
||||||
|
|
||||||
|
// display output from the MyTracks content provider
|
||||||
|
private TextView outputTextView;
|
||||||
|
|
||||||
|
// MyTracks service
|
||||||
|
private ITrackRecordingService myTracksService;
|
||||||
|
|
||||||
|
// intent to access the MyTracks service
|
||||||
|
private Intent intent;
|
||||||
|
|
||||||
|
// connection to the MyTracks service
|
||||||
|
private ServiceConnection serviceConnection = new ServiceConnection() {
|
||||||
|
@Override
|
||||||
|
public void onServiceConnected(ComponentName className, IBinder service) {
|
||||||
|
myTracksService = ITrackRecordingService.Stub.asInterface(service);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onServiceDisconnected(ComponentName className) {
|
||||||
|
myTracksService = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
setContentView(R.layout.main);
|
||||||
|
|
||||||
|
// for the MyTracks content provider
|
||||||
|
myTracksProviderUtils = MyTracksProviderUtils.Factory.get(this);
|
||||||
|
outputTextView = (TextView) findViewById(R.id.output);
|
||||||
|
|
||||||
|
Button addWaypointsButton = (Button) findViewById(R.id.add_waypoints_button);
|
||||||
|
addWaypointsButton.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
List<Track> tracks = myTracksProviderUtils.getAllTracks();
|
||||||
|
Calendar now = Calendar.getInstance();
|
||||||
|
for (Track track : tracks) {
|
||||||
|
Waypoint waypoint = new Waypoint();
|
||||||
|
waypoint.setTrackId(track.getId());
|
||||||
|
waypoint.setName(now.getTime().toLocaleString());
|
||||||
|
waypoint.setDescription(now.getTime().toLocaleString());
|
||||||
|
myTracksProviderUtils.insertWaypoint(waypoint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// for the MyTracks service
|
||||||
|
intent = new Intent();
|
||||||
|
ComponentName componentName = new ComponentName(
|
||||||
|
getString(R.string.mytracks_service_package), getString(R.string.mytracks_service_class));
|
||||||
|
intent.setComponent(componentName);
|
||||||
|
|
||||||
|
Button startRecordingButton = (Button) findViewById(R.id.start_recording_button);
|
||||||
|
startRecordingButton.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
if (myTracksService != null) {
|
||||||
|
try {
|
||||||
|
myTracksService.startNewTrack();
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
Log.e(TAG, "RemoteException", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Button stopRecordingButton = (Button) findViewById(R.id.stop_recording_button);
|
||||||
|
stopRecordingButton.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
if (myTracksService != null) {
|
||||||
|
try {
|
||||||
|
myTracksService.endCurrentTrack();
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
Log.e(TAG, "RemoteException", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onStart() {
|
||||||
|
super.onStart();
|
||||||
|
|
||||||
|
// use the MyTracks content provider to get all the tracks
|
||||||
|
List<Track> tracks = myTracksProviderUtils.getAllTracks();
|
||||||
|
for (Track track : tracks) {
|
||||||
|
outputTextView.append(track.getId() + " ");
|
||||||
|
}
|
||||||
|
|
||||||
|
// start and bind the MyTracks service
|
||||||
|
startService(intent);
|
||||||
|
bindService(intent, serviceConnection, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onStop() {
|
||||||
|
super.onStop();
|
||||||
|
|
||||||
|
// unbind and stop the MyTracks service
|
||||||
|
if (myTracksService != null) {
|
||||||
|
unbindService(serviceConnection);
|
||||||
|
}
|
||||||
|
stopService(intent);
|
||||||
|
}
|
||||||
|
}
|
||||||
+36
@@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011 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.samples.api;
|
||||||
|
|
||||||
|
import android.content.BroadcastReceiver;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A receiver to receive MyTracks notifications.
|
||||||
|
*
|
||||||
|
* @author Jimmy Shih
|
||||||
|
*/
|
||||||
|
public class MyTracksReceiver extends BroadcastReceiver {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onReceive(Context context, Intent intent) {
|
||||||
|
String action = intent.getAction();
|
||||||
|
long trackId = intent.getLongExtra(context.getString(R.string.track_id_broadcast_extra), -1L);
|
||||||
|
Toast.makeText(context, action + " " + trackId, Toast.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -23,20 +23,9 @@ limitations under the License.
|
|||||||
|
|
||||||
<!-- Broadcast notification Intent constants -->
|
<!-- Broadcast notification Intent constants -->
|
||||||
<string name="track_started_broadcast_action">com.google.android.apps.mytracks.TRACK_STARTED</string>
|
<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_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>
|
<string name="track_id_broadcast_extra">com.google.android.apps.mytracks.TRACK_ID</string>
|
||||||
|
|
||||||
<!-- TrackRecordingService actions -->
|
|
||||||
<string name="start_new_track_action">com.google.android.apps.mytracks.START_NEW_TRACK</string>
|
|
||||||
<!--
|
|
||||||
Setting this intent makes the new track the selected track.
|
|
||||||
This is not expected to work if the my tracks activity is currently active.
|
|
||||||
-->
|
|
||||||
<string name="select_new_track_extra">com.google.android.apps.mytracks.SELECT_NEW_TRACK</string>
|
|
||||||
<string name="end_current_track_action">com.google.android.apps.mytracks.END_CURRENT_TRACK</string>
|
|
||||||
|
|
||||||
<!-- My Tracks service constants -->
|
<!-- My Tracks service constants -->
|
||||||
<string name="mytracks_service_class">com.google.android.apps.mytracks.services.TrackRecordingService</string>
|
<string name="mytracks_service_class">com.google.android.apps.mytracks.services.TrackRecordingService</string>
|
||||||
<string name="mytracks_service_package">com.google.android.maps.mytracks</string>
|
<string name="mytracks_service_package">com.google.android.maps.mytracks</string>
|
||||||
|
|||||||
@@ -16,112 +16,43 @@
|
|||||||
package com.google.android.apps.mytracks;
|
package com.google.android.apps.mytracks;
|
||||||
|
|
||||||
import com.google.android.apps.mytracks.content.Waypoint;
|
import com.google.android.apps.mytracks.content.Waypoint;
|
||||||
import com.google.android.maps.GeoPoint;
|
import com.google.android.apps.mytracks.maps.SingleColorTrackPathPainter;
|
||||||
import com.google.android.maps.MapView;
|
import com.google.android.maps.MapView;
|
||||||
import com.google.android.maps.Projection;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
import android.graphics.Path;
|
import android.graphics.Path;
|
||||||
import android.graphics.Point;
|
|
||||||
import android.graphics.PointF;
|
|
||||||
import android.graphics.Rect;
|
|
||||||
import android.location.Location;
|
import android.location.Location;
|
||||||
import android.test.AndroidTestCase;
|
import android.test.AndroidTestCase;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for the MyTracks map overlay.
|
* Tests for the MyTracks map overlay.
|
||||||
*
|
*
|
||||||
* @author Bartlomiej Niechwiej
|
* @author Bartlomiej Niechwiej
|
||||||
|
* @author Vangelis S.
|
||||||
*/
|
*/
|
||||||
public class MapOverlayTest extends AndroidTestCase {
|
public class MapOverlayTest extends AndroidTestCase {
|
||||||
private Canvas canvas;
|
private Canvas canvas;
|
||||||
private MockMyTracksOverlay myTracksOverlay;
|
private MockMyTracksOverlay myTracksOverlay;
|
||||||
private MapView mockView;
|
private MapView mockView;
|
||||||
private Projection mockProjection;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A mock version of {@code MapOverlay} that does not use
|
|
||||||
* {@class MapView}.
|
|
||||||
*/
|
|
||||||
private class MockMyTracksOverlay extends MapOverlay {
|
|
||||||
public MockMyTracksOverlay(Context context) {
|
|
||||||
super(context);
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
Projection getMapProjection(MapView mapView) {
|
|
||||||
return mockProjection;
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
Rect getMapViewRect(MapView mapView) {
|
|
||||||
return new Rect(0, 0, 100, 100);
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
Path newPath() {
|
|
||||||
return new MockPath();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A mock class that intercepts {@code Path}'s and records calls to
|
|
||||||
* {@code #moveTo()} and {@code #lineTo()}.
|
|
||||||
*/
|
|
||||||
private static class MockPath extends Path {
|
|
||||||
/** A list of disjoined path segments. */
|
|
||||||
public final List<List<PointF>> segments = new LinkedList<List<PointF>>();
|
|
||||||
/** The total number of points in this path. */
|
|
||||||
public int totalPoints;
|
|
||||||
|
|
||||||
private List<PointF> currentSegment;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void lineTo(float x, float y) {
|
|
||||||
super.lineTo(x, y);
|
|
||||||
assertNotNull(currentSegment);
|
|
||||||
currentSegment.add(new PointF(x, y));
|
|
||||||
totalPoints++;
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public void moveTo(float x, float y) {
|
|
||||||
super.moveTo(x, y);
|
|
||||||
segments.add(currentSegment =
|
|
||||||
new ArrayList<PointF>(Arrays.asList(new PointF(x, y))));
|
|
||||||
totalPoints++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A mock {@code Projection} that acts as the identity matrix.
|
|
||||||
*/
|
|
||||||
private static class MockProjection implements Projection {
|
|
||||||
@Override
|
|
||||||
public Point toPixels(GeoPoint in, Point out) {
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public float metersToEquatorPixels(float meters) {
|
|
||||||
return meters;
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public GeoPoint fromPixels(int x, int y) {
|
|
||||||
return new GeoPoint(y, x);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void setUp() throws Exception {
|
protected void setUp() throws Exception {
|
||||||
super.setUp();
|
super.setUp();
|
||||||
canvas = new Canvas();
|
canvas = new Canvas();
|
||||||
myTracksOverlay = new MockMyTracksOverlay(getContext());
|
myTracksOverlay = new MockMyTracksOverlay(getContext());
|
||||||
|
|
||||||
// Enable drawing.
|
// Enable drawing.
|
||||||
myTracksOverlay.setTrackDrawingEnabled(true);
|
myTracksOverlay.setTrackDrawingEnabled(true);
|
||||||
|
|
||||||
|
// Set a TrackPathPainter with a MockPath.
|
||||||
|
myTracksOverlay.setTrackPathPainter(new SingleColorTrackPathPainter(getContext()) {
|
||||||
|
@Override
|
||||||
|
public Path newPath() {
|
||||||
|
return new MockPath();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
mockView = null;
|
mockView = null;
|
||||||
mockProjection = new MockProjection();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testAddLocation() throws Exception {
|
public void testAddLocation() throws Exception {
|
||||||
@@ -137,19 +68,21 @@ public class MapOverlayTest extends AndroidTestCase {
|
|||||||
myTracksOverlay.addLocation(location);
|
myTracksOverlay.addLocation(location);
|
||||||
assertEquals(2, myTracksOverlay.getNumLocations());
|
assertEquals(2, myTracksOverlay.getNumLocations());
|
||||||
assertEquals(0, myTracksOverlay.getNumWaypoints());
|
assertEquals(0, myTracksOverlay.getNumWaypoints());
|
||||||
assertNull(myTracksOverlay.getLastPath());
|
assertNull(myTracksOverlay.getTrackPathPainter().getLastPath());
|
||||||
|
|
||||||
// Draw and make sure that we don't lose any point.
|
// Draw and make sure that we don't lose any point.
|
||||||
myTracksOverlay.draw(canvas, mockView, false);
|
myTracksOverlay.draw(canvas, mockView, false);
|
||||||
assertEquals(2, myTracksOverlay.getNumLocations());
|
assertEquals(2, myTracksOverlay.getNumLocations());
|
||||||
assertEquals(0, myTracksOverlay.getNumWaypoints());
|
assertEquals(0, myTracksOverlay.getNumWaypoints());
|
||||||
assertNotNull(myTracksOverlay.getLastPath());
|
assertNotNull(myTracksOverlay.getTrackPathPainter().getLastPath());
|
||||||
assertEquals(2, ((MockPath)myTracksOverlay.getLastPath()).totalPoints);
|
assertTrue(myTracksOverlay.getTrackPathPainter().getLastPath() instanceof MockPath);
|
||||||
|
MockPath path = (MockPath) myTracksOverlay.getTrackPathPainter().getLastPath();
|
||||||
|
assertEquals(2, path.totalPoints);
|
||||||
|
|
||||||
myTracksOverlay.draw(canvas, mockView, true);
|
myTracksOverlay.draw(canvas, mockView, true);
|
||||||
assertEquals(2, myTracksOverlay.getNumLocations());
|
assertEquals(2, myTracksOverlay.getNumLocations());
|
||||||
assertEquals(0, myTracksOverlay.getNumWaypoints());
|
assertEquals(0, myTracksOverlay.getNumWaypoints());
|
||||||
assertNotNull(myTracksOverlay.getLastPath());
|
assertNotNull(myTracksOverlay.getTrackPathPainter().getLastPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testClearPoints() throws Exception {
|
public void testClearPoints() throws Exception {
|
||||||
@@ -182,7 +115,7 @@ public class MapOverlayTest extends AndroidTestCase {
|
|||||||
myTracksOverlay.addWaypoint(waypoint);
|
myTracksOverlay.addWaypoint(waypoint);
|
||||||
assertEquals(1, myTracksOverlay.getNumWaypoints());
|
assertEquals(1, myTracksOverlay.getNumWaypoints());
|
||||||
assertEquals(0, myTracksOverlay.getNumLocations());
|
assertEquals(0, myTracksOverlay.getNumLocations());
|
||||||
assertNull(myTracksOverlay.getLastPath());
|
assertNull(myTracksOverlay.getTrackPathPainter().getLastPath());
|
||||||
|
|
||||||
final int waypoints = 10;
|
final int waypoints = 10;
|
||||||
for (int i = 0; i < waypoints; ++i) {
|
for (int i = 0; i < waypoints; ++i) {
|
||||||
@@ -192,7 +125,7 @@ public class MapOverlayTest extends AndroidTestCase {
|
|||||||
}
|
}
|
||||||
assertEquals(1 + waypoints, myTracksOverlay.getNumWaypoints());
|
assertEquals(1 + waypoints, myTracksOverlay.getNumWaypoints());
|
||||||
assertEquals(0, myTracksOverlay.getNumLocations());
|
assertEquals(0, myTracksOverlay.getNumLocations());
|
||||||
assertNull(myTracksOverlay.getLastPath());
|
assertNull(myTracksOverlay.getTrackPathPainter().getLastPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testClearWaypoints() throws Exception {
|
public void testClearWaypoints() throws Exception {
|
||||||
@@ -226,15 +159,15 @@ public class MapOverlayTest extends AndroidTestCase {
|
|||||||
// Shadow.
|
// Shadow.
|
||||||
myTracksOverlay.draw(canvas, mockView, true);
|
myTracksOverlay.draw(canvas, mockView, true);
|
||||||
// We don't expect to do anything if
|
// We don't expect to do anything if
|
||||||
assertNull(myTracksOverlay.getLastPath());
|
assertNull(myTracksOverlay.getTrackPathPainter().getLastPath());
|
||||||
assertEquals(40, myTracksOverlay.getNumWaypoints());
|
assertEquals(40, myTracksOverlay.getNumWaypoints());
|
||||||
assertEquals(100, myTracksOverlay.getNumLocations());
|
assertEquals(100, myTracksOverlay.getNumLocations());
|
||||||
|
|
||||||
// No shadow.
|
// No shadow.
|
||||||
myTracksOverlay.draw(canvas, mockView, false);
|
myTracksOverlay.draw(canvas, mockView, false);
|
||||||
assertNotNull(myTracksOverlay.getLastPath());
|
assertNotNull(myTracksOverlay.getTrackPathPainter().getLastPath());
|
||||||
assertTrue(myTracksOverlay.getLastPath() instanceof MockPath);
|
assertTrue(myTracksOverlay.getTrackPathPainter().getLastPath() instanceof MockPath);
|
||||||
MockPath path = (MockPath) myTracksOverlay.getLastPath();
|
MockPath path = (MockPath) myTracksOverlay.getTrackPathPainter().getLastPath();
|
||||||
assertEquals(40, myTracksOverlay.getNumWaypoints());
|
assertEquals(40, myTracksOverlay.getNumWaypoints());
|
||||||
assertEquals(100, myTracksOverlay.getNumLocations());
|
assertEquals(100, myTracksOverlay.getNumLocations());
|
||||||
assertEquals(100, path.totalPoints);
|
assertEquals(100, path.totalPoints);
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011 Google Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
* use this file except in compliance with the License. You may obtain a copy of
|
||||||
|
* the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations under
|
||||||
|
* the License.
|
||||||
|
*/
|
||||||
|
package com.google.android.apps.mytracks;
|
||||||
|
|
||||||
|
import com.google.android.maps.MapView;
|
||||||
|
import com.google.android.maps.Projection;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.graphics.Rect;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Elements for Tests for the MyTracks map overlay.
|
||||||
|
*
|
||||||
|
* @author Bartlomiej Niechwiej
|
||||||
|
* @author Vangelis S.
|
||||||
|
*
|
||||||
|
* A mock version of {@code MapOverlay} that does not use
|
||||||
|
* {@class MapView}.
|
||||||
|
*/
|
||||||
|
public class MockMyTracksOverlay extends MapOverlay {
|
||||||
|
|
||||||
|
private Projection mockProjection;
|
||||||
|
|
||||||
|
public MockMyTracksOverlay(Context context) {
|
||||||
|
super(context);
|
||||||
|
mockProjection = new MockProjection();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Projection getMapProjection(MapView mapView) {
|
||||||
|
return mockProjection;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Rect getMapViewRect(MapView mapView) {
|
||||||
|
return new Rect(0, 0, 100, 100);
|
||||||
|
}
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user