Update all TrackPathPainter and TrackPathDescriptor.

Fix issues of incrementally updating a path.
This commit is contained in:
Jimmy Shih
2012-07-26 15:29:16 -07:00
parent 2b85a0ebba
commit 1bcbf7b5de
18 changed files with 334 additions and 372 deletions
@@ -21,7 +21,7 @@ import static com.google.android.apps.mytracks.Constants.TAG;
import com.google.android.apps.mytracks.content.Waypoint; import com.google.android.apps.mytracks.content.Waypoint;
import com.google.android.apps.mytracks.maps.TrackPathPainter; import com.google.android.apps.mytracks.maps.TrackPathPainter;
import com.google.android.apps.mytracks.maps.TrackPathPainterFactory; import com.google.android.apps.mytracks.maps.TrackPathPainterFactory;
import com.google.android.apps.mytracks.maps.TrackPathUtilities; import com.google.android.apps.mytracks.maps.TrackPathUtils;
import com.google.android.apps.mytracks.util.IntentUtils; import com.google.android.apps.mytracks.util.IntentUtils;
import com.google.android.apps.mytracks.util.LocationUtils; import com.google.android.apps.mytracks.util.LocationUtils;
import com.google.android.apps.mytracks.util.PreferencesUtils; import com.google.android.apps.mytracks.util.PreferencesUtils;
@@ -175,7 +175,7 @@ public class MapOverlay extends Overlay implements OnSharedPreferenceChangeListe
endMarker = resources.getDrawable(R.drawable.red_dot); endMarker = resources.getDrawable(R.drawable.red_dot);
endMarker.setBounds(0, 0, markerWidth, markerHeight); endMarker.setBounds(0, 0, markerWidth, markerHeight);
errorCirclePaint = TrackPathUtilities.getPaint(R.color.blue, context); errorCirclePaint = TrackPathUtils.getPaint(context, R.color.blue);
errorCirclePaint.setAlpha(127); errorCirclePaint.setAlpha(127);
trackPathPainter = TrackPathPainterFactory.getTrackPathPainter(context); trackPathPainter = TrackPathPainterFactory.getTrackPathPainter(context);
@@ -216,7 +216,7 @@ public class MapOverlay extends Overlay implements OnSharedPreferenceChangeListe
synchronized (points) { synchronized (points) {
points.clear(); points.clear();
pendingPoints.clear(); pendingPoints.clear();
trackPathPainter.clear(); trackPathPainter.clearPath();
lastReferencePoint = null; lastReferencePoint = null;
lastViewRect = null; lastViewRect = null;
} }
@@ -456,35 +456,37 @@ public class MapOverlay extends Overlay implements OnSharedPreferenceChangeListe
synchronized (points) { synchronized (points) {
// Merge the pending points with the list of cached locations. // Merge the pending points with the list of cached locations.
final GeoPoint referencePoint = projection.fromPixels(0, 0); GeoPoint referencePoint = projection.fromPixels(0, 0);
int newPoints = pendingPoints.drainTo(points); int newPoints = pendingPoints.drainTo(points);
boolean newProjection = !viewRect.equals(lastViewRect) boolean newProjection = !viewRect.equals(lastViewRect)
|| !referencePoint.equals(lastReferencePoint); || !referencePoint.equals(lastReferencePoint);
if (newPoints == 0 && !newProjection && trackPathPainter.getLastPath() != null) { // Call updateState first to trigger its side effects.
// No need to update the path boolean currentPathValid = !trackPathPainter.updateState() && !newProjection
&& trackPathPainter.hasPath();
if (newPoints == 0 && currentPathValid) {
// No need to update
draw = true; draw = true;
} else { } else {
int numPoints = points.size(); int numPoints = points.size();
if (numPoints < 2) { if (numPoints < 2) {
// Not enough points to draw a path // Not enough points to draw a path
draw = false; draw = false;
} else if (!newProjection && trackPathPainter.getLastPath() != null } else if (currentPathValid) {
&& !trackPathPainter.needsRedraw() && false) { // Incremental update of the path
// TODO fix incremental path update
// Incremental update of the path, without repositioning the view
draw = true; draw = true;
trackPathPainter.updatePath(projection, viewRect, numPoints - newPoints, true, points); trackPathPainter.updatePath(projection, viewRect, numPoints - newPoints, points);
} else { } else {
// The view has changed so we have to start from scratch. // Reload the path
draw = true; draw = true;
trackPathPainter.updatePath(projection, viewRect, 0, true, points); trackPathPainter.clearPath();
trackPathPainter.updatePath(projection, viewRect, 0, points);
} }
} }
lastReferencePoint = referencePoint; lastReferencePoint = referencePoint;
lastViewRect = viewRect; lastViewRect = viewRect;
} }
if (draw) { if (draw) {
trackPathPainter.drawTrack(canvas); trackPathPainter.drawPath(canvas);
} }
} }
@@ -13,6 +13,7 @@
* License for the specific language governing permissions and limitations under * License for the specific language governing permissions and limitations under
* the License. * the License.
*/ */
package com.google.android.apps.mytracks.maps; package com.google.android.apps.mytracks.maps;
import static com.google.android.apps.mytracks.Constants.TAG; import static com.google.android.apps.mytracks.Constants.TAG;
@@ -36,60 +37,43 @@ import android.util.Log;
* *
* @author Vangelis S. * @author Vangelis S.
*/ */
public class DynamicSpeedTrackPathDescriptor implements TrackPathDescriptor, public class DynamicSpeedTrackPathDescriptor
OnSharedPreferenceChangeListener { implements TrackPathDescriptor, OnSharedPreferenceChangeListener {
private final Context context;
private int speedMargin;
private int slowSpeed; private int slowSpeed;
private int normalSpeed; private int normalSpeed;
private int speedMargin;
private double averageMovingSpeed; private double averageMovingSpeed;
private final Context context;
@VisibleForTesting @VisibleForTesting
static final int CRITICAL_DIFFERENCE_PERCENTAGE = 20; static final int CRITICAL_DIFFERENCE_PERCENTAGE = 20;
public DynamicSpeedTrackPathDescriptor(Context context) { public DynamicSpeedTrackPathDescriptor(Context context) {
this.context = context; this.context = context;
context.getSharedPreferences(Constants.SETTINGS_NAME, Context.MODE_PRIVATE)
.registerOnSharedPreferenceChangeListener(this);
speedMargin = PreferencesUtils.getInt(context, R.string.track_color_mode_percentage_key, speedMargin = PreferencesUtils.getInt(context, R.string.track_color_mode_percentage_key,
PreferencesUtils.TRACK_COLOR_MODE_PERCENTAGE_DEFAULT); PreferencesUtils.TRACK_COLOR_MODE_PERCENTAGE_DEFAULT);
context.getSharedPreferences(Constants.SETTINGS_NAME, Context.MODE_PRIVATE)
.registerOnSharedPreferenceChangeListener(this);
} }
/** @Override
* Get the slow speed calculated based on the % below the average speed.
*
* @return The speed limit considered as slow.
*/
public int getSlowSpeed() { public int getSlowSpeed() {
slowSpeed = (int) (averageMovingSpeed - (averageMovingSpeed * speedMargin / 100)); slowSpeed = (int) (averageMovingSpeed - (averageMovingSpeed * speedMargin / 100.0));
return slowSpeed; return slowSpeed;
} }
/** @Override
* Gets the medium speed calculated based on the % above the average speed.
*
* @return The speed limit considered as normal.
*/
public int getNormalSpeed() { public int getNormalSpeed() {
normalSpeed = (int) (averageMovingSpeed + (averageMovingSpeed * speedMargin / 100)); normalSpeed = (int) (averageMovingSpeed + (averageMovingSpeed * speedMargin / 100.0));
return normalSpeed; return normalSpeed;
} }
@Override @Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { public boolean updateState() {
Log.d(TAG, "DynamicSpeedTrackPathDescriptor: onSharedPreferences changed " + key);
if (PreferencesUtils.getKey(context, R.string.track_color_mode_percentage_key).equals(key)) {
speedMargin = PreferencesUtils.getInt(context, R.string.track_color_mode_percentage_key,
PreferencesUtils.TRACK_COLOR_MODE_PERCENTAGE_DEFAULT);
}
}
@Override
public boolean needsRedraw() {
long selectedTrackId = PreferencesUtils.getLong(context, R.string.selected_track_id_key); long selectedTrackId = PreferencesUtils.getLong(context, R.string.selected_track_id_key);
if (selectedTrackId == PreferencesUtils.SELECTED_TRACK_ID_DEFAULT) { if (selectedTrackId == PreferencesUtils.SELECTED_TRACK_ID_DEFAULT) {
// Could not find track. Log.d(TAG, "No selected track id.");
return false; return false;
} }
Track track = MyTracksProviderUtils.Factory.get(context).getTrack(selectedTrackId); Track track = MyTracksProviderUtils.Factory.get(context).getTrack(selectedTrackId);
@@ -97,40 +81,48 @@ public class DynamicSpeedTrackPathDescriptor implements TrackPathDescriptor,
Log.d(TAG, "No track for " + selectedTrackId); Log.d(TAG, "No track for " + selectedTrackId);
return false; return false;
} }
TripStatistics stats = track.getTripStatistics(); TripStatistics tripStatistics = track.getTripStatistics();
double newAverageMovingSpeed = (int) Math.floor( double newAverageMovingSpeed = (int) Math.floor(
stats.getAverageMovingSpeed() * UnitConversions.MS_TO_KMH); tripStatistics.getAverageMovingSpeed() * UnitConversions.MS_TO_KMH);
return isDifferenceSignificant(averageMovingSpeed, newAverageMovingSpeed); if (isDifferenceSignificant(averageMovingSpeed, newAverageMovingSpeed)) {
averageMovingSpeed = newAverageMovingSpeed;
return true;
} else {
return false;
}
}
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
if (PreferencesUtils.getKey(context, R.string.track_color_mode_percentage_key).equals(key)) {
speedMargin = PreferencesUtils.getInt(context, R.string.track_color_mode_percentage_key,
PreferencesUtils.TRACK_COLOR_MODE_PERCENTAGE_DEFAULT);
}
} }
/** /**
* Checks whether the old speed and the new speed differ significantly or not. * Returns true if the average moving speed and the new average moving speed
* are significantly different.
*
* @param oldAverageMovingSpeed
* @param newAverageMovingSpeed
*/ */
public boolean isDifferenceSignificant(double oldAverageMovingSpeed, double newAverageMovingSpeed) { @VisibleForTesting
boolean isDifferenceSignificant(double oldAverageMovingSpeed, double newAverageMovingSpeed) {
if (oldAverageMovingSpeed == 0) { if (oldAverageMovingSpeed == 0) {
if (newAverageMovingSpeed == 0) { return newAverageMovingSpeed != 0;
return false;
} else {
averageMovingSpeed = newAverageMovingSpeed;
return true;
}
} }
// Here, both oldAverageMovingSpeed and newAverageMovingSpeed are not zero. // Here, both oldAverageMovingSpeed and newAverageMovingSpeed are not zero.
double maxValue = Math.max(oldAverageMovingSpeed, newAverageMovingSpeed); double maxValue = Math.max(oldAverageMovingSpeed, newAverageMovingSpeed);
double differencePercentage = Math.abs(oldAverageMovingSpeed - newAverageMovingSpeed) double differencePercentage = Math.abs(oldAverageMovingSpeed - newAverageMovingSpeed) / maxValue
/ maxValue * 100; * 100.0;
if (differencePercentage >= CRITICAL_DIFFERENCE_PERCENTAGE) { return differencePercentage >= CRITICAL_DIFFERENCE_PERCENTAGE;
averageMovingSpeed = newAverageMovingSpeed;
return true;
}
return false;
} }
/** /**
* Gets the value of variable speedMargin to check the result of test. * Gets the speed margin.
* @return the value of speedMargin.
*/ */
@VisibleForTesting @VisibleForTesting
int getSpeedMargin() { int getSpeedMargin() {
@@ -138,21 +130,20 @@ public class DynamicSpeedTrackPathDescriptor implements TrackPathDescriptor,
} }
/** /**
* Sets the value of newAverageMovingSpeed to test the method isDifferenceSignificant. * Gets the average moving speed.
* @param newAverageMovingSpeed the value to set.
*/
@VisibleForTesting
void setAverageMovingSpeed(double newAverageMovingSpeed) {
averageMovingSpeed = newAverageMovingSpeed;
}
/**
* Gets the value of averageMovingSpeed to check the result of test.
*
* @return the value of averageMovingSpeed
*/ */
@VisibleForTesting @VisibleForTesting
double getAverageMovingSpeed() { double getAverageMovingSpeed() {
return averageMovingSpeed; return averageMovingSpeed;
} }
/**
* Sets the average moving speed.
*
* @param value the value
*/
@VisibleForTesting
void setAverageMovingSpeed(double value) {
averageMovingSpeed = value;
}
} }
@@ -25,7 +25,6 @@ import com.google.common.annotations.VisibleForTesting;
import android.content.Context; import android.content.Context;
import android.graphics.Canvas; import android.graphics.Canvas;
import android.graphics.Paint; import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point; import android.graphics.Point;
import android.graphics.Rect; import android.graphics.Rect;
@@ -33,117 +32,105 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
/** /**
* A path painter that varies the path colors based on fixed speeds or average speed margin * A path painter that varies the path colors based on fixed speeds or average
* depending of the TrackPathDescriptor passed to its constructor. * speed margin depending of the TrackPathDescriptor passed to its constructor.
* *
* @author Vangelis S. * @author Vangelis S.
*/ */
public class DynamicSpeedTrackPathPainter implements TrackPathPainter { public class DynamicSpeedTrackPathPainter implements TrackPathPainter {
private final Paint selectedTrackPaintSlow;
private final Paint selectedTrackPaintMedium;
private final Paint selectedTrackPaintFast;
private final List<ColoredPath> coloredPaths;
private final TrackPathDescriptor trackPathDescriptor; private final TrackPathDescriptor trackPathDescriptor;
private int slowSpeed; private final Paint slowPaint;
private int normalSpeed; private final Paint mediumPaint;
private final Paint fastPaint;
private final List<ColoredPath> coloredPaths;
public DynamicSpeedTrackPathPainter (Context context, TrackPathDescriptor trackPathDescriptor) { public DynamicSpeedTrackPathPainter(Context context, TrackPathDescriptor trackPathDescriptor) {
this.trackPathDescriptor = trackPathDescriptor; this.trackPathDescriptor = trackPathDescriptor;
slowPaint = TrackPathUtils.getPaint(context, R.color.slow_path);
selectedTrackPaintSlow = TrackPathUtilities.getPaint(R.color.slow_path, context); mediumPaint = TrackPathUtils.getPaint(context, R.color.normal_path);
selectedTrackPaintMedium = TrackPathUtilities.getPaint(R.color.normal_path, context); fastPaint = TrackPathUtils.getPaint(context, R.color.fast_path);
selectedTrackPaintFast = TrackPathUtilities.getPaint(R.color.fast_path, context); coloredPaths = new ArrayList<ColoredPath>();
this.coloredPaths = new ArrayList<ColoredPath>();
} }
@Override @Override
public void drawTrack(Canvas canvas) { public boolean hasPath() {
for(int i = 0; i < coloredPaths.size(); ++i) { return !coloredPaths.isEmpty();
ColoredPath coloredPath = coloredPaths.get(i); }
canvas.drawPath(coloredPath.getPath(), coloredPath.getPathPaint());
@Override
public boolean updateState() {
return trackPathDescriptor.updateState();
}
@Override
public void updatePath(
Projection projection, Rect viewRect, int startIndex, List<CachedLocation> points) {
boolean hasLastPoint = startIndex != 0 && points.get(startIndex -1).isValid();
Point point = new Point();
if (hasLastPoint) {
GeoPoint geoPoint = points.get(startIndex -1).getGeoPoint();
projection.toPixels(geoPoint, point);
} }
} boolean newSegment = !hasLastPoint;
// Assume if last point exists, it is visible
boolean lastPointVisible = hasLastPoint;
int slowSpeed = trackPathDescriptor.getSlowSpeed();
int normalSpeed = trackPathDescriptor.getNormalSpeed();
@Override for (int i = startIndex; i < points.size(); ++i) {
public void updatePath(Projection projection, Rect viewRect, int startLocationIdx, CachedLocation cachedLocation = points.get(i);
Boolean alwaysVisible, List<CachedLocation> points) {
// Whether to start a new segment on new valid and visible point.
boolean newSegment = startLocationIdx <= 0 || !points.get(startLocationIdx - 1).isValid();
boolean lastVisible = !newSegment;
final Point pt = new Point();
clear(); // If not valid, start a new segment
if (!cachedLocation.isValid()) {
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.isValid()) {
newSegment = true; newSegment = true;
continue; continue;
} }
final GeoPoint geoPoint = loc.getGeoPoint(); GeoPoint geoPoint = cachedLocation.getGeoPoint();
// Check if this breaks the existing segment. // Check if this breaks the existing segment.
boolean visible = alwaysVisible || viewRect.contains( boolean pointVisible = viewRect.contains(geoPoint.getLongitudeE6(), geoPoint.getLatitudeE6());
geoPoint.getLongitudeE6(), geoPoint.getLatitudeE6()); if (!pointVisible && !lastPointVisible) {
if (!visible && !lastVisible) { // This point and the last point are both outside visible area.
// This is a point outside view not connected to a visible one.
newSegment = true; newSegment = true;
} }
lastVisible = visible; lastPointVisible = pointVisible;
// Either move to beginning of a new segment or continue the old one. // Either update point or draw a line from the last point
if (newSegment) { if (newSegment) {
projection.toPixels(geoPoint, pt); projection.toPixels(geoPoint, point);
newSegment = false; newSegment = false;
} else { } else {
ColoredPath coloredPath; ColoredPath coloredPath;
if(loc.getSpeed() <= slowSpeed) { if (cachedLocation.getSpeed() <= slowSpeed) {
coloredPath = new ColoredPath(selectedTrackPaintSlow); coloredPath = new ColoredPath(slowPaint);
} } else if (cachedLocation.getSpeed() <= normalSpeed) {
else if(loc.getSpeed() <= normalSpeed) { coloredPath = new ColoredPath(mediumPaint);
coloredPath = new ColoredPath(selectedTrackPaintMedium);
} else { } else {
coloredPath = new ColoredPath(selectedTrackPaintFast); coloredPath = new ColoredPath(fastPaint);
} }
coloredPath.getPath().moveTo(pt.x, pt.y); coloredPath.getPath().moveTo(point.x, point.y);
projection.toPixels(geoPoint, pt); projection.toPixels(geoPoint, point);
coloredPath.getPath().lineTo(pt.x, pt.y); coloredPath.getPath().lineTo(point.x, point.y);
coloredPaths.add(coloredPath); coloredPaths.add(coloredPath);
} }
} }
} }
@Override @Override
public void clear() public void clearPath() {
{
coloredPaths.clear(); coloredPaths.clear();
} }
@Override @Override
public boolean needsRedraw() { public void drawPath(Canvas canvas) {
return trackPathDescriptor.needsRedraw(); for (int i = 0; i < coloredPaths.size(); i++) {
} ColoredPath coloredPath = coloredPaths.get(i);
canvas.drawPath(coloredPath.getPath(), coloredPath.getPathPaint());
@Override
public Path getLastPath() {
Path path = new Path();
for(int i = 0; i < coloredPaths.size(); ++i) {
path.addPath(coloredPaths.get(i).getPath());
} }
return path;
} }
/** /**
* Returns coloredPaths. * Gets the colored paths.
*
* @return coloredPaths
*/ */
@VisibleForTesting @VisibleForTesting
List<ColoredPath> getColoredPaths() { List<ColoredPath> getColoredPaths() {
@@ -31,40 +31,36 @@ import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
*/ */
public class FixedSpeedTrackPathDescriptor public class FixedSpeedTrackPathDescriptor
implements TrackPathDescriptor, OnSharedPreferenceChangeListener { implements TrackPathDescriptor, OnSharedPreferenceChangeListener {
private final Context context;
private int slowSpeed; private int slowSpeed;
private int normalSpeed; private int normalSpeed;
private final Context context;
public FixedSpeedTrackPathDescriptor(Context context) { public FixedSpeedTrackPathDescriptor(Context context) {
this.context = context; this.context = context;
context.getSharedPreferences(Constants.SETTINGS_NAME, Context.MODE_PRIVATE)
.registerOnSharedPreferenceChangeListener(this);
slowSpeed = PreferencesUtils.getInt(context, R.string.track_color_mode_slow_key, slowSpeed = PreferencesUtils.getInt(context, R.string.track_color_mode_slow_key,
PreferencesUtils.TRACK_COLOR_MODE_SLOW_DEFAULT); PreferencesUtils.TRACK_COLOR_MODE_SLOW_DEFAULT);
normalSpeed = PreferencesUtils.getInt(context, R.string.track_color_mode_medium_key, normalSpeed = PreferencesUtils.getInt(context, R.string.track_color_mode_medium_key,
PreferencesUtils.TRACK_COLOR_MODE_MEDIUM_DEFAULT); PreferencesUtils.TRACK_COLOR_MODE_MEDIUM_DEFAULT);
context.getSharedPreferences(Constants.SETTINGS_NAME, Context.MODE_PRIVATE)
.registerOnSharedPreferenceChangeListener(this);
} }
/** @Override
* Gets the slow speed for reference.
*
* @return The speed limit considered as slow.
*/
public int getSlowSpeed() { public int getSlowSpeed() {
return slowSpeed; return slowSpeed;
} }
/** @Override
* Gets the normal speed for reference.
*
* @return The speed limit considered as normal.
*/
public int getNormalSpeed() { public int getNormalSpeed() {
return normalSpeed; return normalSpeed;
} }
@Override
public boolean updateState() {
return false;
}
@Override @Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
if (PreferencesUtils.getKey(context, R.string.track_color_mode_slow_key).equals(key)) { if (PreferencesUtils.getKey(context, R.string.track_color_mode_slow_key).equals(key)) {
@@ -75,9 +71,4 @@ public class FixedSpeedTrackPathDescriptor
PreferencesUtils.TRACK_COLOR_MODE_MEDIUM_DEFAULT); PreferencesUtils.TRACK_COLOR_MODE_MEDIUM_DEFAULT);
} }
} }
@Override
public boolean needsRedraw() {
return false;
}
} }
@@ -40,90 +40,103 @@ public class SingleColorTrackPathPainter implements TrackPathPainter {
private Path path; private Path path;
public SingleColorTrackPathPainter(Context context) { public SingleColorTrackPathPainter(Context context) {
selectedTrackPaint = TrackPathUtilities.getPaint(R.color.red, context); selectedTrackPaint = TrackPathUtils.getPaint(context, R.color.red);
} }
@Override @Override
public void drawTrack(Canvas canvas) { public boolean hasPath() {
return path != null;
}
@Override
public boolean updateState() {
return false;
}
@Override
public void updatePath(
Projection projection, Rect viewRect, int startIndex, List<CachedLocation> points) {
if (!hasPath()) {
path = newPath();
}
updatePath(projection, viewRect, startIndex, points, path);
}
@Override
public void clearPath() {
path = null;
}
@Override
public void drawPath(Canvas canvas) {
if (path != null) { if (path != null) {
canvas.drawPath(path, selectedTrackPaint); canvas.drawPath(path, selectedTrackPaint);
} }
} }
@Override
public void updatePath(Projection projection, Rect viewRect, int startLocationIdx,
Boolean alwaysVisible, List<CachedLocation> points) {
path = newPath();
updatePath(projection, viewRect, startLocationIdx, alwaysVisible, points, path);
}
/** /**
* Updates the path. * Updates the path.
* *
* @param projection The Canvas to draw upon. * @param projection the projection
* @param viewRect The Path to be drawn. * @param viewRect the view rectangle
* @param startLocationIdx The start point from where update the path. * @param startIndex the start index
* @param alwaysVisible Flag for always visible. * @param points the points
* @param points The list of points used to update the path. * @param pathToUpdate the path to update
* @param pathToUpdate The path to be created.
*/ */
@VisibleForTesting @VisibleForTesting
void updatePath(Projection projection, Rect viewRect, int startLocationIdx, void updatePath(Projection projection, Rect viewRect, int startIndex, List<CachedLocation> points,
Boolean alwaysVisible, List<CachedLocation> points, Path pathToUpdate) { Path pathToUpdate) {
pathToUpdate.incReserve(points.size()); pathToUpdate.incReserve(points.size() - startIndex);
// Whether to start a new segment on new valid and visible point.
boolean newSegment = startLocationIdx <= 0 || !points.get(startLocationIdx - 1).isValid();
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. boolean hasLastPoint = startIndex != 0 && points.get(startIndex - 1).isValid();
if (!loc.isValid()) { boolean newSegment = !hasLastPoint;
// Assume if last point exists, it is visible
boolean lastPointVisible = hasLastPoint;
Point point = new Point();
for (int i = startIndex; i < points.size(); i++) {
CachedLocation cachedLocation = points.get(i);
// If not valid, start a new segment
if (!cachedLocation.isValid()) {
newSegment = true; newSegment = true;
continue; continue;
} }
final GeoPoint geoPoint = loc.getGeoPoint(); GeoPoint geoPoint = cachedLocation.getGeoPoint();
// Check if this breaks the existing segment. // Check if this breaks the existing segment.
boolean visible = alwaysVisible boolean pointVisible = viewRect.contains(geoPoint.getLongitudeE6(), geoPoint.getLatitudeE6());
|| viewRect.contains(geoPoint.getLongitudeE6(), geoPoint.getLatitudeE6()); if (!pointVisible && !lastPointVisible) {
if (!visible && !lastVisible) { // This point and the last point are both outside visible area.
// This is a point outside view not connected to a visible one.
newSegment = true; newSegment = true;
} }
lastVisible = visible; lastPointVisible = pointVisible;
// Either move to beginning of a new segment or continue the old one. // Either update point or draw a line from the last point
projection.toPixels(geoPoint, pt); projection.toPixels(geoPoint, point);
if (newSegment) { if (newSegment) {
pathToUpdate.moveTo(pt.x, pt.y); pathToUpdate.moveTo(point.x, point.y);
newSegment = false; newSegment = false;
} else { } else {
pathToUpdate.lineTo(pt.x, pt.y); pathToUpdate.lineTo(point.x, point.y);
} }
} }
} }
@Override /**
public void clear() { * Creates a new path.
path = null; */
@VisibleForTesting
protected Path newPath() {
return new Path();
} }
@Override /**
public boolean needsRedraw() { * Gets the path.
return false; */
} @VisibleForTesting
public Path getPath() {
@Override
public Path getLastPath() {
return path; return path;
} }
// Visible for testing
public Path newPath() {
return new Path();
}
} }
@@ -13,6 +13,7 @@
* License for the specific language governing permissions and limitations under * License for the specific language governing permissions and limitations under
* the License. * the License.
*/ */
package com.google.android.apps.mytracks.maps; package com.google.android.apps.mytracks.maps;
/** /**
@@ -21,18 +22,19 @@ package com.google.android.apps.mytracks.maps;
* @author Vangelis S. * @author Vangelis S.
*/ */
public interface TrackPathDescriptor { public interface TrackPathDescriptor {
/**
* @return The maximum speed which is considered slow.
*/
int getSlowSpeed();
/** /**
* @return The maximum speed which is considered normal. * Gets the maximum speed which is considered slow.
*/ */
int getNormalSpeed(); public int getSlowSpeed();
/** /**
* @return True if the path needs to be updated. * Gets the maximum speed which is considered normal.
*/ */
boolean needsRedraw(); public int getNormalSpeed();
/**
* Updates state. Returns true if the state is updated.
*/
public boolean updateState();
} }
@@ -13,13 +13,13 @@
* License for the specific language governing permissions and limitations under * License for the specific language governing permissions and limitations under
* the License. * the License.
*/ */
package com.google.android.apps.mytracks.maps; package com.google.android.apps.mytracks.maps;
import com.google.android.apps.mytracks.MapOverlay.CachedLocation; import com.google.android.apps.mytracks.MapOverlay.CachedLocation;
import com.google.android.maps.Projection; import com.google.android.maps.Projection;
import android.graphics.Canvas; import android.graphics.Canvas;
import android.graphics.Path;
import android.graphics.Rect; import android.graphics.Rect;
import java.util.List; import java.util.List;
@@ -32,37 +32,35 @@ import java.util.List;
public interface TrackPathPainter { public interface TrackPathPainter {
/** /**
* Clears the related data. * Returns true if has path.
*/ */
void clear(); public boolean hasPath();
/** /**
* Draws the path to the canvas. * Updates state. Returns true if the state is updated.
* @param canvas The Canvas to draw upon
*/ */
void drawTrack(Canvas canvas); public boolean updateState();
/** /**
* Updates the path. * Updates the path. Creates a new path if necessary
* @param projection The Canvas to draw upon. *
* @param viewRect The Path to be drawn. * @param projection the projection
* @param startLocationIdx The start point from where update the path. * @param viewRect the view rectangle
* @param alwaysVisible Flag for alwaysvisible. * @param startIndex the start index
* @param points The list of points used to update the path. * @param points the points
*/ */
void updatePath(Projection projection, Rect viewRect, int startLocationIdx, public void updatePath(
Boolean alwaysVisible, List<CachedLocation> points); Projection projection, Rect viewRect, int startIndex, List<CachedLocation> points);
/** /**
* @return True if the path needs to be updated. * Clears the path.
*/ */
boolean needsRedraw(); public void clearPath();
/** /**
* @return The path being used currently. * Draws the path.
*
* @param canvas the canvas
*/ */
Path getLastPath(); public void drawPath(Canvas canvas);
} }
@@ -13,6 +13,7 @@
* License for the specific language governing permissions and limitations under * License for the specific language governing permissions and limitations under
* the License. * the License.
*/ */
package com.google.android.apps.mytracks.maps; package com.google.android.apps.mytracks.maps;
import static com.google.android.apps.mytracks.Constants.TAG; import static com.google.android.apps.mytracks.Constants.TAG;
@@ -24,32 +25,31 @@ import android.content.Context;
import android.util.Log; import android.util.Log;
/** /**
* A factory for TrackPathPainters. * A factory for {@link TrackPathPainter}.
* *
* @author Vangelis S. * @author Vangelis S.
*/ */
public class TrackPathPainterFactory { public class TrackPathPainterFactory {
private TrackPathPainterFactory() { private TrackPathPainterFactory() {}
}
/** /**
* Get a new TrackPathPainter. * Get a new {@link TrackPathPainter}.
* @param context Context to fetch system preferences. *
* @return The TrackPathPainter that corresponds to the track color mode setting. * @param context the context
*/ */
public static TrackPathPainter getTrackPathPainter(Context context) { public static TrackPathPainter getTrackPathPainter(Context context) {
String trackColorMode = PreferencesUtils.getString(context, R.string.track_color_mode_key, String trackColorMode = PreferencesUtils.getString(context, R.string.track_color_mode_key,
context.getString(R.string.settings_map_track_color_mode_single_value)); context.getString(R.string.settings_map_track_color_mode_single_value));
Log.i(TAG, "Creating track path painter of type: " + trackColorMode); Log.i(TAG, "Creating track path painter of type: " + trackColorMode);
if (context.getString(R.string.settings_map_track_color_mode_fixed_value) if (context.getString(R.string.settings_map_track_color_mode_dynamic_value)
.equals(trackColorMode)) {
return new DynamicSpeedTrackPathPainter(context, new FixedSpeedTrackPathDescriptor(context));
} else if (context.getString(R.string.settings_map_track_color_mode_dynamic_value)
.equals(trackColorMode)) { .equals(trackColorMode)) {
return new DynamicSpeedTrackPathPainter(context, new DynamicSpeedTrackPathDescriptor( return new DynamicSpeedTrackPathPainter(context, new DynamicSpeedTrackPathDescriptor(
context)); context));
} else if (context.getString(R.string.settings_map_track_color_mode_fixed_value)
.equals(trackColorMode)) {
return new DynamicSpeedTrackPathPainter(context, new FixedSpeedTrackPathDescriptor(context));
} else { } else {
return new SingleColorTrackPathPainter(context); return new SingleColorTrackPathPainter(context);
} }
@@ -13,21 +13,30 @@
* License for the specific language governing permissions and limitations under * License for the specific language governing permissions and limitations under
* the License. * the License.
*/ */
package com.google.android.apps.mytracks.maps; package com.google.android.apps.mytracks.maps;
import android.content.Context; import android.content.Context;
import android.graphics.Paint; import android.graphics.Paint;
/** /**
* Various utility functions for TrackPath painting. * Various utility functions for track path painting.
* *
* @author Vangelis S. * @author Vangelis S.
*/ */
public class TrackPathUtilities { public class TrackPathUtils {
public static Paint getPaint(int id, Context context) { private TrackPathUtils() {}
/**
* Gets a paint.
*
* @param context the context
* @param colorId the color id
*/
public static Paint getPaint(Context context, int colorId) {
Paint paint = new Paint(); Paint paint = new Paint();
paint.setColor(context.getResources().getColor(id)); paint.setColor(context.getResources().getColor(colorId));
paint.setStrokeWidth(3); paint.setStrokeWidth(3);
paint.setStyle(Paint.Style.STROKE); paint.setStyle(Paint.Style.STROKE);
paint.setAntiAlias(true); paint.setAntiAlias(true);
@@ -71,21 +71,22 @@ public class MapOverlayTest extends AndroidTestCase {
mockMyTracksOverlay.addLocation(location); mockMyTracksOverlay.addLocation(location);
assertEquals(2, mockMyTracksOverlay.getNumLocations()); assertEquals(2, mockMyTracksOverlay.getNumLocations());
assertEquals(0, mockMyTracksOverlay.getNumWaypoints()); assertEquals(0, mockMyTracksOverlay.getNumWaypoints());
assertNull(mockMyTracksOverlay.getTrackPathPainter().getLastPath()); assertFalse(mockMyTracksOverlay.getTrackPathPainter().hasPath());
// Draw and make sure that we don't lose any point. // Draw and make sure that we don't lose any point.
mockMyTracksOverlay.draw(canvas, mapView, false); mockMyTracksOverlay.draw(canvas, mapView, false);
assertEquals(2, mockMyTracksOverlay.getNumLocations()); assertEquals(2, mockMyTracksOverlay.getNumLocations());
assertEquals(0, mockMyTracksOverlay.getNumWaypoints()); assertEquals(0, mockMyTracksOverlay.getNumWaypoints());
assertNotNull(mockMyTracksOverlay.getTrackPathPainter().getLastPath()); assertTrue(mockMyTracksOverlay.getTrackPathPainter().hasPath());
assertTrue(mockMyTracksOverlay.getTrackPathPainter().getLastPath() instanceof MockPath); SingleColorTrackPathPainter trackPathPainter = (SingleColorTrackPathPainter) mockMyTracksOverlay
MockPath path = (MockPath) mockMyTracksOverlay.getTrackPathPainter().getLastPath(); .getTrackPathPainter();
MockPath path = (MockPath) trackPathPainter.getPath();
assertEquals(2, path.getTotalPoints()); assertEquals(2, path.getTotalPoints());
mockMyTracksOverlay.draw(canvas, mapView, true); mockMyTracksOverlay.draw(canvas, mapView, true);
assertEquals(2, mockMyTracksOverlay.getNumLocations()); assertEquals(2, mockMyTracksOverlay.getNumLocations());
assertEquals(0, mockMyTracksOverlay.getNumWaypoints()); assertEquals(0, mockMyTracksOverlay.getNumWaypoints());
assertNotNull(mockMyTracksOverlay.getTrackPathPainter().getLastPath()); assertTrue(mockMyTracksOverlay.getTrackPathPainter().hasPath());
} }
/** /**
@@ -124,7 +125,7 @@ public class MapOverlayTest extends AndroidTestCase {
mockMyTracksOverlay.addWaypoint(waypoint); mockMyTracksOverlay.addWaypoint(waypoint);
assertEquals(1, mockMyTracksOverlay.getNumWaypoints()); assertEquals(1, mockMyTracksOverlay.getNumWaypoints());
assertEquals(0, mockMyTracksOverlay.getNumLocations()); assertEquals(0, mockMyTracksOverlay.getNumLocations());
assertNull(mockMyTracksOverlay.getTrackPathPainter().getLastPath()); assertFalse(mockMyTracksOverlay.getTrackPathPainter().hasPath());
final int waypoints = 10; final int waypoints = 10;
for (int i = 0; i < waypoints; ++i) { for (int i = 0; i < waypoints; ++i) {
@@ -134,7 +135,7 @@ public class MapOverlayTest extends AndroidTestCase {
} }
assertEquals(1 + waypoints, mockMyTracksOverlay.getNumWaypoints()); assertEquals(1 + waypoints, mockMyTracksOverlay.getNumWaypoints());
assertEquals(0, mockMyTracksOverlay.getNumLocations()); assertEquals(0, mockMyTracksOverlay.getNumLocations());
assertNull(mockMyTracksOverlay.getTrackPathPainter().getLastPath()); assertFalse(mockMyTracksOverlay.getTrackPathPainter().hasPath());
} }
/** /**
@@ -174,15 +175,16 @@ public class MapOverlayTest extends AndroidTestCase {
// Shadow. // Shadow.
mockMyTracksOverlay.draw(canvas, mapView, true); mockMyTracksOverlay.draw(canvas, mapView, true);
// We don't expect to do anything if // We don't expect to do anything if
assertNull(mockMyTracksOverlay.getTrackPathPainter().getLastPath()); assertFalse(mockMyTracksOverlay.getTrackPathPainter().hasPath());
assertEquals(40, mockMyTracksOverlay.getNumWaypoints()); assertEquals(40, mockMyTracksOverlay.getNumWaypoints());
assertEquals(100, mockMyTracksOverlay.getNumLocations()); assertEquals(100, mockMyTracksOverlay.getNumLocations());
// No shadow. // No shadow.
mockMyTracksOverlay.draw(canvas, mapView, false); mockMyTracksOverlay.draw(canvas, mapView, false);
assertNotNull(mockMyTracksOverlay.getTrackPathPainter().getLastPath()); assertTrue(mockMyTracksOverlay.getTrackPathPainter().hasPath());
assertTrue(mockMyTracksOverlay.getTrackPathPainter().getLastPath() instanceof MockPath); SingleColorTrackPathPainter trackPathPainter = (SingleColorTrackPathPainter) mockMyTracksOverlay
MockPath path = (MockPath) mockMyTracksOverlay.getTrackPathPainter().getLastPath(); .getTrackPathPainter();
MockPath path = (MockPath) trackPathPainter.getPath();
assertEquals(40, mockMyTracksOverlay.getNumWaypoints()); assertEquals(40, mockMyTracksOverlay.getNumWaypoints());
assertEquals(100, mockMyTracksOverlay.getNumLocations()); assertEquals(100, mockMyTracksOverlay.getNumLocations());
assertEquals(100, path.getTotalPoints()); assertEquals(100, path.getTotalPoints());
@@ -44,6 +44,6 @@ public class MockMyTracksOverlay extends MapOverlay {
@Override @Override
public Rect getMapViewRect(MapView mapView) { public Rect getMapViewRect(MapView mapView) {
return new Rect(0, 0, 100, 100); return new Rect(0, 0, (int) (100 * 1E6), (int) (100 * 1E6));
} }
} }
@@ -57,35 +57,6 @@ public class DynamicSpeedTrackPathDescriptorTest extends AndroidTestCase {
} }
} }
/**
* Tests {@link DynamicSpeedTrackPathDescriptor#onSharedPreferenceChanged(SharedPreferences,
* String)} when the key is null.
*/
public void testOnSharedPreferenceChanged_nullKey() {
DynamicSpeedTrackPathDescriptor dynamicSpeedTrackPathDescriptor = new DynamicSpeedTrackPathDescriptor(
context);
int speedMargin = dynamicSpeedTrackPathDescriptor.getSpeedMargin();
// Change value in shared preferences.
PreferencesUtils.setInt(context, R.string.track_color_mode_percentage_key, speedMargin + 2);
dynamicSpeedTrackPathDescriptor.onSharedPreferenceChanged(sharedPreferences, null);
assertEquals(speedMargin, dynamicSpeedTrackPathDescriptor.getSpeedMargin());
}
/**
* Tests {@link DynamicSpeedTrackPathDescriptor#onSharedPreferenceChanged(SharedPreferences,
* String)} when the key is not null, and not trackColorModeDynamicVariation.
*/
public void testOnSharedPreferenceChanged_otherKey() {
DynamicSpeedTrackPathDescriptor dynamicSpeedTrackPathDescriptor = new DynamicSpeedTrackPathDescriptor(
context);
int speedMargin = dynamicSpeedTrackPathDescriptor.getSpeedMargin();
// Change value in shared preferences.
PreferencesUtils.setInt(context, R.string.track_color_mode_percentage_key, speedMargin + 2);
dynamicSpeedTrackPathDescriptor.onSharedPreferenceChanged(sharedPreferences, "anyKey");
assertEquals(speedMargin, dynamicSpeedTrackPathDescriptor.getSpeedMargin());
}
/** /**
* Tests {@link DynamicSpeedTrackPathDescriptor#onSharedPreferenceChanged(SharedPreferences, * Tests {@link DynamicSpeedTrackPathDescriptor#onSharedPreferenceChanged(SharedPreferences,
* String)} when the key is trackColorModeDynamicVariation. * String)} when the key is trackColorModeDynamicVariation.
@@ -120,7 +91,7 @@ public class DynamicSpeedTrackPathDescriptorTest extends AndroidTestCase {
} }
/** /**
* Tests {@link DynamicSpeedTrackPathDescriptor#needsRedraw()} by wrong track * Tests {@link DynamicSpeedTrackPathDescriptor#updateState()} by wrong track
* id. * id.
*/ */
public void testNeedsRedraw_WrongTrackId() { public void testNeedsRedraw_WrongTrackId() {
@@ -128,11 +99,11 @@ public class DynamicSpeedTrackPathDescriptorTest extends AndroidTestCase {
context, R.string.selected_track_id_key, PreferencesUtils.SELECTED_TRACK_ID_DEFAULT); context, R.string.selected_track_id_key, PreferencesUtils.SELECTED_TRACK_ID_DEFAULT);
DynamicSpeedTrackPathDescriptor dynamicSpeedTrackPathDescriptor = new DynamicSpeedTrackPathDescriptor( DynamicSpeedTrackPathDescriptor dynamicSpeedTrackPathDescriptor = new DynamicSpeedTrackPathDescriptor(
context); context);
assertEquals(false, dynamicSpeedTrackPathDescriptor.needsRedraw()); assertEquals(false, dynamicSpeedTrackPathDescriptor.updateState());
} }
/** /**
* Tests {@link DynamicSpeedTrackPathDescriptor#needsRedraw()} by different * Tests {@link DynamicSpeedTrackPathDescriptor#updateState()} by different
* averageMovingSpeed. * averageMovingSpeed.
*/ */
public void testIsDiffereceSignificant() { public void testIsDiffereceSignificant() {
@@ -145,8 +116,7 @@ public class DynamicSpeedTrackPathDescriptorTest extends AndroidTestCase {
// Difference is more than CRITICAL_DIFFERENCE_PERCENTAGE // Difference is more than CRITICAL_DIFFERENCE_PERCENTAGE
30 * (1 + (DynamicSpeedTrackPathDescriptor.CRITICAL_DIFFERENCE_PERCENTAGE / 100.00) * 2) }; 30 * (1 + (DynamicSpeedTrackPathDescriptor.CRITICAL_DIFFERENCE_PERCENTAGE / 100.00) * 2) };
boolean[] expectedValues = { true, false, false, true }; boolean[] expectedValues = { true, false, false, true };
double[] expectedAverageMovingSpeed = { 20, 30, 30, double[] expectedAverageMovingSpeed = { 0, 30, 30, 30 };
30 * (1 + (DynamicSpeedTrackPathDescriptor.CRITICAL_DIFFERENCE_PERCENTAGE / 100.00) * 2) };
// Test // Test
for (int i = 0; i < newAverageMovingSpeed.length; i++) { for (int i = 0; i < newAverageMovingSpeed.length; i++) {
dynamicSpeedTrackPathDescriptor.setAverageMovingSpeed(averageMovingSpeeds[i]); dynamicSpeedTrackPathDescriptor.setAverageMovingSpeed(averageMovingSpeeds[i]);
@@ -62,7 +62,7 @@ public class DynamicSpeedTrackPathPainterTest extends TrackPathPainterTestCase {
public void testUpdatePath_AllInvalidLocation() { public void testUpdatePath_AllInvalidLocation() {
List<CachedLocation> points = createCachedLocations(NUMBER_OF_LOCATIONS, INVALID_LATITUDE, -1); List<CachedLocation> points = createCachedLocations(NUMBER_OF_LOCATIONS, INVALID_LATITUDE, -1);
dynamicSpeedTrackPathPainter.updatePath(myTracksOverlay.getMapProjection(mockView), dynamicSpeedTrackPathPainter.updatePath(myTracksOverlay.getMapProjection(mockView),
myTracksOverlay.getMapViewRect(mockView), 1, true, points); myTracksOverlay.getMapViewRect(mockView), 1, points);
AndroidMock.verify(trackPathDescriptor); AndroidMock.verify(trackPathDescriptor);
// Should be zero for there is no valid locations. // Should be zero for there is no valid locations.
assertEquals(0, dynamicSpeedTrackPathPainter.getColoredPaths().size()); assertEquals(0, dynamicSpeedTrackPathPainter.getColoredPaths().size());
@@ -80,7 +80,7 @@ public class DynamicSpeedTrackPathPainterTest extends TrackPathPainterTestCase {
// Gets a number as the start index of points. // Gets a number as the start index of points.
int startLocationIdx = NUMBER_OF_LOCATIONS / 2; int startLocationIdx = NUMBER_OF_LOCATIONS / 2;
dynamicSpeedTrackPathPainter.updatePath(myTracksOverlay.getMapProjection(mockView), dynamicSpeedTrackPathPainter.updatePath(myTracksOverlay.getMapProjection(mockView),
myTracksOverlay.getMapViewRect(mockView), startLocationIdx, true, points); myTracksOverlay.getMapViewRect(mockView), startLocationIdx, points);
AndroidMock.verify(trackPathDescriptor); AndroidMock.verify(trackPathDescriptor);
assertEquals(NUMBER_OF_LOCATIONS - startLocationIdx, dynamicSpeedTrackPathPainter assertEquals(NUMBER_OF_LOCATIONS - startLocationIdx, dynamicSpeedTrackPathPainter
@@ -123,7 +123,7 @@ public class DynamicSpeedTrackPathPainterTest extends TrackPathPainterTestCase {
slowSpeed)); slowSpeed));
dynamicSpeedTrackPathPainter.updatePath(myTracksOverlay.getMapProjection(mockView), dynamicSpeedTrackPathPainter.updatePath(myTracksOverlay.getMapProjection(mockView),
myTracksOverlay.getMapViewRect(mockView), startLocationIdx, true, points); myTracksOverlay.getMapViewRect(mockView), startLocationIdx, points);
AndroidMock.verify(trackPathDescriptor); AndroidMock.verify(trackPathDescriptor);
List<ColoredPath> coloredPath = dynamicSpeedTrackPathPainter.getColoredPaths(); List<ColoredPath> coloredPath = dynamicSpeedTrackPathPainter.getColoredPaths();
@@ -31,9 +31,10 @@ import java.util.List;
*/ */
public class SingleColorTrackPathPainterTest extends TrackPathPainterTestCase { public class SingleColorTrackPathPainterTest extends TrackPathPainterTestCase {
private static final int NUMBER_OF_LOCATIONS = 10;
private SingleColorTrackPathPainter singleColorTrackPathPainter; private SingleColorTrackPathPainter singleColorTrackPathPainter;
private Path pathMock; private Path pathMock;
private static final int NUMBER_OF_LOCATIONS = 100;
/** /**
* Initials a mocked TrackPathDescriptor object and * Initials a mocked TrackPathDescriptor object and
@@ -44,8 +45,8 @@ public class SingleColorTrackPathPainterTest extends TrackPathPainterTestCase {
protected void setUp() throws Exception { protected void setUp() throws Exception {
super.setUp(); super.setUp();
pathMock = AndroidMock.createStrictMock(Path.class);
singleColorTrackPathPainter = new SingleColorTrackPathPainter(getContext()); singleColorTrackPathPainter = new SingleColorTrackPathPainter(getContext());
pathMock = AndroidMock.createStrictMock(Path.class);
} }
/** /**
@@ -54,19 +55,20 @@ public class SingleColorTrackPathPainterTest extends TrackPathPainterTestCase {
* method when all locations are valid. * method when all locations are valid.
*/ */
public void testUpdatePath_AllValidLocation() { public void testUpdatePath_AllValidLocation() {
pathMock.incReserve(NUMBER_OF_LOCATIONS);
List<CachedLocation> points = createCachedLocations(NUMBER_OF_LOCATIONS,
TrackStubUtils.INITIAL_LATITUDE, -1);
// Gets a number as the start index of points. // Gets a number as the start index of points.
int startLocationIdx = NUMBER_OF_LOCATIONS / 2; int startLocationIdx = NUMBER_OF_LOCATIONS / 2;
pathMock.incReserve(NUMBER_OF_LOCATIONS - startLocationIdx);
List<CachedLocation> points = createCachedLocations(NUMBER_OF_LOCATIONS,
TrackStubUtils.INITIAL_LATITUDE, -1);
for (int i = startLocationIdx; i < NUMBER_OF_LOCATIONS; i++) { for (int i = startLocationIdx; i < NUMBER_OF_LOCATIONS; i++) {
pathMock.lineTo(0, 0); pathMock.lineTo(0, 0);
} }
AndroidMock.replay(pathMock); AndroidMock.replay(pathMock);
singleColorTrackPathPainter.updatePath(myTracksOverlay.getMapProjection(mockView), singleColorTrackPathPainter.updatePath(myTracksOverlay.getMapProjection(mockView),
myTracksOverlay.getMapViewRect(mockView), startLocationIdx, true, points, pathMock); myTracksOverlay.getMapViewRect(mockView), startLocationIdx, points, pathMock);
AndroidMock.verify(pathMock); AndroidMock.verify(pathMock);
} }
@@ -76,20 +78,20 @@ public class SingleColorTrackPathPainterTest extends TrackPathPainterTestCase {
* method when all locations are invalid. * method when all locations are invalid.
*/ */
public void testUpdatePath_AllInvalidLocation() { public void testUpdatePath_AllInvalidLocation() {
pathMock.incReserve(NUMBER_OF_LOCATIONS); int startLocationIdx = NUMBER_OF_LOCATIONS / 2;
pathMock.incReserve(NUMBER_OF_LOCATIONS - startLocationIdx);
List<CachedLocation> points = createCachedLocations(NUMBER_OF_LOCATIONS, INVALID_LATITUDE, -1); List<CachedLocation> points = createCachedLocations(NUMBER_OF_LOCATIONS, INVALID_LATITUDE, -1);
// Gets a random number from 1 to numberOfLocations. // Gets a random number from 1 to numberOfLocations.
int startLocationIdx = NUMBER_OF_LOCATIONS / 2;
AndroidMock.replay(pathMock); AndroidMock.replay(pathMock);
singleColorTrackPathPainter.updatePath(myTracksOverlay.getMapProjection(mockView), singleColorTrackPathPainter.updatePath(myTracksOverlay.getMapProjection(mockView),
myTracksOverlay.getMapViewRect(mockView), startLocationIdx, true, points, pathMock); myTracksOverlay.getMapViewRect(mockView), startLocationIdx, points, pathMock);
AndroidMock.verify(pathMock); AndroidMock.verify(pathMock);
} }
/** /**
* Tests the * Tests the {@link SingleColorTrackPathPainter#updatePath(com.google.android.maps.Projection,
* {@link SingleColorTrackPathPainter#updatePath(com.google.android.maps.Projection, android.graphics.Rect, int, Boolean, List, Path)} * android.graphics.Rect, int, Boolean, List, Path)} method when there are
* method when there are three segments. * three segments.
*/ */
public void testUpdatePath_ThreeSegments() { public void testUpdatePath_ThreeSegments() {
// First segment. // First segment.
@@ -103,7 +105,7 @@ public class SingleColorTrackPathPainterTest extends TrackPathPainterTestCase {
points.addAll(createCachedLocations(NUMBER_OF_LOCATIONS, TrackStubUtils.INITIAL_LATITUDE, -1)); points.addAll(createCachedLocations(NUMBER_OF_LOCATIONS, TrackStubUtils.INITIAL_LATITUDE, -1));
// Gets a random number from 1 to numberOfLocations. // Gets a random number from 1 to numberOfLocations.
int startLocationIdx = NUMBER_OF_LOCATIONS / 2; int startLocationIdx = NUMBER_OF_LOCATIONS / 2;
pathMock.incReserve(NUMBER_OF_LOCATIONS *3 + 1 +1); pathMock.incReserve(NUMBER_OF_LOCATIONS *3 + 1 +1 - startLocationIdx);
for (int i = 0; i < NUMBER_OF_LOCATIONS - startLocationIdx; i++) { for (int i = 0; i < NUMBER_OF_LOCATIONS - startLocationIdx; i++) {
pathMock.lineTo(0, 0); pathMock.lineTo(0, 0);
} }
@@ -118,7 +120,7 @@ public class SingleColorTrackPathPainterTest extends TrackPathPainterTestCase {
AndroidMock.replay(pathMock); AndroidMock.replay(pathMock);
singleColorTrackPathPainter.updatePath(myTracksOverlay.getMapProjection(mockView), singleColorTrackPathPainter.updatePath(myTracksOverlay.getMapProjection(mockView),
myTracksOverlay.getMapViewRect(mockView), startLocationIdx, true, points, pathMock); myTracksOverlay.getMapViewRect(mockView), startLocationIdx, points, pathMock);
AndroidMock.verify(pathMock); AndroidMock.verify(pathMock);
} }
} }
@@ -40,13 +40,12 @@ public class TrackPathDescriptorDynamicSpeedTest extends TrackPathPainterTestCas
myTracksOverlay.setTrackPathPainter(painter); myTracksOverlay.setTrackPathPainter(painter);
int startLocationIdx = 0; int startLocationIdx = 0;
Boolean alwaysVisible = true;
assertNotNull(painter); assertNotNull(painter);
painter.updatePath(myTracksOverlay.getMapProjection(mockView), painter.updatePath(myTracksOverlay.getMapProjection(mockView),
myTracksOverlay.getMapViewRect(mockView), startLocationIdx, alwaysVisible, myTracksOverlay.getMapViewRect(mockView), startLocationIdx,
myTracksOverlay.getPoints()); myTracksOverlay.getPoints());
assertNotNull(myTracksOverlay.getTrackPathPainter().getLastPath()); assertNotNull(myTracksOverlay.getTrackPathPainter().hasPath());
painter.drawTrack(canvas); painter.drawPath(canvas);
} }
} }
@@ -40,13 +40,11 @@ public class TrackPathDescriptorFixedSpeedTest extends TrackPathPainterTestCase
myTracksOverlay.setTrackPathPainter(painter); myTracksOverlay.setTrackPathPainter(painter);
int startLocationIdx = 0; int startLocationIdx = 0;
Boolean alwaysVisible = true;
assertNotNull(painter); assertNotNull(painter);
painter.updatePath(myTracksOverlay.getMapProjection(mockView), painter.updatePath(myTracksOverlay.getMapProjection(mockView),
myTracksOverlay.getMapViewRect(mockView), startLocationIdx, alwaysVisible, myTracksOverlay.getMapViewRect(mockView), startLocationIdx, myTracksOverlay.getPoints());
myTracksOverlay.getPoints()); assertNotNull(myTracksOverlay.getTrackPathPainter().hasPath());
assertNotNull(myTracksOverlay.getTrackPathPainter().getLastPath()); painter.drawPath(canvas);
painter.drawTrack(canvas);
} }
} }
@@ -55,7 +55,6 @@ public class TrackPathPainterFactoryTest extends TrackPathPainterTestCase {
context, R.string.track_color_mode_key, context.getString(track_color_mode)); context, R.string.track_color_mode_key, context.getString(track_color_mode));
int startLocationIdx = 0; int startLocationIdx = 0;
Boolean alwaysVisible = true;
TrackPathPainter painter = TrackPathPainterFactory.getTrackPathPainter(context); TrackPathPainter painter = TrackPathPainterFactory.getTrackPathPainter(context);
myTracksOverlay.setTrackPathPainter(painter); myTracksOverlay.setTrackPathPainter(painter);
@@ -64,9 +63,9 @@ public class TrackPathPainterFactoryTest extends TrackPathPainterTestCase {
assertTrue(c.isInstance(painter)); assertTrue(c.isInstance(painter));
painter.updatePath(myTracksOverlay.getMapProjection(mockView), painter.updatePath(myTracksOverlay.getMapProjection(mockView),
myTracksOverlay.getMapViewRect(mockView), startLocationIdx, alwaysVisible, myTracksOverlay.getMapViewRect(mockView), startLocationIdx,
myTracksOverlay.getPoints()); myTracksOverlay.getPoints());
assertNotNull(myTracksOverlay.getTrackPathPainter().getLastPath()); assertNotNull(myTracksOverlay.getTrackPathPainter().hasPath());
painter.drawTrack(canvas); painter.drawPath(canvas);
} }
} }
@@ -39,13 +39,12 @@ public class TrackPathPainterSingleColorTest extends TrackPathPainterTestCase {
myTracksOverlay.setTrackPathPainter(painter); myTracksOverlay.setTrackPathPainter(painter);
int startLocationIdx = 0; int startLocationIdx = 0;
Boolean alwaysVisible = true;
assertNotNull(painter); assertNotNull(painter);
painter.updatePath(myTracksOverlay.getMapProjection(mockView), painter.updatePath(myTracksOverlay.getMapProjection(mockView),
myTracksOverlay.getMapViewRect(mockView), startLocationIdx, alwaysVisible, myTracksOverlay.getMapViewRect(mockView), startLocationIdx,
myTracksOverlay.getPoints()); myTracksOverlay.getPoints());
assertNotNull(myTracksOverlay.getTrackPathPainter().getLastPath()); assertNotNull(myTracksOverlay.getTrackPathPainter().hasPath());
painter.drawTrack(canvas); painter.drawPath(canvas);
} }
} }