diff --git a/.hgignore b/.hgignore
index 1c3f1f5a7..ffa8823b5 100644
--- a/.hgignore
+++ b/.hgignore
@@ -7,3 +7,5 @@ syntax:glob
MyTracksTest/annotations.log
**/*.pyc
**/*.pyo
+syntax: glob
+MyTracksTest/hs_err_pid*.log
diff --git a/MyTracks/.classpath b/MyTracks/.classpath
index 4a0943047..b65e415b1 100644
--- a/MyTracks/.classpath
+++ b/MyTracks/.classpath
@@ -1,13 +1,24 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/MyTracks/.project b/MyTracks/.project
index 5a87d6231..4ff12bb43 100644
--- a/MyTracks/.project
+++ b/MyTracks/.project
@@ -1,41 +1,41 @@
-
-
- MyTracks
-
-
- MyTracksLib
-
-
-
- com.android.ide.eclipse.adt.ResourceManagerBuilder
-
-
-
-
- com.android.ide.eclipse.adt.PreCompilerBuilder
-
-
-
-
- org.eclipse.jdt.core.javabuilder
-
-
-
-
- com.android.ide.eclipse.adt.ApkBuilder
-
-
-
-
-
- com.android.ide.eclipse.adt.AndroidNature
- org.eclipse.jdt.core.javanature
-
-
-
- MyTracksLib_src
- 2
- _android_MyTracksLib_e2802071/src
-
-
-
+
+
+ MyTracks
+
+
+ MyTracksLib
+
+
+
+ com.android.ide.eclipse.adt.ResourceManagerBuilder
+
+
+
+
+ com.android.ide.eclipse.adt.PreCompilerBuilder
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ com.android.ide.eclipse.adt.ApkBuilder
+
+
+
+
+
+ com.android.ide.eclipse.adt.AndroidNature
+ org.eclipse.jdt.core.javanature
+
+
+
+ MyTracksLib_src
+ 2
+ _android_MyTracksLib_e2802071/src
+
+
+
diff --git a/MyTracks/default.properties b/MyTracks/default.properties
index ee3f68e34..75e62f9cb 100644
--- a/MyTracks/default.properties
+++ b/MyTracks/default.properties
@@ -13,7 +13,5 @@ split.density=false
target=Google Inc.:Google APIs:13
android.library.reference.1=../MyTracksLib/
-# ProGuard is turned off while we investigate the removal of code that
-# isn't actually dead from Fusion Tables. See issue 303 for an example of
-# the result of that removal.
-#proguard.config=proguard.cfg
+# Enable proguard.
+proguard.config=proguard.cfg
diff --git a/MyTracks/libs/README.txt b/MyTracks/libs/README.txt
index 62e619f85..0df5b07bb 100644
--- a/MyTracks/libs/README.txt
+++ b/MyTracks/libs/README.txt
@@ -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
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):
-http://code.google.com/p/google-api-java-client/
+google-common.jar
-google-common.jar,
-googleloginclient-helper.jar,
-libmymaps.jar (Google My Maps upload library):
-Licensed exclusively for use in My Tracks and derived Android applications.
+googleloginclient-helper.jar
+
+libGoogleAnalytics.jar
+- see http://code.google.com/mobile/analytics/docs/.
diff --git a/MyTracks/libs/google-api-client-1.2.2-alpha.jar b/MyTracks/libs/google-api-client-1.2.2-alpha.jar
deleted file mode 100644
index 7194648fd..000000000
Binary files a/MyTracks/libs/google-api-client-1.2.2-alpha.jar and /dev/null differ
diff --git a/MyTracks/libs/google-api-client/commons-codec-1.3.jar b/MyTracks/libs/google-api-client/commons-codec-1.3.jar
new file mode 100644
index 000000000..957b6752a
Binary files /dev/null and b/MyTracks/libs/google-api-client/commons-codec-1.3.jar differ
diff --git a/MyTracks/libs/google-api-client/commons-logging-1.1.1.jar b/MyTracks/libs/google-api-client/commons-logging-1.1.1.jar
new file mode 100644
index 000000000..1deef144c
Binary files /dev/null and b/MyTracks/libs/google-api-client/commons-logging-1.1.1.jar differ
diff --git a/MyTracks/libs/google-api-client/google-api-client-1.5.0-beta.jar b/MyTracks/libs/google-api-client/google-api-client-1.5.0-beta.jar
new file mode 100644
index 000000000..41f2e578e
Binary files /dev/null and b/MyTracks/libs/google-api-client/google-api-client-1.5.0-beta.jar differ
diff --git a/MyTracks/libs/google-api-client/google-http-client-1.5.0-beta.jar b/MyTracks/libs/google-api-client/google-http-client-1.5.0-beta.jar
new file mode 100644
index 000000000..b5e610ddf
Binary files /dev/null and b/MyTracks/libs/google-api-client/google-http-client-1.5.0-beta.jar differ
diff --git a/MyTracks/libs/google-api-client/google-oauth-client-1.5.0-beta.jar b/MyTracks/libs/google-api-client/google-oauth-client-1.5.0-beta.jar
new file mode 100644
index 000000000..af73e9aa4
Binary files /dev/null and b/MyTracks/libs/google-api-client/google-oauth-client-1.5.0-beta.jar differ
diff --git a/MyTracks/libs/google-api-client/gson-1.6.jar b/MyTracks/libs/google-api-client/gson-1.6.jar
new file mode 100644
index 000000000..40648939f
Binary files /dev/null and b/MyTracks/libs/google-api-client/gson-1.6.jar differ
diff --git a/MyTracks/libs/google-api-client/guava-r09.jar b/MyTracks/libs/google-api-client/guava-r09.jar
new file mode 100644
index 000000000..30dbc5692
Binary files /dev/null and b/MyTracks/libs/google-api-client/guava-r09.jar differ
diff --git a/MyTracks/libs/google-api-client/httpclient-4.0.3.jar b/MyTracks/libs/google-api-client/httpclient-4.0.3.jar
new file mode 100644
index 000000000..16e349a48
Binary files /dev/null and b/MyTracks/libs/google-api-client/httpclient-4.0.3.jar differ
diff --git a/MyTracks/libs/google-api-client/httpcore-4.0.1.jar b/MyTracks/libs/google-api-client/httpcore-4.0.1.jar
new file mode 100644
index 000000000..4aef35e2f
Binary files /dev/null and b/MyTracks/libs/google-api-client/httpcore-4.0.1.jar differ
diff --git a/MyTracks/libs/google-api-client/jackson-core-asl-1.6.7.jar b/MyTracks/libs/google-api-client/jackson-core-asl-1.6.7.jar
new file mode 100644
index 000000000..7c1207210
Binary files /dev/null and b/MyTracks/libs/google-api-client/jackson-core-asl-1.6.7.jar differ
diff --git a/MyTracks/libs/google-api-client/jsr305-1.3.9.jar b/MyTracks/libs/google-api-client/jsr305-1.3.9.jar
new file mode 100644
index 000000000..a9afc6619
Binary files /dev/null and b/MyTracks/libs/google-api-client/jsr305-1.3.9.jar differ
diff --git a/MyTracks/libs/google-api-client/junit-4.8.2.jar b/MyTracks/libs/google-api-client/junit-4.8.2.jar
new file mode 100644
index 000000000..5b4bb849a
Binary files /dev/null and b/MyTracks/libs/google-api-client/junit-4.8.2.jar differ
diff --git a/MyTracks/proguard.cfg b/MyTracks/proguard.cfg
index 8a6087a72..8b178c6b8 100644
--- a/MyTracks/proguard.cfg
+++ b/MyTracks/proguard.cfg
@@ -51,3 +51,15 @@
-keep class * implements android.os.Parcelable {
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 ;
+}
+
+-keepattributes Signature,RuntimeVisibleAnnotations,AnnotationDefault
+
+# Needed by Guava
+
+-dontwarn sun.misc.Unsafe
diff --git a/MyTracks/res/values/arrays_do_not_translate.xml b/MyTracks/res/values/arrays_do_not_translate.xml
index 25f173930..89c48c308 100644
--- a/MyTracks/res/values/arrays_do_not_translate.xml
+++ b/MyTracks/res/values/arrays_do_not_translate.xml
@@ -118,4 +118,16 @@ limitations under the License.
- @string/ant_sensor_type
- @string/srm_ant_bridge_sensor_type
+
+
+ - @string/track_color_mode_none
+ - @string/track_color_mode_fixed
+ - @string/track_color_mode_dynamic
+
+
+
+ - @string/none
+ - @string/track_color_mode_fixed
+ - @string/track_color_mode_dynamic
+
diff --git a/MyTracks/res/values/colors.xml b/MyTracks/res/values/colors.xml
index 803446580..eca05f9d7 100644
--- a/MyTracks/res/values/colors.xml
+++ b/MyTracks/res/values/colors.xml
@@ -51,4 +51,14 @@ limitations under the License.
#EDEDED
#99999999
+
+
+
+ #F774DF00
+
+
+ #F75858FA
+
+
+ #F7DF0101
diff --git a/MyTracks/res/values/keys.xml b/MyTracks/res/values/keys.xml
index 24794476e..add11edba 100644
--- a/MyTracks/res/values/keys.xml
+++ b/MyTracks/res/values/keys.xml
@@ -41,7 +41,13 @@ limitations under the License.
shareUrlOnly
splitFrequency
timestampTrackName
-
+ trackColorMode
+ trackColorModeFixedSlow
+ trackColorModeFixedMedium
+ trackColorModeFixedSlowDisplay
+ trackColorModeFixedMediumDisplay
+ trackColorModeDynamicVariation
+
autoResumeTrackCurrentRetry
recordingTrack
@@ -54,4 +60,5 @@ limitations under the License.
sensorOptions
antOptions
displaySettingsScreen
+ trackColorModeFixedOptions
diff --git a/MyTracks/res/values/strings.xml b/MyTracks/res/values/strings.xml
index 0f78c57a2..2ab353a40 100644
--- a/MyTracks/res/values/strings.xml
+++ b/MyTracks/res/values/strings.xml
@@ -268,6 +268,17 @@ limitations under the License.
The bluetooth sensor to connect to
Modular Stats Display
+ Track Color Mode
+ The way to color the track
+ Fixed
+ Dynamic
+ Fixed Speed Slow
+ Slow speed top value
+ Fixed Speed Medium
+ Medium speed top value
+ Dynamic Speed Variation
+ % Margin from average speed to consider medium speed
+
Backup (BETA)
SD Card Backup
@@ -483,7 +494,10 @@ limitations under the License.
bluetoothSensorsEnabled
ANT options
Sensor Options
-
+ Track Color Mode
+ Fixed Speed Options
+ Dynamic Speed Options
+
Connected to %s
Bluetooth sensor connecting ...
@@ -517,4 +531,8 @@ limitations under the License.
Polar Bluetooth
Zephyr Bluetooth
+
+ None
+ Fixed (BETA)
+ Dynamic (BETA)
diff --git a/MyTracks/res/xml/preferences.xml b/MyTracks/res/xml/preferences.xml
index b1dfb8ee9..f4cb8d523 100644
--- a/MyTracks/res/xml/preferences.xml
+++ b/MyTracks/res/xml/preferences.xml
@@ -33,6 +33,58 @@ limitations under the License.
android:summaryOn="@string/settings_report_speed_or_pace_summary_on"
android:summaryOff="@string/settings_report_speed_or_pace_summary_off"
android:defaultValue="true" />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/MyTracks/src/com/google/android/apps/mytracks/ColoredPath.java b/MyTracks/src/com/google/android/apps/mytracks/ColoredPath.java
new file mode 100644
index 000000000..be34ced2a
--- /dev/null
+++ b/MyTracks/src/com/google/android/apps/mytracks/ColoredPath.java
@@ -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;
+ }
+}
\ No newline at end of file
diff --git a/MyTracks/src/com/google/android/apps/mytracks/ImportAllTracks.java b/MyTracks/src/com/google/android/apps/mytracks/ImportAllTracks.java
index e36c76197..dfea7d5d5 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/ImportAllTracks.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/ImportAllTracks.java
@@ -217,4 +217,4 @@ public class ImportAllTracks {
}
return gpxFiles;
}
-}
+}
\ No newline at end of file
diff --git a/MyTracks/src/com/google/android/apps/mytracks/MapOverlay.java b/MyTracks/src/com/google/android/apps/mytracks/MapOverlay.java
index 0203d8d6b..b26d4a0b0 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/MapOverlay.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/MapOverlay.java
@@ -18,6 +18,9 @@ package com.google.android.apps.mytracks;
import static com.google.android.apps.mytracks.Constants.TAG;
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.maps.GeoPoint;
import com.google.android.maps.MapView;
@@ -27,6 +30,8 @@ import com.google.android.maps.mytracks.R;
import android.content.Context;
import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Paint;
@@ -48,7 +53,7 @@ import java.util.concurrent.BlockingQueue;
*
* @author Leif Hendrik Wilden
*/
-public class MapOverlay extends Overlay {
+public class MapOverlay extends Overlay implements OnSharedPreferenceChangeListener {
private final Drawable[] arrows;
private final int arrowWidth, arrowHeight;
@@ -57,7 +62,6 @@ public class MapOverlay extends Overlay {
private final Drawable startMarker;
private final Drawable endMarker;
private final int markerWidth, markerHeight;
- private final Paint selectedTrackPaint;
private final Paint errorCirclePaint;
private final Context context;
private final List waypoints;
@@ -73,22 +77,26 @@ public class MapOverlay extends Overlay {
private GeoPoint lastReferencePoint;
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.
* 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 GeoPoint geoPoint;
-
+ public final int speed;
+
/**
* Constructor for an invalid cached location.
*/
public CachedLocation() {
this.valid = false;
this.geoPoint = null;
+ this.speed = -1;
}
/**
@@ -97,6 +105,7 @@ public class MapOverlay extends Overlay {
public CachedLocation(Location location) {
this.valid = LocationUtils.isValidLocation(location);
this.geoPoint = valid ? LocationUtils.getGeoPoint(location) : null;
+ this.speed = (int) Math.floor(location.getSpeed() * 3.6);
}
};
@@ -151,18 +160,13 @@ public class MapOverlay extends Overlay {
waypointMarker = resources.getDrawable(R.drawable.blue_pushpin);
waypointMarker.setBounds(0, 0, markerWidth, markerHeight);
- selectedTrackPaint = new Paint();
- 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 = TrackPathUtilities.getPaint(R.color.blue, context);
errorCirclePaint.setAlpha(127);
- errorCirclePaint.setAntiAlias(true);
+
+ trackPathPainter = TrackPathPainterFactory.getTrackPathPainter(context);
+
+ context.getSharedPreferences(Constants.SETTINGS_NAME, 0)
+ .registerOnSharedPreferenceChangeListener(this);
}
/**
@@ -205,18 +209,19 @@ public class MapOverlay extends Overlay {
}
// Visible for testing.
- int getNumWaypoints() {
+ public int getNumWaypoints() {
synchronized (waypoints) {
return waypoints.size();
}
}
public void clearPoints() {
- synchronized (points) {
- points.clear();
+ synchronized (getPoints()) {
+ getPoints().clear();
pendingPoints.clear();
- lastPath = null;
+ lastPathExists = false;
lastViewRect = null;
+ trackPathPainter.clear();
}
}
@@ -254,6 +259,9 @@ public class MapOverlay extends Overlay {
// Draw the selected track:
drawTrack(canvas, projection, viewRect);
+ // Draw the "Start" and "End" markers:
+ drawMarkers(canvas, projection);
+
// Draw the waypoints:
drawWaypoints(canvas, projection);
}
@@ -262,6 +270,28 @@ public class MapOverlay extends Overlay {
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.
Projection getMapProjection(MapView mapView) {
return mapView.getProjection();
@@ -282,10 +312,10 @@ public class MapOverlay extends Overlay {
}
// Visible for testing.
- Path getLastPath() {
- return lastPath;
+ public Path getLastPath() {
+ return trackPathPainter.getLastPath();
}
-
+
private void drawWaypoints(Canvas canvas, Projection projection) {
synchronized (waypoints) {;
for (Waypoint wpt : waypoints) {
@@ -311,96 +341,39 @@ public class MapOverlay extends Overlay {
canvas.drawCircle(pt.x, pt.y, radius, errorCirclePaint);
}
- private void drawTrack(Canvas canvas, Projection projection, Rect viewRect) {
- Path path;
+ private void drawTrack(Canvas canvas, Projection projection, Rect viewRect)
+ {
+ boolean draw;
+
synchronized (points) {
// Merge the pending points with the list of cached locations.
final GeoPoint referencePoint = projection.fromPixels(0, 0);
- int newPoints = pendingPoints.drainTo(points);
+ int newPoints = pendingPoints.drainTo(points);
boolean newProjection = !viewRect.equals(lastViewRect) ||
- !referencePoint.equals(lastReferencePoint);
- if (newPoints == 0 && lastPath != null && !newProjection) {
+ !referencePoint.equals(lastReferencePoint);
+ if (newPoints == 0 && lastPathExists && !newProjection) {
// No need to recreate path (same points and viewing area).
- path = lastPath;
+ draw = true;
} else {
int numPoints = points.size();
if (numPoints < 2) {
// Not enough points to draw a path.
- path = null;
- } else if (lastPath != null && !newProjection) {
+ draw = false;
+ } else if (!trackPathPainter.needsRedraw() && lastPathExists && !newProjection) {
// Incremental update of the path, without repositioning the view.
- path = lastPath;
- updatePath(projection, viewRect, path, numPoints - newPoints);
+ draw = true;
+ trackPathPainter.updatePath(projection, viewRect, numPoints - newPoints, alwaysVisible, points);
} else {
// The view has changed so we have to start from scratch.
- path = newPath();
- path.incReserve(numPoints);
- updatePath(projection, viewRect, path, 0);
+ draw = true;
+ trackPathPainter.updatePath(projection, viewRect, 0, alwaysVisible, points);
}
- lastPath = path;
}
lastReferencePoint = referencePoint;
lastViewRect = viewRect;
}
- if (path != null) {
- canvas.drawPath(path, selectedTrackPaint);
- }
-
- // 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);
- }
+ if (draw) {
+ trackPathPainter.drawTrack(canvas);
}
}
@@ -479,4 +452,21 @@ public class MapOverlay extends Overlay {
}
return super.onTap(p, mapView);
}
+
+ /**
+ * @return the points
+ */
+ public List 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);
+ }
+ }
+ }
}
diff --git a/MyTracks/src/com/google/android/apps/mytracks/SettingsActivity.java b/MyTracks/src/com/google/android/apps/mytracks/SettingsActivity.java
index 960deb69b..559d9af31 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/SettingsActivity.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/SettingsActivity.java
@@ -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.util.ApiFeatures;
import com.google.android.apps.mytracks.util.BluetoothDeviceUtils;
+import com.google.android.apps.mytracks.util.UnitConversions;
import com.google.android.maps.mytracks.R;
import android.app.AlertDialog;
@@ -32,11 +33,13 @@ import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.CheckBoxPreference;
+import android.preference.EditTextPreference;
import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.Preference.OnPreferenceChangeListener;
import android.preference.Preference.OnPreferenceClickListener;
import android.preference.PreferenceActivity;
+import android.preference.PreferenceCategory;
import android.preference.PreferenceManager;
import android.preference.PreferenceScreen;
import android.provider.Settings;
@@ -128,7 +131,8 @@ public class SettingsActivity extends PreferenceActivity {
updatePreferenceUnits(metricUnitsPreference.isChecked());
customizeSensorOptionsPreferences();
-
+ customizeTrackColorModePreferences();
+
// Hook up action for resetting all settings
Preference resetPreference = findPreference(getString(R.string.reset_key));
resetPreference.setOnPreferenceClickListener(new OnPreferenceClickListener() {
@@ -203,6 +207,29 @@ public class SettingsActivity extends PreferenceActivity {
sensorOptionsScreen.removePreference(findPreference(getString(R.string.ant_options_key)));
}
}
+
+ 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
protected void onResume() {
@@ -288,6 +315,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
* the proper unit the user has selected.
@@ -416,4 +455,84 @@ public class SettingsActivity extends PreferenceActivity {
}
}.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;
+ }
+ });
+ }
}
diff --git a/MyTracks/src/com/google/android/apps/mytracks/io/SendToFusionTables.java b/MyTracks/src/com/google/android/apps/mytracks/io/SendToFusionTables.java
index f830abe6d..f8b7e1f69 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/io/SendToFusionTables.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/io/SendToFusionTables.java
@@ -26,20 +26,23 @@ 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.stats.DoubleBuffer;
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.StringUtils;
import com.google.android.apps.mytracks.util.SystemUtils;
import com.google.android.apps.mytracks.util.UnitConversions;
import com.google.android.maps.mytracks.R;
import com.google.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.HttpRequest;
+import com.google.api.client.http.HttpRequestFactory;
import com.google.api.client.http.HttpResponse;
import com.google.api.client.http.HttpResponseException;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.InputStreamContent;
-import com.google.api.client.javanet.NetHttpTransport;
+import com.google.api.client.http.apache.ApacheHttpTransport;
+import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.util.Strings;
import android.app.Activity;
@@ -64,6 +67,8 @@ import java.util.Vector;
*/
public class SendToFusionTables implements Runnable {
+ private static final String CONTENT_TYPE = "application/x-www-form-urlencoded";
+
/**
* Listener invoked when sending to fusion tables completes.
*/
@@ -118,22 +123,15 @@ public class SendToFusionTables implements Runnable {
private int totalLocations;
private int totalSegmentsUploaded;
- private HttpTransport transport;
+ private HttpRequestFactory httpRequestFactory;
private String tableId;
private static String MARKER_TYPE_START = "large_green";
private static String MARKER_TYPE_END = "large_red";
private static String MARKER_TYPE_WAYPOINT = "large_yellow";
- static {
- // We manually assign the transport to avoid having HttpTransport try to
- // 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) {
+ public SendToFusionTables(Activity context, AuthManager auth, long trackId,
+ ProgressIndicator progressIndicator, OnSendCompletedListener onCompletion) {
this.context = context;
this.auth = auth;
this.trackId = trackId;
@@ -142,13 +140,9 @@ public class SendToFusionTables implements Runnable {
this.stringUtils = new StringUtils(context);
this.providerUtils = MyTracksProviderUtils.Factory.get(context);
- GoogleHeaders headers = new GoogleHeaders();
- headers.setApplicationName("Google-MyTracks-" + SystemUtils.getMyTracksVersion(context));
- headers.gdataVersion = GDATA_VERSION;
-
- transport = new HttpTransport();
- MethodOverrideIntercepter.setAsFirstFor(transport);
- transport.defaultHeaders = headers;
+ HttpTransport transport = ApiFeatures.getInstance().useNetHttpTransport()
+ ? new NetHttpTransport() : new ApacheHttpTransport();
+ httpRequestFactory = transport.createRequestFactory(new MethodOverride());
}
@Override
@@ -177,7 +171,6 @@ public class SendToFusionTables implements Runnable {
}
private void doUpload() {
- ((GoogleHeaders) transport.defaultHeaders).setGoogleLogin(auth.getAuthToken());
int statusMessageId = R.string.error_sending_to_fusiontables;
boolean success = true;
try {
@@ -280,7 +273,7 @@ public class SendToFusionTables implements Runnable {
*
* @param name the marker name
* @param description the marker description
- * @param the marker location
+ * @param location the marker location
* @return true in case of success.
*/
private boolean createNewPoint(String name, String description, Location location,
@@ -306,7 +299,6 @@ public class SendToFusionTables implements Runnable {
}
private boolean uploadAllTrackPoints(final Track track, String originalDescription) {
-
SharedPreferences preferences = context.getSharedPreferences(Constants.SETTINGS_NAME, 0);
boolean metricUnits = true;
if (preferences != null) {
@@ -440,10 +432,10 @@ public class SendToFusionTables implements Runnable {
}
/**
- * Returns a KML Point tag for the given location.
+ * Returns a KML LineString.
*
- * @param location The location.
- * @return the kml.
+ * @param track the track.
+ * @return the KML LineString.
*/
private String getKmlLineString(Track track) {
StringBuilder builder = new StringBuilder("");
@@ -500,7 +492,7 @@ public class SendToFusionTables implements Runnable {
* Prepares a buffer of locations for transmission to google fusion tables.
*
* @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
* original buffer
*/
@@ -665,33 +657,40 @@ public class SendToFusionTables implements Runnable {
* @return true in case of success
*/
private boolean runUpdate(final String query) {
- GDataWrapper wrapper = new GDataWrapper();
+ GDataWrapper wrapper = new GDataWrapper();
wrapper.setAuthManager(auth);
wrapper.setRetryOnAuthFailure(true);
- wrapper.setClient(transport);
+ wrapper.setClient(httpRequestFactory);
Log.d(Constants.TAG, "GData connection prepared: " + this.auth);
- wrapper.runQuery(new QueryFunction() {
+ wrapper.runQuery(new QueryFunction() {
@Override
- public void query(HttpTransport client)
+ public void query(HttpRequestFactory factory)
throws IOException, GDataWrapper.ParseException, GDataWrapper.HttpException,
GDataWrapper.AuthenticationException {
- HttpRequest request = transport.buildPostRequest();
- request.headers.contentType = "application/x-www-form-urlencoded";
GenericUrl url = new GenericUrl(FUSIONTABLES_BASE_FEED_URL);
- request.url = url;
- InputStreamContent isc = new InputStreamContent();
- String sql = "sql=" + URLEncoder.encode(query, "UTF-8");
- isc.inputStream = new ByteArrayInputStream(Strings.toBytesUtf8(sql));
- request.content = isc;
+ String sql = "sql=" + URLEncoder.encode(query, "UTF-8");
+ ByteArrayInputStream inputStream = new ByteArrayInputStream(Strings.toBytesUtf8(sql));
+ 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);
HttpResponse response;
try {
response = request.execute();
} 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) {
byte[] result = new byte[1024];
int read = response.getContent().read(result);
@@ -704,9 +703,11 @@ public class SendToFusionTables implements Runnable {
Log.w(Constants.TAG, "Unrecognized response: " + lines[0]);
}
} else {
- Log.d(Constants.TAG, "Query failed: " + response.statusMessage + " (" +
- response.statusCode + ")");
- throw new GDataWrapper.HttpException(response.statusCode, response.statusMessage);
+ Log.d(Constants.TAG,
+ "Query failed: " + response.getStatusMessage() + " ("
+ + response.getStatusCode() + ")");
+ throw new GDataWrapper.HttpException(
+ response.getStatusCode(), response.getStatusMessage());
}
}
});
diff --git a/MyTracks/src/com/google/android/apps/mytracks/maps/DynamicSpeedTrackPathDescriptor.java b/MyTracks/src/com/google/android/apps/mytracks/maps/DynamicSpeedTrackPathDescriptor.java
new file mode 100644
index 000000000..f6fc968d5
--- /dev/null
+++ b/MyTracks/src/com/google/android/apps/mytracks/maps/DynamicSpeedTrackPathDescriptor.java
@@ -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;
+ }
+}
\ No newline at end of file
diff --git a/MyTracks/src/com/google/android/apps/mytracks/maps/DynamicSpeedTrackPathPainter.java b/MyTracks/src/com/google/android/apps/mytracks/maps/DynamicSpeedTrackPathPainter.java
new file mode 100644
index 000000000..2234f8b8f
--- /dev/null
+++ b/MyTracks/src/com/google/android/apps/mytracks/maps/DynamicSpeedTrackPathPainter.java
@@ -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 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();
+ }
+
+ @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 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;
+ }
+}
\ No newline at end of file
diff --git a/MyTracks/src/com/google/android/apps/mytracks/maps/FixedSpeedTrackPathDescriptor.java b/MyTracks/src/com/google/android/apps/mytracks/maps/FixedSpeedTrackPathDescriptor.java
new file mode 100644
index 000000000..e69b4a6a5
--- /dev/null
+++ b/MyTracks/src/com/google/android/apps/mytracks/maps/FixedSpeedTrackPathDescriptor.java
@@ -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;
+ }
+}
\ No newline at end of file
diff --git a/MyTracks/src/com/google/android/apps/mytracks/maps/SingleColorTrackPathPainter.java b/MyTracks/src/com/google/android/apps/mytracks/maps/SingleColorTrackPathPainter.java
new file mode 100644
index 000000000..b12ae2370
--- /dev/null
+++ b/MyTracks/src/com/google/android/apps/mytracks/maps/SingleColorTrackPathPainter.java
@@ -0,0 +1,107 @@
+/*
+ * 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 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 = new Path();
+ 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;
+ }
+}
\ No newline at end of file
diff --git a/MyTracks/src/com/google/android/apps/mytracks/maps/TrackPathDescriptor.java b/MyTracks/src/com/google/android/apps/mytracks/maps/TrackPathDescriptor.java
new file mode 100644
index 000000000..389994e6b
--- /dev/null
+++ b/MyTracks/src/com/google/android/apps/mytracks/maps/TrackPathDescriptor.java
@@ -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();
+}
\ No newline at end of file
diff --git a/MyTracks/src/com/google/android/apps/mytracks/maps/TrackPathPainter.java b/MyTracks/src/com/google/android/apps/mytracks/maps/TrackPathPainter.java
new file mode 100644
index 000000000..1f1d8e31d
--- /dev/null
+++ b/MyTracks/src/com/google/android/apps/mytracks/maps/TrackPathPainter.java
@@ -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 points);
+
+ /**
+ * @return True if the path needs to be updated.
+ */
+ boolean needsRedraw();
+
+ /**
+ * @return The path being used currently.
+ */
+ Path getLastPath();
+}
+
+
+
diff --git a/MyTracks/src/com/google/android/apps/mytracks/maps/TrackPathPainterFactory.java b/MyTracks/src/com/google/android/apps/mytracks/maps/TrackPathPainterFactory.java
new file mode 100644
index 000000000..14f8f29cd
--- /dev/null
+++ b/MyTracks/src/com/google/android/apps/mytracks/maps/TrackPathPainterFactory.java
@@ -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);
+ }
+ }
+}
\ No newline at end of file
diff --git a/MyTracks/src/com/google/android/apps/mytracks/maps/TrackPathUtilities.java b/MyTracks/src/com/google/android/apps/mytracks/maps/TrackPathUtilities.java
new file mode 100644
index 000000000..956d2c8eb
--- /dev/null
+++ b/MyTracks/src/com/google/android/apps/mytracks/maps/TrackPathUtilities.java
@@ -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;
+ }
+}
\ No newline at end of file
diff --git a/MyTracks/src/com/google/android/apps/mytracks/util/ApiFeatures.java b/MyTracks/src/com/google/android/apps/mytracks/util/ApiFeatures.java
index 04e88baa4..821e05c80 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/util/ApiFeatures.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/util/ApiFeatures.java
@@ -16,6 +16,7 @@
package com.google.android.apps.mytracks.util;
import com.google.android.apps.mytracks.Constants;
+import com.google.api.client.http.HttpTransport;
import android.os.Build;
import android.util.Log;
@@ -123,6 +124,15 @@ public class ApiFeatures {
public boolean canReuseSQLiteQueryBuilder() {
return getApiLevel() > 4;
}
+
+ /**
+ * Returns true if com.google.api.client.javanet.NetHttpTransport should be
+ * used rather than com.google.api.client.apache.ApacheHttpTransport. See
+ * {@link HttpTransport} for more info.
+ */
+ public boolean useNetHttpTransport() {
+ return getApiLevel() >= 9;
+ }
// Visible for testing.
protected int getApiLevel() {
diff --git a/MyTracks/src/com/google/android/apps/mytracks/util/UnitConversions.java b/MyTracks/src/com/google/android/apps/mytracks/util/UnitConversions.java
index c524ca917..609a7a9cf 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/util/UnitConversions.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/util/UnitConversions.java
@@ -28,7 +28,8 @@ public abstract class UnitConversions {
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 TO_RADIANS = Math.PI / 180.0;
-
+ public static final double MPH_TO_KMH = 1.609344;
+
protected UnitConversions() {
}
}
diff --git a/MyTracksTest/src/com/google/android/apps/mytracks/MapOverlayTest.java b/MyTracksTest/src/com/google/android/apps/mytracks/MapOverlayTest.java
index 3ea8d4a11..49a91b49b 100644
--- a/MyTracksTest/src/com/google/android/apps/mytracks/MapOverlayTest.java
+++ b/MyTracksTest/src/com/google/android/apps/mytracks/MapOverlayTest.java
@@ -16,103 +16,23 @@
package com.google.android.apps.mytracks;
import com.google.android.apps.mytracks.content.Waypoint;
-import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapView;
-import com.google.android.maps.Projection;
-import android.content.Context;
import android.graphics.Canvas;
-import android.graphics.Path;
-import android.graphics.Point;
-import android.graphics.PointF;
-import android.graphics.Rect;
import android.location.Location;
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.
*
* @author Bartlomiej Niechwiej
+ * @author Vangelis S.
*/
public class MapOverlayTest extends AndroidTestCase {
private Canvas canvas;
private MockMyTracksOverlay myTracksOverlay;
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> segments = new LinkedList>();
- /** The total number of points in this path. */
- public int totalPoints;
-
- private List 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(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
protected void setUp() throws Exception {
super.setUp();
@@ -121,9 +41,8 @@ public class MapOverlayTest extends AndroidTestCase {
// Enable drawing.
myTracksOverlay.setTrackDrawingEnabled(true);
mockView = null;
- mockProjection = new MockProjection();
}
-
+
public void testAddLocation() throws Exception {
Location location = new Location("gps");
location.setLatitude(10);
diff --git a/MyTracksTest/src/com/google/android/apps/mytracks/MockMyTracksOverlay.java b/MyTracksTest/src/com/google/android/apps/mytracks/MockMyTracksOverlay.java
new file mode 100644
index 000000000..9c2355758
--- /dev/null
+++ b/MyTracksTest/src/com/google/android/apps/mytracks/MockMyTracksOverlay.java
@@ -0,0 +1,57 @@
+/*
+ * 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.Path;
+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);
+ }
+
+ @Override
+ public Path newPath() {
+ return new MockPath();
+ }
+}
\ No newline at end of file
diff --git a/MyTracksTest/src/com/google/android/apps/mytracks/MockPath.java b/MyTracksTest/src/com/google/android/apps/mytracks/MockPath.java
new file mode 100644
index 000000000..ba9592c08
--- /dev/null
+++ b/MyTracksTest/src/com/google/android/apps/mytracks/MockPath.java
@@ -0,0 +1,60 @@
+/*
+ * 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.Path;
+import android.graphics.PointF;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+
+import junit.framework.Assert;
+
+/**
+ * Elements for Tests for the MyTracks map overlay.
+ *
+ * @author Bartlomiej Niechwiej
+ * @author Vangelis S.
+ *
+ * A mock class that intercepts {@code Path}'s and records calls to
+ * {@code #moveTo()} and {@code #lineTo()}.
+ */
+public class MockPath extends Path {
+
+ /** A list of disjoined path segments. */
+ public final List> segments = new LinkedList>();
+ /** The total number of points in this path. */
+ public int totalPoints;
+ private List currentSegment;
+
+ @Override
+ public void lineTo(float x, float y) {
+ super.lineTo(x, y);
+ Assert.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(Arrays.asList(new PointF(x, y))));
+ totalPoints++;
+ }
+}
\ No newline at end of file
diff --git a/MyTracksTest/src/com/google/android/apps/mytracks/MockProjection.java b/MyTracksTest/src/com/google/android/apps/mytracks/MockProjection.java
new file mode 100644
index 000000000..a1f36d90b
--- /dev/null
+++ b/MyTracksTest/src/com/google/android/apps/mytracks/MockProjection.java
@@ -0,0 +1,47 @@
+/*
+ * 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.GeoPoint;
+import com.google.android.maps.Projection;
+
+import android.graphics.Point;
+
+/**
+ * Elements for Tests for the MyTracks map overlay.
+ *
+ * @author Bartlomiej Niechwiej
+ * @author Vangelis S.
+ *
+ * A mock {@code Projection} that acts as the identity matrix.
+ */
+public 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);
+ }
+}
\ No newline at end of file
diff --git a/MyTracksTest/src/com/google/android/apps/mytracks/maps/TrackPathDescriptorDynamicSpeedTest.java b/MyTracksTest/src/com/google/android/apps/mytracks/maps/TrackPathDescriptorDynamicSpeedTest.java
new file mode 100644
index 000000000..63eec1182
--- /dev/null
+++ b/MyTracksTest/src/com/google/android/apps/mytracks/maps/TrackPathDescriptorDynamicSpeedTest.java
@@ -0,0 +1,53 @@
+/*
+ * 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.MockPath;
+
+import android.location.Location;
+
+/**
+ * Tests for the MyTracks track path descriptors and painters.
+ *
+ * @author Vangelis S.
+ */
+public class TrackPathDescriptorDynamicSpeedTest extends TrackPathPainterTestCase {
+
+ public void testDynamicSpeedTrackPathDescriptor() throws Exception {
+ Location location = new Location("gps");
+ location.setLatitude(10);
+
+ for (int i = 0; i < 100; ++i) {
+ location = new Location("gps");
+ location.setLatitude(20 + i / 2);
+ location.setLongitude(150 - i);
+ myTracksOverlay.addLocation(location);
+ }
+
+ TrackPathPainter painter = new DynamicSpeedTrackPathPainter(getContext(), new DynamicSpeedTrackPathDescriptor(getContext()));
+ int startLocationIdx = 0;
+ Boolean alwaysVisible = true;
+
+ assertNotNull(painter);
+ painter.updatePath(myTracksOverlay.getMapProjection(mockView),
+ myTracksOverlay.getMapViewRect(mockView), startLocationIdx, alwaysVisible,
+ myTracksOverlay.getPoints());
+ assertNotNull(myTracksOverlay.getLastPath());
+ assertTrue(myTracksOverlay.getLastPath() instanceof MockPath);
+ painter.drawTrack(canvas);
+
+ }
+}
diff --git a/MyTracksTest/src/com/google/android/apps/mytracks/maps/TrackPathDescriptorFixedSpeedTest.java b/MyTracksTest/src/com/google/android/apps/mytracks/maps/TrackPathDescriptorFixedSpeedTest.java
new file mode 100644
index 000000000..d78c02fcb
--- /dev/null
+++ b/MyTracksTest/src/com/google/android/apps/mytracks/maps/TrackPathDescriptorFixedSpeedTest.java
@@ -0,0 +1,52 @@
+/*
+ * 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.MockPath;
+
+import android.location.Location;
+
+/**
+ * Tests for the MyTracks track path descriptors and painters.
+ *
+ * @author Vangelis S.
+ */
+public class TrackPathDescriptorFixedSpeedTest extends TrackPathPainterTestCase {
+
+ public void testFixedSpeedTrackPathDescriptor() throws Exception {
+ Location location = new Location("gps");
+ location.setLatitude(10);
+
+ for (int i = 0; i < 100; ++i) {
+ location = new Location("gps");
+ location.setLatitude(20 + i / 2);
+ location.setLongitude(150 - i);
+ myTracksOverlay.addLocation(location);
+ }
+
+ TrackPathPainter painter = new DynamicSpeedTrackPathPainter(getContext(), new FixedSpeedTrackPathDescriptor(getContext()));
+ int startLocationIdx = 0;
+ Boolean alwaysVisible = true;
+
+ assertNotNull(painter);
+ painter.updatePath(myTracksOverlay.getMapProjection(mockView),
+ myTracksOverlay.getMapViewRect(mockView), startLocationIdx, alwaysVisible,
+ myTracksOverlay.getPoints());
+ assertNotNull(myTracksOverlay.getLastPath());
+ assertTrue(myTracksOverlay.getLastPath() instanceof MockPath);
+ painter.drawTrack(canvas);
+ }
+}
diff --git a/MyTracksTest/src/com/google/android/apps/mytracks/maps/TrackPathPainterFactoryTest.java b/MyTracksTest/src/com/google/android/apps/mytracks/maps/TrackPathPainterFactoryTest.java
new file mode 100644
index 000000000..83482b26b
--- /dev/null
+++ b/MyTracksTest/src/com/google/android/apps/mytracks/maps/TrackPathPainterFactoryTest.java
@@ -0,0 +1,78 @@
+/*
+ * 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.Constants;
+import com.google.android.apps.mytracks.MockPath;
+import com.google.android.maps.mytracks.R;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.location.Location;
+
+/**
+ * Tests for the MyTracks track path painter factory.
+ *
+ * @author Vangelis S.
+ */
+public class TrackPathPainterFactoryTest extends TrackPathPainterTestCase {
+
+ public void testTrackPathPainterFactory() throws Exception {
+ Location location = new Location("gps");
+ location.setLatitude(10);
+
+ for (int i = 0; i < 100; ++i) {
+ location = new Location("gps");
+ location.setLatitude(20 + i / 2);
+ location.setLongitude(150 - i);
+ myTracksOverlay.addLocation(location);
+ }
+
+ Context context = getContext();
+ SharedPreferences prefs = context.getSharedPreferences(Constants.SETTINGS_NAME, 0);
+ if (prefs == null) {
+ return;
+ }
+
+ testTrackPathPainterFactorySpecific(context, prefs, R.string.track_color_mode_none,
+ SingleColorTrackPathPainter.class);
+ testTrackPathPainterFactorySpecific(context, prefs, R.string.track_color_mode_fixed,
+ DynamicSpeedTrackPathPainter.class);
+ testTrackPathPainterFactorySpecific(context, prefs, R.string.track_color_mode_dynamic,
+ DynamicSpeedTrackPathPainter.class);
+ }
+
+ private void testTrackPathPainterFactorySpecific(Context context, SharedPreferences prefs,
+ int track_color_mode, Class > c) {
+ prefs.edit().putString(context.getString(track_color_mode),
+ context.getString(R.string.track_color_mode_key)).commit();
+
+ int startLocationIdx = 0;
+ Boolean alwaysVisible = true;
+
+ TrackPathPainter painter = TrackPathPainterFactory.getTrackPathPainter(context);
+
+ assertNotNull(painter);
+ assertTrue(c.isInstance(painter));
+
+ painter.updatePath(myTracksOverlay.getMapProjection(mockView),
+ myTracksOverlay.getMapViewRect(mockView), startLocationIdx, alwaysVisible,
+ myTracksOverlay.getPoints());
+ assertNotNull(myTracksOverlay.getLastPath());
+ assertTrue(myTracksOverlay.getLastPath() instanceof MockPath);
+ painter.drawTrack(canvas);
+ }
+}
diff --git a/MyTracksTest/src/com/google/android/apps/mytracks/maps/TrackPathPainterSingleColorTest.java b/MyTracksTest/src/com/google/android/apps/mytracks/maps/TrackPathPainterSingleColorTest.java
new file mode 100644
index 000000000..6c6682e32
--- /dev/null
+++ b/MyTracksTest/src/com/google/android/apps/mytracks/maps/TrackPathPainterSingleColorTest.java
@@ -0,0 +1,52 @@
+/*
+ * 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.MockPath;
+
+import android.location.Location;
+
+/**
+ * Tests for the MyTracks track path descriptors and painters.
+ *
+ * @author Vangelis S.
+ */
+public class TrackPathPainterSingleColorTest extends TrackPathPainterTestCase {
+
+ public void testSimpeColorTrackPathPainter() throws Exception {
+ Location location = new Location("gps");
+ location.setLatitude(10);
+
+ for (int i = 0; i < 100; ++i) {
+ location = new Location("gps");
+ location.setLatitude(20 + i / 2);
+ location.setLongitude(150 - i);
+ myTracksOverlay.addLocation(location);
+ }
+
+ TrackPathPainter painter = new SingleColorTrackPathPainter(getContext());
+ int startLocationIdx = 0;
+ Boolean alwaysVisible = true;
+
+ assertNotNull(painter);
+ painter.updatePath(myTracksOverlay.getMapProjection(mockView),
+ myTracksOverlay.getMapViewRect(mockView), startLocationIdx, alwaysVisible,
+ myTracksOverlay.getPoints());
+ assertNotNull(myTracksOverlay.getLastPath());
+ assertTrue(myTracksOverlay.getLastPath() instanceof MockPath);
+ painter.drawTrack(canvas);
+ }
+}
diff --git a/MyTracksTest/src/com/google/android/apps/mytracks/maps/TrackPathPainterTestCase.java b/MyTracksTest/src/com/google/android/apps/mytracks/maps/TrackPathPainterTestCase.java
new file mode 100644
index 000000000..59ceb94fd
--- /dev/null
+++ b/MyTracksTest/src/com/google/android/apps/mytracks/maps/TrackPathPainterTestCase.java
@@ -0,0 +1,43 @@
+/*
+ * 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.MockMyTracksOverlay;
+import com.google.android.maps.MapView;
+
+import android.graphics.Canvas;
+import android.test.AndroidTestCase;
+
+/**
+ * Tests for the MyTracks track path descriptors and painters.
+ *
+ * @author Vangelis S.
+ */
+public class TrackPathPainterTestCase extends AndroidTestCase {
+ protected Canvas canvas;
+ protected MockMyTracksOverlay myTracksOverlay;
+ protected MapView mockView;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ canvas = new Canvas();
+ myTracksOverlay = new MockMyTracksOverlay(getContext());
+ // Enable drawing.
+ myTracksOverlay.setTrackDrawingEnabled(true);
+ mockView = null;
+ }
+}