diff --git a/MyTracks/res/values/keys.xml b/MyTracks/res/values/keys.xml
index 30a83a613..8cc20c02b 100644
--- a/MyTracks/res/values/keys.xml
+++ b/MyTracks/res/values/keys.xml
@@ -37,6 +37,7 @@ limitations under the License.
shareUrlOnly
signalSamplingFrequency
splitFrequency
+ debugDrawBounds
recordingTrack
diff --git a/MyTracks/res/xml/preferences.xml b/MyTracks/res/xml/preferences.xml
index ddc6b2ff9..f9cc821a7 100644
--- a/MyTracks/res/xml/preferences.xml
+++ b/MyTracks/res/xml/preferences.xml
@@ -125,4 +125,13 @@ limitations under the License.
android:persistent="false" />
+
+
+
diff --git a/MyTracks/src/com/google/android/apps/mytracks/MyTracksMap.java b/MyTracks/src/com/google/android/apps/mytracks/MyTracksMap.java
index 7966975b4..fcf9c9308 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/MyTracksMap.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/MyTracksMap.java
@@ -372,6 +372,8 @@ public class MyTracksMap extends MapActivity
setSelectedTrack(selectedTrackId);
}
updateOptionsButton();
+ mapOverlay.setDrawBounds(preferences.getBoolean(
+ getString(R.string.debug_draw_bounds_key), false));
preferences.registerOnSharedPreferenceChangeListener(this);
}
}
@@ -916,6 +918,10 @@ public class MyTracksMap extends MapActivity
mapOverlay.setShowEndMarker(!isRecordingSelected());
mapView.postInvalidate();
}
+ } else if (key.equals(getString(R.string.debug_draw_bounds_key))) {
+ mapOverlay.setDrawBounds(
+ sharedPreferences.getBoolean(
+ getString(R.string.debug_draw_bounds_key), false));
}
}
});
diff --git a/MyTracks/src/com/google/android/apps/mytracks/MyTracksOverlay.java b/MyTracks/src/com/google/android/apps/mytracks/MyTracksOverlay.java
index dfc235827..47faf8fad 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/MyTracksOverlay.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/MyTracksOverlay.java
@@ -29,6 +29,7 @@ import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
import android.graphics.Rect;
+import android.graphics.Region;
import android.graphics.drawable.Drawable;
import android.location.Location;
@@ -59,6 +60,7 @@ public class MyTracksOverlay extends Overlay {
private int lastHeading = 0;
private Location myLocation;
private boolean showEndMarker = true;
+ private boolean drawBounds;
public MyTracksOverlay(Context context) {
this.context = context;
@@ -127,7 +129,11 @@ public class MyTracksOverlay extends Overlay {
* @param l the location to add
*/
public void addLocation(Location l) {
- points.add(l);
+ if (l != null) {
+ synchronized (points) {
+ points.add(l);
+ }
+ }
}
public void addWaypoint(Waypoint wpt) {
@@ -135,7 +141,9 @@ public class MyTracksOverlay extends Overlay {
}
public int getNumLocations() {
- return points.size();
+ synchronized (points) {
+ return points.size();
+ }
}
public void clearWaypoints() {
@@ -143,7 +151,9 @@ public class MyTracksOverlay extends Overlay {
}
public void clearPoints() {
- points.clear();
+ synchronized (points) {
+ points.clear();
+ }
}
public void setTrackDrawingEnabled(boolean trackDrawingEnabled) {
@@ -220,73 +230,118 @@ public class MyTracksOverlay extends Overlay {
}
private void drawTrack(Canvas canvas, MapView mapView) {
- if (points.size() < 2) {
- return;
- }
+ Path path;
+ Point pt = new Point();
+ Location lastValidLocation;
+ int locLon = 0, locLat = 0;
+ GeoPoint firstGeoPoint = null;
+ boolean lastLocValid;
// Get the current viewing window:
int w = mapView.getLongitudeSpan();
int h = mapView.getLatitudeSpan();
int cx = mapView.getMapCenter().getLongitudeE6();
int cy = mapView.getMapCenter().getLatitudeE6();
- Rect rect = new Rect(cx - w, cy - h, cx + w, cy + h);
+ Rect viewRect = new Rect(cx - w, cy - h, cx + w, cy + h);
- Point pt = new Point();
- GeoPoint geoPoint;
- Location loc;
- Location lastValidLocation = null;
- Path path;
- boolean wasInside;
-
- // Do as much allocation and preparation outside the loop over track
- // points:
- wasInside = false;
- int locLon = 0, locLat = 0, minLon, maxLon, minLat, maxLat;
- int lastLocLon = (int) (points.get(0).getLongitude() * 1E6);
- int lastLocLat = (int) (points.get(0).getLatitude() * 1E6);
-
- // Loop over track points:
- path = new Path();
- for (int i = 1; i < points.size(); i++) {
-
- loc = points.get(i);
- if (loc == null) {
- continue;
+ // Global bounding box, including points not visible
+ int allMinLat, allMinLon, allMaxLat, allMaxLon;
+
+ synchronized (points) {
+ int numPoints = points.size();
+ if (numPoints < 2) {
+ return;
}
- locLon = (int) (loc.getLongitude() * 1E6);
- locLat = (int) (loc.getLatitude() * 1E6);
- // Draw a line segment if it's inside the viewing window:
- if (locLat < 90E6 && lastLocLat < 90E6) {
- lastValidLocation = loc;
- minLon = Math.min(locLon, lastLocLon);
- maxLon = Math.max(locLon, lastLocLon);
- minLat = Math.min(locLat, lastLocLat);
- maxLat = Math.max(locLat, lastLocLat);
- if (rect.intersects(minLon, minLat, maxLon, maxLat)) {
- if (!wasInside) {
- geoPoint = new GeoPoint(lastLocLat, lastLocLon);
- mapView.getProjection().toPixels(geoPoint, pt);
- path.moveTo(pt.x, pt.y);
+ GeoPoint geoPoint;
+ Location loc;
+ int minLon, maxLon, minLat, maxLat;
+ lastValidLocation = points.get(0);
+ int lastLocLon = allMinLon = allMaxLon = (int) (lastValidLocation.getLongitude() * 1E6);
+ int lastLocLat = allMinLat = allMaxLat = (int) (lastValidLocation.getLatitude() * 1E6);
+ lastLocValid = MyTracksUtils.isValidLocation(lastValidLocation);
+ boolean lastLocVisible = false;
+ path = new Path();
+
+ // Loop over track points:
+ path.incReserve(numPoints);
+ for (int i = 1; i < numPoints; i++) {
+ loc = points.get(i);
+
+ boolean locValid = MyTracksUtils.isValidLocation(loc);
+ boolean locVisible = false;
+ if (locValid) {
+ locLon = (int) (loc.getLongitude() * 1E6);
+ locLat = (int) (loc.getLatitude() * 1E6);
+
+ if (firstGeoPoint == null) {
+ // Found the starting point
+ firstGeoPoint = new GeoPoint(locLat, locLon);
+ }
+
+ // If both the current and previous locations were valid
+ if (lastLocValid) {
+ lastValidLocation = loc;
+
+ // Get the bounding box of the segment about to be drawn
+ if (locLon > lastLocLon) {
+ minLon = lastLocLon;
+ maxLon = locLon;
+ } else {
+ minLon = locLon;
+ maxLon = lastLocLon;
+ }
+ if (locLat > lastLocLat) {
+ minLat = lastLocLat;
+ maxLat = locLat;
+ } else {
+ minLat = locLat;
+ maxLat = lastLocLat;
+ }
+
+ if (drawBounds) {
+ allMaxLat = Math.max(allMaxLat, maxLat);
+ allMinLat = Math.min(allMinLat, minLat);
+ allMaxLon = Math.max(allMaxLon, maxLon);
+ allMinLon = Math.min(allMinLon, minLon);
+ }
+
+ // See if that bounding box intersects the viewable bounding box
+ // Assume that if it does, the location is visible
+ locVisible = viewRect.intersects(minLon, minLat, maxLon, maxLat);
+ if (locVisible) {
+ // If the previous point wasn't drawn, start at its position
+ if (!lastLocVisible) {
+ geoPoint = new GeoPoint(lastLocLat, lastLocLon);
+ mapView.getProjection().toPixels(geoPoint, pt);
+ path.moveTo(pt.x, pt.y);
+ }
+
+ // Draw a line to the new point
+ geoPoint = new GeoPoint(locLat, locLon);
+ mapView.getProjection().toPixels(geoPoint, pt);
+ path.lineTo(pt.x, pt.y);
+ }
}
- geoPoint = new GeoPoint(locLat, locLon);
- mapView.getProjection().toPixels(geoPoint, pt);
- path.lineTo(pt.x, pt.y);
- wasInside = rect.contains(locLon, locLat);
}
- } else {
- wasInside = false;
+ lastLocLon = locLon;
+ lastLocLat = locLat;
+ lastLocValid = locValid;
+ lastLocVisible = locVisible;
}
- lastLocLon = locLon;
- lastLocLat = locLat;
}
+
canvas.drawPath(path, selectedTrackPaint);
+ if (drawBounds) {
+ drawBoundingBox(canvas, mapView,
+ allMinLat, allMinLon, allMaxLat, allMaxLon);
+ }
+
// Draw the "End" marker:
- Location currentLastValidLocation = lastValidLocation;
- if (showEndMarker && currentLastValidLocation != null) {
+ if (showEndMarker && lastValidLocation != null) {
canvas.save();
- geoPoint = MyTracksUtils.getGeoPoint(currentLastValidLocation);
+ GeoPoint geoPoint = MyTracksUtils.getGeoPoint(lastValidLocation);
mapView.getProjection().toPixels(geoPoint, pt);
canvas.translate(pt.x - (markerWidth / 2), pt.y - markerHeight);
endMarker.draw(canvas);
@@ -294,22 +349,46 @@ public class MyTracksOverlay extends Overlay {
}
// Draw the "Start" marker:
- for (int i = 0; i < points.size(); i++) {
- loc = points.get(i);
- if (loc.getLatitude() < 90) {
- locLon = (int) (loc.getLongitude() * 1E6);
- locLat = (int) (loc.getLatitude() * 1E6);
- geoPoint = new GeoPoint(locLat, locLon);
- mapView.getProjection().toPixels(geoPoint, pt);
- canvas.save();
- canvas.translate(pt.x - (markerWidth / 2), pt.y - markerHeight);
- startMarker.draw(canvas);
- canvas.restore();
- break;
- }
+ if (firstGeoPoint != null) {
+ mapView.getProjection().toPixels(firstGeoPoint, pt);
+ canvas.save();
+ canvas.translate(pt.x - (markerWidth / 2), pt.y - markerHeight);
+ startMarker.draw(canvas);
+ canvas.restore();
}
}
+ private void drawBoundingBox(Canvas canvas, MapView mapView, int allMinLat,
+ int allMinLon, int allMaxLat, int allMaxLon) {
+ // Transform coordinates
+ GeoPoint maxPoint = new GeoPoint(allMaxLat, allMaxLon);
+ GeoPoint minPoint = new GeoPoint(allMinLat, allMinLon);
+ Point minPt = new Point();
+ Point maxPt = new Point();
+ mapView.getProjection().toPixels(minPoint, minPt);
+ mapView.getProjection().toPixels(maxPoint, maxPt);
+ Rect allBounds = new Rect(minPt.x, minPt.y, maxPt.x, maxPt.y);
+
+ // Prepare a green paint
+ Paint boundingBoxPaint = new Paint();
+ boundingBoxPaint.setColor(context.getResources().getColor(R.color.green));
+ boundingBoxPaint.setStrokeWidth(2);
+ boundingBoxPaint.setStyle(Paint.Style.STROKE);
+ boundingBoxPaint.setAntiAlias(true);
+
+ // Disable clipping
+ canvas.save();
+ canvas.clipRect(Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY,
+ Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY,
+ Region.Op.REPLACE);
+
+ // Draw the bounding box
+ canvas.drawRect(allBounds, boundingBoxPaint);
+
+ // Re-enable clipping
+ canvas.restore();
+ }
+
@Override
public boolean draw(Canvas canvas, MapView mapView, boolean shadow,
long when) {
@@ -378,4 +457,8 @@ public class MyTracksOverlay extends Overlay {
}
return super.onTap(p, mapView);
}
+
+ public void setDrawBounds(boolean drawBounds) {
+ this.drawBounds = drawBounds;
+ }
}
diff --git a/MyTracks/src/com/google/android/apps/mytracks/StatsActivity.java b/MyTracks/src/com/google/android/apps/mytracks/StatsActivity.java
index 1432888f5..9eed646a2 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/StatsActivity.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/StatsActivity.java
@@ -49,14 +49,12 @@ import android.widget.Toast;
* @author Sandor Dornbush
*/
public class StatsActivity extends Activity
- implements OnSharedPreferenceChangeListener, LocationListener {
-
+ implements OnSharedPreferenceChangeListener {
private final StatsUtilities utils;
private UIUpdateThread thread;
private ContentObserver observer;
- private LocationManager locationManager;
/**
* The id of the currently selected track.
@@ -96,7 +94,6 @@ public class StatsActivity extends Activity
private boolean showCurrentSegment = false;
private final MyTracksProviderUtils providerUtils;
- private Track track = null;
/**
* A runnable for posting to the UI thread. Will update the total time field.
@@ -179,11 +176,9 @@ public class StatsActivity extends Activity
preferences.getBoolean(getString(R.string.report_speed_key), true);
checkLiveTrack();
restoreStats();
- updateLocation(null);
+ showUnknownLocation();
preferences.registerOnSharedPreferenceChangeListener(this);
}
- locationManager =
- (LocationManager) getSystemService(Context.LOCATION_SERVICE);
utils.setMetricUnits(metricUnits);
utils.setReportSpeed(displaySpeed);
utils.updateUnits();
@@ -214,7 +209,7 @@ public class StatsActivity extends Activity
activityOnTop = true;
checkLiveTrack();
restoreStats();
- updateLocation(null);
+ showUnknownLocation();
super.onResume();
}
@@ -234,7 +229,7 @@ public class StatsActivity extends Activity
-1);
checkLiveTrack();
restoreStats();
- updateLocation(null);
+ showUnknownLocation();
} else if (key.equals(getString(R.string.recording_track_key))) {
recordingTrackId =
sharedPreferences.getLong(
@@ -242,7 +237,7 @@ public class StatsActivity extends Activity
-1);
checkLiveTrack();
restoreStats();
- updateLocation(null);
+ showUnknownLocation();
} else if (key.equals(getString(R.string.metric_units_key))) {
metricUnits =
sharedPreferences.getBoolean(
@@ -299,29 +294,36 @@ public class StatsActivity extends Activity
return super.onOptionsItemSelected(item);
}
- @Override
- public void onLocationChanged(Location l) {
- if (selectedTrackIsRecording()) {
- updateLocation(l);
+ private final LocationListener locationListener = new LocationListener() {
+ @Override
+ public void onLocationChanged(Location l) {
+ if (selectedTrackIsRecording()) {
+ showLocation(l);
+ }
}
- }
-
- @Override
- public void onProviderDisabled(String provider) {
- }
-
- @Override
- public void onProviderEnabled(String provider) {
- }
-
- @Override
- public void onStatusChanged(String provider, int status, Bundle extras) {
- }
+
+ @Override
+ public void onProviderDisabled(String provider) {
+ // Do nothing
+ }
+
+ @Override
+ public void onProviderEnabled(String provider) {
+ // Do nothing
+ }
+
+ @Override
+ public void onStatusChanged(String provider, int status, Bundle extras) {
+ // Do nothing
+ }
+ };
/**
* Registers to receive location updates from the GPS location provider.
*/
private void registerLocationListener() {
+ LocationManager locationManager =
+ (LocationManager) getSystemService(Context.LOCATION_SERVICE);
if (locationManager != null) {
LocationProvider gpsProvider =
locationManager.getProvider(MyTracksConstants.GPS_PROVIDER);
@@ -334,7 +336,7 @@ public class StatsActivity extends Activity
+ gpsProvider.getName());
}
locationManager.requestLocationUpdates(gpsProvider.getName(),
- 0/*minTime*/, 0/*minDist*/, this);
+ 0/*minTime*/, 0/*minDist*/, locationListener);
}
}
@@ -342,8 +344,10 @@ public class StatsActivity extends Activity
* Unregisters all location listener.
*/
private void unregisterLocationListener() {
+ LocationManager locationManager =
+ (LocationManager) getSystemService(Context.LOCATION_SERVICE);
if (locationManager != null) {
- locationManager.removeUpdates(this);
+ locationManager.removeUpdates(locationListener);
}
}
@@ -364,7 +368,7 @@ public class StatsActivity extends Activity
return;
}
- track = providerUtils.getTrack(selectedTrackId);
+ Track track = providerUtils.getTrack(selectedTrackId);
if (track == null || track.getStatistics() == null) {
utils.setAllToUnknown();
return;
@@ -421,17 +425,17 @@ public class StatsActivity extends Activity
*
* @param l may be null (will set location fields to unknown)
*/
- private void updateLocation(Location l) {
- if (l == null) {
- utils.setUnknown(R.id.elevation_register);
- utils.setUnknown(R.id.latitude_register);
- utils.setUnknown(R.id.longitude_register);
- utils.setUnknown(R.id.speed_register);
- } else {
- utils.setAltitude(R.id.elevation_register, l.getAltitude());
- utils.setLatLong(R.id.latitude_register, l.getLatitude());
- utils.setLatLong(R.id.longitude_register, l.getLongitude());
- utils.setSpeed(R.id.speed_register, l.getSpeed() * 3.6);
- }
+ private void showLocation(Location l) {
+ utils.setAltitude(R.id.elevation_register, l.getAltitude());
+ utils.setLatLong(R.id.latitude_register, l.getLatitude());
+ utils.setLatLong(R.id.longitude_register, l.getLongitude());
+ utils.setSpeed(R.id.speed_register, l.getSpeed() * 3.6);
+ }
+
+ private void showUnknownLocation() {
+ utils.setUnknown(R.id.elevation_register);
+ utils.setUnknown(R.id.latitude_register);
+ utils.setUnknown(R.id.longitude_register);
+ utils.setUnknown(R.id.speed_register);
}
}