(
Constants.MAX_DISPLAYED_TRACK_POINTS, true);
- /*
- * TODO: Use animation rather than individual resources for each arrow
- * direction.
- */
- final Resources resources = context.getResources();
- arrows = new Drawable[] { resources.getDrawable(R.drawable.arrow_0),
- resources.getDrawable(R.drawable.arrow_20), resources.getDrawable(R.drawable.arrow_40),
- resources.getDrawable(R.drawable.arrow_60), resources.getDrawable(R.drawable.arrow_80),
- resources.getDrawable(R.drawable.arrow_100), resources.getDrawable(R.drawable.arrow_120),
- resources.getDrawable(R.drawable.arrow_140), resources.getDrawable(R.drawable.arrow_160),
- resources.getDrawable(R.drawable.arrow_180), resources.getDrawable(R.drawable.arrow_200),
- resources.getDrawable(R.drawable.arrow_220), resources.getDrawable(R.drawable.arrow_240),
- resources.getDrawable(R.drawable.arrow_260), resources.getDrawable(R.drawable.arrow_280),
- resources.getDrawable(R.drawable.arrow_300), resources.getDrawable(R.drawable.arrow_320),
- resources.getDrawable(R.drawable.arrow_340) };
- arrowWidth = arrows[headingIndex].getIntrinsicWidth();
- arrowHeight = arrows[headingIndex].getIntrinsicHeight();
- for (Drawable arrow : arrows) {
- arrow.setBounds(0, 0, arrowWidth, arrowHeight);
- }
-
- statsMarker = resources.getDrawable(R.drawable.yellow_pushpin);
- markerWidth = statsMarker.getIntrinsicWidth();
- markerHeight = statsMarker.getIntrinsicHeight();
- statsMarker.setBounds(0, 0, markerWidth, markerHeight);
-
- waypointMarker = resources.getDrawable(R.drawable.blue_pushpin);
- waypointMarker.setBounds(0, 0, markerWidth, markerHeight);
-
- startMarker = resources.getDrawable(R.drawable.green_dot);
- startMarker.setBounds(0, 0, markerWidth, markerHeight);
-
- endMarker = resources.getDrawable(R.drawable.red_dot);
- endMarker.setBounds(0, 0, markerWidth, markerHeight);
-
- errorCirclePaint = TrackPathUtils.getPaint(context, R.color.blue);
- errorCirclePaint.setAlpha(127);
-
- trackPathPainter = TrackPathPainterFactory.getTrackPathPainter(context);
-
context.getSharedPreferences(Constants.SETTINGS_NAME, Context.MODE_PRIVATE)
.registerOnSharedPreferenceChangeListener(sharedPreferenceChangeListener);
+ sharedPreferenceChangeListener.onSharedPreferenceChanged(null, null);
}
/**
- * Add a location to the map overlay.
- *
- * NOTE: This method doesn't take ownership of the given location, so it is
- * safe to reuse the same location while calling this method.
+ * Add a location.
*
* @param location the location
*/
public void addLocation(Location location) {
- // Queue up in the pendingPoints until it's merged with points.
- if (!pendingPoints.offer(new CachedLocation(location))) {
- Log.e(TAG, "Unable to add to pendingPoints.");
+ // Queue up in the pendingLocations until it's merged with locations
+ if (!pendingLocations.offer(new CachedLocation(location))) {
+ Log.e(TAG, "Unable to add to pendingLocations.");
}
}
/**
- * Adds a segment split to the map overlay.
+ * Adds a segment split.
*/
public void addSegmentSplit() {
- // Queue up in the pendingPoints until it's merged with points.
- if (!pendingPoints.offer(new CachedLocation())) {
- Log.e(TAG, "Unable to add to pendingPoints");
+ // Queue up in the pendingLocations until it's merged with locations
+ if (!pendingLocations.offer(new CachedLocation())) {
+ Log.e(TAG, "Unable to add to pendingLocations.");
}
}
@@ -223,26 +165,20 @@ public class MapOverlay extends Overlay {
* Clears the locations.
*/
public void clearPoints() {
- synchronized (points) {
- points.clear();
- pendingPoints.clear();
- trackPathPainter.clearPath();
- lastReferencePoint = null;
- lastViewRect = null;
+ synchronized (locations) {
+ locations.clear();
+ pendingLocations.clear();
}
}
/**
- * Adds a waypoint to the map overlay.
+ * Adds a waypoint.
*
* @param waypoint the waypoint
*/
public void addWaypoint(Waypoint waypoint) {
- // Note: We don't cache waypoints because it's not worth the effort.
- if (waypoint != null && waypoint.getLocation() != null) {
- synchronized (waypoints) {
- waypoints.add(waypoint);
- }
+ synchronized (waypoints) {
+ waypoints.add(waypoint);
}
}
@@ -256,327 +192,92 @@ public class MapOverlay extends Overlay {
}
/**
- * Sets whether to draw the track or not.
+ * Sets whether to show the end marker.
*
- * @param trackDrawingEnabled true to draw track
+ * @param show true to show the end marker
*/
- public void setTrackDrawingEnabled(boolean trackDrawingEnabled) {
- this.trackDrawingEnabled = trackDrawingEnabled;
+ public void setShowEndMarker(boolean show) {
+ showEndMarker = show;
}
/**
- * Sets whether to draw the end maker or not.
+ * Updates the track, start and end markers, and waypoints.
*
- * @param showEndMarker true to draw end marker
+ * @param googleMap the google map
+ * @param paths the paths
+ * @param reload true to reload all points
*/
- public void setShowEndMarker(boolean showEndMarker) {
- this.showEndMarker = showEndMarker;
- }
-
- /**
- * Sets my location.
- *
- * @param myLocation my location
- */
- public void setMyLocation(Location myLocation) {
- this.myLocation = myLocation;
- }
-
- /**
- * Sets the heading.
- *
- * @param heading the heading
- * @return true if the visible heading has changed.
- */
- public boolean setHeading(float heading) {
- /*
- * Use -heading because the arrow images are counter-clockwise rather than
- * clockwise.
- */
- int index = Math.round(-heading / 360 * 18);
- while (index < 0) {
- index += 18;
- }
- while (index > 17) {
- index -= 18;
- }
- if (index != headingIndex) {
- headingIndex = index;
- return true;
- } else {
- return false;
- }
- }
-
- @Override
- public void draw(Canvas canvas, MapView mapView, boolean shadow) {
- if (shadow) {
- return;
- }
-
- // It's safe to keep projection within a single draw operation
- Projection projection = getMapProjection(mapView);
- if (projection == null) {
- Log.w(TAG, "No projection, unable to draw.");
- return;
- }
-
- if (trackDrawingEnabled) {
- // Get the current viewing Rect
- Rect viewRect = getMapViewRect(mapView);
-
- // Draw the selected track
- drawTrack(canvas, projection, viewRect);
-
- // Draw the start and end markers
- drawMarkers(canvas, projection);
-
- // Draw the waypoints
- drawWaypoints(canvas, projection);
- }
-
- // Draw the current location
- drawMyLocation(canvas, projection);
- }
-
- @Override
- public boolean onTap(GeoPoint geoPoint, MapView mapView) {
- if (geoPoint.equals(mapView.getMapCenter())) {
- /*
- * There is (unfortunately) no good way to determine whether the tap was
- * caused by an actual tap on the screen or the track ball. If the
- * location is equal to the map center,then it was a track ball press with
- * very high likelihood.
- */
- return false;
- }
- final Location tapLocation = LocationUtils.getLocation(geoPoint);
- double minDistance = Double.MAX_VALUE;
- Waypoint waypoint = null;
- synchronized (waypoints) {
- for (int i = 0; i < waypoints.size(); i++) {
- final Location waypointLocation = waypoints.get(i).getLocation();
- if (waypointLocation == null) {
- continue;
- }
- final double distance = waypointLocation.distanceTo(tapLocation);
- if (distance < minDistance) {
- minDistance = distance;
- waypoint = waypoints.get(i);
- }
- }
- }
-
- if (waypoint != null && minDistance < 15000000 / Math.pow(2, mapView.getZoomLevel())) {
- Intent intent = IntentUtils.newIntent(context, MarkerDetailActivity.class)
- .putExtra(MarkerDetailActivity.EXTRA_MARKER_ID, waypoint.getId());
- context.startActivity(intent);
- return true;
- }
- return super.onTap(geoPoint, mapView);
- }
-
- /**
- * Gets the points.
- */
- @VisibleForTesting
- public List getPoints() {
- return points;
- }
-
- /**
- * Gets the track path painter.
- */
- @VisibleForTesting
- public TrackPathPainter getTrackPathPainter() {
- return trackPathPainter;
- }
-
- /**
- * Sets the track path painter.
- *
- * @param trackPathPainter the track path painter
- */
- @VisibleForTesting
- public void setTrackPathPainter(TrackPathPainter trackPathPainter) {
- this.trackPathPainter = trackPathPainter;
- }
-
- /**
- * Gets the map view projection.
- *
- * @param mapView the map view
- */
- @VisibleForTesting
- protected Projection getMapProjection(MapView mapView) {
- return mapView.getProjection();
- }
-
- /**
- * Gets the map view Rect.
- *
- * @param mapView the map view
- */
- @VisibleForTesting
- protected Rect getMapViewRect(MapView mapView) {
- int width = mapView.getLongitudeSpan();
- int height = mapView.getLatitudeSpan();
- int centerX = mapView.getMapCenter().getLongitudeE6();
- int centerY = mapView.getMapCenter().getLatitudeE6();
- return new Rect(centerX - width / 2, centerY - height / 2, centerX + width / 2, centerY + height
- / 2);
- }
-
- /**
- * Gets number of locations.
- */
- @VisibleForTesting
- int getNumLocations() {
- synchronized (points) {
- return points.size() + pendingPoints.size();
- }
- }
-
- /**
- * Gets number of waypoints.
- */
- @VisibleForTesting
- int getNumWaypoints() {
- synchronized (waypoints) {
- return waypoints.size();
- }
- }
-
- /**
- * Draws the track.
- *
- * @param canvas the canvas
- * @param projection the projection
- * @param viewRect the view rect
- */
- private void drawTrack(Canvas canvas, Projection projection, Rect viewRect) {
- boolean draw;
-
- synchronized (points) {
- // Merge the pending points with the list of cached locations.
- GeoPoint referencePoint = projection.fromPixels(0, 0);
- int newPoints = pendingPoints.drainTo(points);
- boolean newProjection = !viewRect.equals(lastViewRect)
- || !referencePoint.equals(lastReferencePoint);
- // Call updateState first to trigger its side effects.
- boolean currentPathValid = !trackPathPainter.updateState() && !newProjection
- && trackPathPainter.hasPath();
- if (newPoints == 0 && currentPathValid) {
- // No need to update
- draw = true;
+ public void update(GoogleMap googleMap, ArrayList paths, boolean reload) {
+ synchronized (locations) {
+ // Merge pendingLocations with locations
+ int newLocations = pendingLocations.drainTo(locations);
+ boolean needReload = reload || trackPath.updateState();
+ if (needReload) {
+ googleMap.clear();
+ paths.clear();
+ trackPath.updatePath(googleMap, paths, 0, locations);
+ updateStartAndEndMarkers(googleMap);
+ updateWaypoints(googleMap);
} else {
- int numPoints = points.size();
- if (numPoints < 2) {
- // Not enough points to draw a path
- draw = false;
- } else if (currentPathValid) {
- // Incremental update of the path
- draw = true;
- trackPathPainter.updatePath(projection, viewRect, numPoints - newPoints, points);
- } else {
- // Reload the path
- draw = true;
- trackPathPainter.clearPath();
- trackPathPainter.updatePath(projection, viewRect, 0, points);
+ if (newLocations != 0) {
+ int numLocations = locations.size();
+ trackPath.updatePath(googleMap, paths, numLocations - newLocations, locations);
}
}
- lastReferencePoint = referencePoint;
- lastViewRect = viewRect;
- }
- if (draw) {
- trackPathPainter.drawPath(canvas);
}
}
/**
- * Draws the start and end markers.
+ * Updates the start and end markers.
*
- * @param canvas the canvas
- * @param projection the projection
+ * @param googleMap the google map
*/
- private void drawMarkers(Canvas canvas, Projection projection) {
- int offsetY = (int) (markerHeight * Constants.MARKER_Y_OFFSET_PERCENTAGE);
- // Draw the end marker
+ private void updateStartAndEndMarkers(GoogleMap googleMap) {
+ // Add 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, -offsetY);
+ for (int i = locations.size() - 1; i >= 0; i--) {
+ CachedLocation cachedLocation = locations.get(i);
+ if (cachedLocation.valid) {
+ Marker.Options options = Model.newMarkerOptions().position(cachedLocation.getLatLng())
+ .anchor(MARKER_X_ANCHOR, MARKER_Y_ANCHOR).draggable(false).visible(true)
+ .icon(BitmapDescriptors.fromResource(R.drawable.red_dot));
+ googleMap.addMarker(options);
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, -offsetY);
+ // Add the start marker
+ for (int i = 0; i < locations.size(); i++) {
+ CachedLocation cachedLocation = locations.get(i);
+ if (cachedLocation.valid) {
+ Marker.Options options = Model.newMarkerOptions().position(cachedLocation.getLatLng())
+ .anchor(MARKER_X_ANCHOR, MARKER_Y_ANCHOR).draggable(false).visible(true)
+ .icon(BitmapDescriptors.fromResource(R.drawable.green_dot));
+ googleMap.addMarker(options);
break;
}
}
}
/**
- * Draws the waypoints.
+ * Updates the waypoints.
*
- * @param canvas the canvas
- * @param projection the projection
+ * @param googleMap the google map.
*/
- private void drawWaypoints(Canvas canvas, Projection projection) {
+ private void updateWaypoints(GoogleMap googleMap) {
synchronized (waypoints) {
- int offsetX = (int) (markerWidth * Constants.WAYPOINT_X_OFFSET_PERCENTAGE);
for (Waypoint waypoint : waypoints) {
Location location = waypoint.getLocation();
- Drawable drawable = waypoint.getType() == Waypoint.TYPE_STATISTICS ? statsMarker
- : waypointMarker;
- drawElement(canvas, projection, LocationUtils.getGeoPoint(location), drawable, -offsetX,
- -markerHeight);
+ LatLng latLng = new LatLng(location.getLatitude(), location.getLongitude());
+ int drawableId = waypoint.getType() == Waypoint.TYPE_STATISTICS ? R.drawable.yellow_pushpin
+ : R.drawable.blue_pushpin;
+ Marker.Options options = Model.newMarkerOptions().position(latLng)
+ .anchor(WAYPOINT_X_ANCHOR, WAYPOINT_Y_ANCHOR).draggable(false).visible(true)
+ .icon(BitmapDescriptors.fromResource(drawableId))
+ .title(String.valueOf(waypoint.getId()));
+ googleMap.addMarker(options);
}
}
}
-
- /**
- * Draws my location.
- *
- * @param canvas the canvas
- * @param projection the projection
- */
- private void drawMyLocation(Canvas canvas, Projection projection) {
- if (myLocation == null) {
- return;
- }
- Point point = drawElement(canvas, projection, LocationUtils.getGeoPoint(myLocation),
- arrows[headingIndex], -(arrowWidth / 2), -(arrowHeight / 2));
- // Draw the error circle
- float radius = projection.metersToEquatorPixels(myLocation.getAccuracy());
- canvas.drawCircle(point.x, point.y, radius, errorCirclePaint);
- }
-
- /**
- * Draws an element.
- *
- * @param canvas the canvas
- * @param projection the projection
- * @param geoPoint the geo point
- * @param drawable the drawable
- * @param offsetX the x offset
- * @param offsetY the y offset
- * @return the point of the drawing.
- */
- private Point drawElement(Canvas canvas, Projection projection, GeoPoint geoPoint,
- Drawable drawable, int offsetX, int offsetY) {
- Point point = new Point();
- projection.toPixels(geoPoint, point);
- canvas.save();
- canvas.translate(point.x + offsetX, point.y + offsetY);
- drawable.draw(canvas);
- canvas.restore();
- return point;
- }
}
diff --git a/MyTracks/src/com/google/android/apps/mytracks/TrackDetailActivity.java b/MyTracks/src/com/google/android/apps/mytracks/TrackDetailActivity.java
index f44e00710..94f778baf 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/TrackDetailActivity.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/TrackDetailActivity.java
@@ -28,7 +28,7 @@ import com.google.android.apps.mytracks.fragments.DeleteOneTrackDialogFragment;
import com.google.android.apps.mytracks.fragments.DeleteOneTrackDialogFragment.DeleteOneTrackCaller;
import com.google.android.apps.mytracks.fragments.FrequencyDialogFragment;
import com.google.android.apps.mytracks.fragments.InstallEarthDialogFragment;
-import com.google.android.apps.mytracks.fragments.MapFragment;
+import com.google.android.apps.mytracks.fragments.MyTracksMapFragment;
import com.google.android.apps.mytracks.fragments.StatsFragment;
import com.google.android.apps.mytracks.io.file.SaveActivity;
import com.google.android.apps.mytracks.io.file.TrackWriterFactory.TrackFileFormat;
@@ -36,7 +36,6 @@ import com.google.android.apps.mytracks.io.sendtogoogle.SendRequest;
import com.google.android.apps.mytracks.services.TrackRecordingServiceConnection;
import com.google.android.apps.mytracks.settings.SettingsActivity;
import com.google.android.apps.mytracks.util.AnalyticsUtils;
-import com.google.android.apps.mytracks.util.ApiAdapterFactory;
import com.google.android.apps.mytracks.util.IntentUtils;
import com.google.android.apps.mytracks.util.PreferencesUtils;
import com.google.android.apps.mytracks.util.TrackRecordingServiceConnectionUtils;
@@ -63,7 +62,7 @@ import java.util.List;
/**
* An activity to show the track detail.
- *
+ *
* @author Leif Hendrik Wilden
* @author Rodrigo Damazio
*/
@@ -74,19 +73,18 @@ public class TrackDetailActivity extends AbstractMyTracksActivity implements Del
private static final String TAG = TrackDetailActivity.class.getSimpleName();
private static final String CURRENT_TAB_TAG_KEY = "current_tab_tag_key";
-
+
// The following are set in onCreate
private TrackRecordingServiceConnection trackRecordingServiceConnection;
private TrackDataHub trackDataHub;
- private View mapViewContainer;
private TabHost tabHost;
private TabManager tabManager;
private TrackController trackController;
-
+
// From intent
private long trackId;
private long markerId;
-
+
// Preferences
private long recordingTrackId;
private boolean recordingTrackPaused;
@@ -136,7 +134,7 @@ public class TrackDetailActivity extends AbstractMyTracksActivity implements Del
if (key != null) {
boolean isRecording = trackId == recordingTrackId;
updateMenuItems(isRecording, recordingTrackPaused);
- trackController.update(isRecording, recordingTrackPaused);
+ trackController.update(isRecording, recordingTrackPaused);
}
}
};
@@ -170,25 +168,6 @@ public class TrackDetailActivity extends AbstractMyTracksActivity implements Del
}
};
- /**
- * We are not displaying driving directions. Just an arbitrary track that is
- * not associated to any licensed mapping data. Therefore it should be okay to
- * return false here and still comply with the terms of service.
- */
- @Override
- protected boolean isRouteDisplayed() {
- return false;
- }
-
- /**
- * We are displaying a location. This needs to return true in order to comply
- * with the terms of service.
- */
- @Override
- protected boolean isLocationDisplayed() {
- return true;
- }
-
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -199,18 +178,16 @@ public class TrackDetailActivity extends AbstractMyTracksActivity implements Del
sharedPreferences.registerOnSharedPreferenceChangeListener(sharedPreferenceChangeListener);
sharedPreferenceChangeListener.onSharedPreferenceChanged(sharedPreferences, null);
- trackRecordingServiceConnection = new TrackRecordingServiceConnection(this, bindChangedCallback);
+ trackRecordingServiceConnection = new TrackRecordingServiceConnection(
+ this, bindChangedCallback);
trackDataHub = TrackDataHub.newInstance(this);
- mapViewContainer = getLayoutInflater().inflate(R.layout.map, null);
- ApiAdapterFactory.getApiAdapter().disableHardwareAccelerated(mapViewContainer);
-
tabHost = (TabHost) findViewById(android.R.id.tabhost);
tabHost.setup();
tabManager = new TabManager(this, tabHost, R.id.realtabcontent);
- TabSpec mapTabSpec = tabHost.newTabSpec(MapFragment.MAP_FRAGMENT_TAG).setIndicator(
+ TabSpec mapTabSpec = tabHost.newTabSpec(MyTracksMapFragment.MAP_FRAGMENT_TAG).setIndicator(
getString(R.string.track_detail_map_tab), getResources().getDrawable(R.drawable.tab_map));
- tabManager.addTab(mapTabSpec, MapFragment.class, null);
+ tabManager.addTab(mapTabSpec, MyTracksMapFragment.class, null);
TabSpec chartTabSpec = tabHost.newTabSpec(ChartFragment.CHART_FRAGMENT_TAG).setIndicator(
getString(R.string.track_detail_chart_tab),
getResources().getDrawable(R.drawable.tab_chart));
@@ -222,7 +199,8 @@ public class TrackDetailActivity extends AbstractMyTracksActivity implements Del
if (savedInstanceState != null) {
tabHost.setCurrentTabByTag(savedInstanceState.getString(CURRENT_TAB_TAG_KEY));
}
- trackController = new TrackController(this, trackRecordingServiceConnection, false, recordListener, stopListener);
+ trackController = new TrackController(
+ this, trackRecordingServiceConnection, false, recordListener, stopListener);
showMarker();
}
@@ -274,7 +252,7 @@ public class TrackDetailActivity extends AbstractMyTracksActivity implements Del
super.onDestroy();
trackRecordingServiceConnection.unbind();
}
-
+
@Override
protected void onHomeSelected() {
Intent intent = IntentUtils.newIntent(this, TrackListActivity.class);
@@ -427,13 +405,6 @@ public class TrackDetailActivity extends AbstractMyTracksActivity implements Del
return trackRecordingServiceConnection;
}
- /**
- * Gets the map view container.
- */
- public View getMapViewContainer() {
- return mapViewContainer;
- }
-
/**
* Gets the {@link TrackDataHub}.
*/
@@ -475,10 +446,10 @@ public class TrackDetailActivity extends AbstractMyTracksActivity implements Del
*/
private void showMarker() {
if (markerId != -1L) {
- MapFragment mapFragmet = (MapFragment) getSupportFragmentManager()
- .findFragmentByTag(MapFragment.MAP_FRAGMENT_TAG);
+ MyTracksMapFragment mapFragmet = (MyTracksMapFragment) getSupportFragmentManager()
+ .findFragmentByTag(MyTracksMapFragment.MAP_FRAGMENT_TAG);
if (mapFragmet != null) {
- tabHost.setCurrentTabByTag(MapFragment.MAP_FRAGMENT_TAG);
+ tabHost.setCurrentTabByTag(MyTracksMapFragment.MAP_FRAGMENT_TAG);
mapFragmet.showMarker(trackId, markerId);
} else {
Log.e(TAG, "MapFragment is null");
@@ -488,7 +459,7 @@ public class TrackDetailActivity extends AbstractMyTracksActivity implements Del
/**
* Updates the menu items.
- *
+ *
* @param isRecording true if recording
*/
private void updateMenuItems(boolean isRecording, boolean isPaused) {
@@ -516,8 +487,7 @@ public class TrackDetailActivity extends AbstractMyTracksActivity implements Del
String title;
if (isRecording) {
- title = getString(
- isPaused ? R.string.generic_paused : R.string.generic_recording);
+ title = getString(isPaused ? R.string.generic_paused : R.string.generic_recording);
} else {
Track track = MyTracksProviderUtils.Factory.get(this).getTrack(trackId);
title = track != null ? track.getName() : getString(R.string.my_tracks_app_name);
@@ -527,7 +497,7 @@ public class TrackDetailActivity extends AbstractMyTracksActivity implements Del
/**
* Starts the {@link SaveActivity} to save a track.
- *
+ *
* @param trackFileFormat the track file format
*/
private void startSaveActivity(TrackFileFormat trackFileFormat) {
diff --git a/MyTracks/src/com/google/android/apps/mytracks/fragments/MapFragment.java b/MyTracks/src/com/google/android/apps/mytracks/fragments/MapFragment.java
deleted file mode 100644
index ba236bccf..000000000
--- a/MyTracks/src/com/google/android/apps/mytracks/fragments/MapFragment.java
+++ /dev/null
@@ -1,594 +0,0 @@
-/*
- * Copyright 2008 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package com.google.android.apps.mytracks.fragments;
-
-import com.google.android.apps.mytracks.MapOverlay;
-import com.google.android.apps.mytracks.TrackDetailActivity;
-import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
-import com.google.android.apps.mytracks.content.MyTracksProviderUtils.Factory;
-import com.google.android.apps.mytracks.content.Track;
-import com.google.android.apps.mytracks.content.TrackDataHub;
-import com.google.android.apps.mytracks.content.TrackDataListener;
-import com.google.android.apps.mytracks.content.TrackDataType;
-import com.google.android.apps.mytracks.content.Waypoint;
-import com.google.android.apps.mytracks.stats.TripStatistics;
-import com.google.android.apps.mytracks.util.ApiAdapterFactory;
-import com.google.android.apps.mytracks.util.GeoRect;
-import com.google.android.apps.mytracks.util.GoogleLocationUtils;
-import com.google.android.apps.mytracks.util.LocationUtils;
-import com.google.android.maps.GeoPoint;
-import com.google.android.maps.MapController;
-import com.google.android.maps.MapView;
-import com.google.android.maps.Overlay;
-import com.google.android.maps.mytracks.R;
-
-import android.content.Intent;
-import android.location.Location;
-import android.os.Bundle;
-import android.provider.Settings;
-import android.support.v4.app.Fragment;
-import android.view.LayoutInflater;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ImageButton;
-import android.widget.TextView;
-import android.widget.Toast;
-
-import java.util.EnumSet;
-import java.util.List;
-
-/**
- * A fragment to display map to the user.
- *
- * @author Leif Hendrik Wilden
- * @author Rodrigo Damazio
- */
-public class MapFragment extends Fragment
- implements View.OnTouchListener, View.OnClickListener, TrackDataListener {
-
- public static final String MAP_FRAGMENT_TAG = "mapFragment";
-
- private static final String CURRENT_LOCATION_KEY = "current_location_key";
- private static final String KEEP_MY_LOCATION_VISIBLE_KEY = "keep_my_location_visible_key";
-
- private TrackDataHub trackDataHub;
-
- // True to keep my location visible.
- private boolean keepMyLocationVisible;
-
- // True to zoom to my location. Only apply when keepMyLocationVisible is true.
- private boolean zoomToMyLocation;
-
- // The track id of the marker to show.
- private long markerTrackId;
-
- // The marker id to show
- private long markerId;
-
- // The current selected track id. Set in onSelectedTrackChanged.
- private long currentSelectedTrackId;
-
- // The current location. Set in onCurrentLocationChanged.
- private Location currentLocation;
-
- // UI elements
- private View mapViewContainer;
- private MapView mapView;
- private MapOverlay mapOverlay;
- private ImageButton myLocationImageButton;
- private TextView messageTextView;
-
- @Override
- public void onCreate(Bundle bundle) {
- super.onCreate(bundle);
- setHasOptionsMenu(true);
- }
-
- @Override
- public View onCreateView(
- LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
- mapViewContainer = ((TrackDetailActivity) getActivity()).getMapViewContainer();
- mapView = (MapView) mapViewContainer.findViewById(R.id.map_view);
- mapOverlay = new MapOverlay(getActivity());
-
- List overlays = mapView.getOverlays();
- overlays.clear();
- overlays.add(mapOverlay);
-
- mapView.requestFocus();
- mapView.setOnTouchListener(this);
- mapView.setBuiltInZoomControls(true);
- myLocationImageButton = (ImageButton) mapViewContainer.findViewById(R.id.map_my_location);
- myLocationImageButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- showMyLocation();
- }
- });
- messageTextView = (TextView) mapViewContainer.findViewById(R.id.map_message);
-
- ApiAdapterFactory.getApiAdapter().invalidMenu(getActivity());
- return mapViewContainer;
- }
-
- @Override
- public void onActivityCreated(Bundle savedInstanceState) {
- super.onActivityCreated(savedInstanceState);
- if (savedInstanceState != null) {
- keepMyLocationVisible = savedInstanceState.getBoolean(KEEP_MY_LOCATION_VISIBLE_KEY, false);
- currentLocation = (Location) savedInstanceState.getParcelable(CURRENT_LOCATION_KEY);
- if (currentLocation != null) {
- updateCurrentLocation();
- }
- }
- }
-
- @Override
- public void onResume() {
- super.onResume();
- resumeTrackDataHub();
- }
-
- @Override
- public void onSaveInstanceState(Bundle outState) {
- super.onSaveInstanceState(outState);
- outState.putBoolean(KEEP_MY_LOCATION_VISIBLE_KEY, keepMyLocationVisible);
- if (currentLocation != null) {
- outState.putParcelable(CURRENT_LOCATION_KEY, currentLocation);
- }
- }
-
- @Override
- public void onPause() {
- super.onPause();
- pauseTrackDataHub();
- }
-
- @Override
- public void onDestroyView() {
- super.onDestroyView();
- ViewGroup parentViewGroup = (ViewGroup) mapViewContainer.getParent();
- if (parentViewGroup != null) {
- parentViewGroup.removeView(mapViewContainer);
- }
- }
-
- @Override
- public void onCreateOptionsMenu(Menu menu, MenuInflater menuInflator) {
- menuInflator.inflate(R.menu.map, menu);
- }
-
- @Override
- public void onPrepareOptionsMenu(Menu menu) {
- int titleId = R.string.menu_satellite_mode;
- if (mapView != null) {
- titleId = mapView.isSatellite() ? R.string.menu_map_mode : R.string.menu_satellite_mode;
- }
- menu.findItem(R.id.map_satellite_mode).setTitle(titleId);
- super.onPrepareOptionsMenu(menu);
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem menuItem) {
- if (mapView != null && menuItem.getItemId() == R.id.map_satellite_mode) {
- mapView.setSatellite(!mapView.isSatellite());
- return true;
- }
- return super.onOptionsItemSelected(menuItem);
- }
-
- /**
- * Shows my location.
- */
- private void showMyLocation() {
- updateTrackDataHub();
- keepMyLocationVisible = true;
- zoomToMyLocation = true;
- if (currentLocation != null) {
- updateCurrentLocation();
- }
- }
-
- /**
- * Shows the marker.
- *
- * @param id the marker id
- */
- private void showMarker(long id) {
- MyTracksProviderUtils MyTracksProviderUtils = Factory.get(getActivity());
- Waypoint waypoint = MyTracksProviderUtils.getWaypoint(id);
- if (waypoint != null && waypoint.getLocation() != null) {
- keepMyLocationVisible = false;
- GeoPoint center = new GeoPoint((int) (waypoint.getLocation().getLatitude() * 1E6),
- (int) (waypoint.getLocation().getLongitude() * 1E6));
- mapView.getController().setCenter(center);
- mapView.getController().setZoom(mapView.getMaxZoomLevel());
- mapView.invalidate();
- }
- }
-
- /**
- * Shows the marker.
- *
- * @param trackId the track id
- * @param id the marker id
- */
- public void showMarker(long trackId, long id) {
- /*
- * Synchronize to prevent race condition in changing markerTrackId and
- * markerId variables.
- */
- synchronized (this) {
- if (trackId == currentSelectedTrackId) {
- showMarker(id);
- markerTrackId = -1L;
- markerId = -1L;
- return;
- }
- markerTrackId = trackId;
- markerId = id;
- }
- }
-
- @Override
- public boolean onTouch(View view, MotionEvent event) {
- if (keepMyLocationVisible && event.getAction() == MotionEvent.ACTION_MOVE) {
- if (!isVisible(currentLocation)) {
- /*
- * Only set to false when no longer visible. Thus can keep showing the
- * current location with the next location update.
- */
- keepMyLocationVisible = false;
- }
- }
- return false;
- }
-
- @Override
- public void onClick(View v) {
- if (v == messageTextView) {
- Intent intent = GoogleLocationUtils.isAvailable(getActivity()) ? new Intent(
- GoogleLocationUtils.ACTION_GOOGLE_LOCATION_SETTINGS)
- : new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- startActivity(intent);
- }
- }
-
- @Override
- public void onLocationStateChanged(LocationState state) {
- if (isResumed()) {
- final String message;
- final boolean isGpsDisabled;
- if (!isSelectedTrackRecording()) {
- message = null;
- isGpsDisabled = false;
- } else {
- switch (state) {
- case DISABLED:
- String setting = getString(
- GoogleLocationUtils.isAvailable(getActivity()) ? R.string.gps_google_location_settings
- : R.string.gps_location_access);
- message = getString(R.string.gps_disabled, setting);
- isGpsDisabled = true;
- currentLocation = null;
- updateCurrentLocation();
- break;
- case NO_FIX:
- message = getString(R.string.gps_wait_for_signal);
- isGpsDisabled = false;
- break;
- case BAD_FIX:
- message = getString(R.string.gps_wait_for_better_signal);
- isGpsDisabled = false;
- break;
- case GOOD_FIX:
- message = null;
- isGpsDisabled = false;
- break;
- default:
- throw new IllegalArgumentException("Unexpected state: " + state);
- }
- }
- getActivity().runOnUiThread(new Runnable() {
- @Override
- public void run() {
- if (isResumed()) {
- if (message == null) {
- messageTextView.setVisibility(View.GONE);
- return;
- }
- messageTextView.setText(message);
- messageTextView.setVisibility(View.VISIBLE);
- if (isGpsDisabled) {
- Toast.makeText(getActivity(), R.string.gps_not_found, Toast.LENGTH_LONG).show();
-
- // Click to show the location source settings
- messageTextView.setOnClickListener(MapFragment.this);
- } else {
- messageTextView.setOnClickListener(null);
- }
- }
- }
- });
- }
- }
-
- @Override
- public void onLocationChanged(Location location) {
- if (isResumed()) {
- currentLocation = location;
- updateCurrentLocation();
- }
- }
-
- @Override
- public void onHeadingChanged(double heading) {
- if (isResumed()) {
- if (mapOverlay.setHeading((float) heading)) {
- mapView.postInvalidate();
- }
- }
- }
-
- @Override
- public void onSelectedTrackChanged(final Track track) {
- if (isResumed()) {
- getActivity().runOnUiThread(new Runnable() {
- @Override
- public void run() {
- if (isResumed()) {
- boolean hasTrack = track != null;
- mapOverlay.setTrackDrawingEnabled(hasTrack);
-
- if (hasTrack) {
- synchronized (this) {
- /*
- * Synchronize to prevent race condition in changing
- * markerTrackId and markerId variables.
- */
- currentSelectedTrackId = track.getId();
- updateMap(track);
- }
- mapOverlay.setShowEndMarker(!isSelectedTrackRecording());
- }
- mapView.invalidate();
- }
- }
- });
- }
- }
-
- @Override
- public void onTrackUpdated(Track track) {
- // We don't care.
- }
-
- @Override
- public void clearTrackPoints() {
- if (isResumed()) {
- mapOverlay.clearPoints();
- }
- }
-
- @Override
- public void onSampledInTrackPoint(Location location) {
- if (isResumed()) {
- mapOverlay.addLocation(location);
- }
- }
-
- @Override
- public void onSampledOutTrackPoint(Location location) {
- // We don't care.
- }
-
- @Override
- public void onSegmentSplit(Location location) {
- if (isResumed()) {
- mapOverlay.addSegmentSplit();
- }
- }
-
- @Override
- public void onNewTrackPointsDone() {
- if (isResumed()) {
- mapView.postInvalidate();
- }
- }
-
- @Override
- public void clearWaypoints() {
- if (isResumed()) {
- mapOverlay.clearWaypoints();
- }
- }
-
- @Override
- public void onNewWaypoint(Waypoint waypoint) {
- if (isResumed() && waypoint != null && LocationUtils.isValidLocation(waypoint.getLocation())) {
- // TODO: Optimize locking inside addWaypoint
- mapOverlay.addWaypoint(waypoint);
- }
- }
-
- @Override
- public void onNewWaypointsDone() {
- if (isResumed()) {
- mapView.postInvalidate();
- }
- }
-
- @Override
- public boolean onMetricUnitsChanged(boolean metric) {
- // We don't care.
- return false;
- }
-
- @Override
- public boolean onReportSpeedChanged(boolean reportSpeed) {
- // We don't care.
- return false;
- }
-
- @Override
- public boolean onMinRecordingDistanceChanged(int minRecordingDistance) {
- // We don't care.
- return false;
- }
-
- /**
- * Resumes the trackDataHub. Needs to be synchronized because trackDataHub can
- * be accessed by multiple threads.
- */
- private synchronized void resumeTrackDataHub() {
- trackDataHub = ((TrackDetailActivity) getActivity()).getTrackDataHub();
- trackDataHub.registerTrackDataListener(this, EnumSet.of(TrackDataType.SELECTED_TRACK,
- TrackDataType.WAYPOINTS_TABLE, TrackDataType.SAMPLED_IN_TRACK_POINTS_TABLE,
- TrackDataType.LOCATION, TrackDataType.HEADING));
- }
-
- /**
- * Pauses the trackDataHub. Needs to be synchronized because trackDataHub can
- * be accessed by multiple threads.
- */
- private synchronized void pauseTrackDataHub() {
- trackDataHub.unregisterTrackDataListener(this);
- trackDataHub = null;
- }
-
- /**
- * Updates the trackDataHub. Needs to be synchronized because trackDataHub can
- * be accessed by multiple threads.
- */
- private synchronized void updateTrackDataHub() {
- if (trackDataHub != null) {
- trackDataHub.forceUpdateLocation();
- }
- }
-
- /**
- * Returns true if the selected track is recording. Needs to be synchronized
- * because trackDataHub can be accessed by multiple threads.
- */
- private synchronized boolean isSelectedTrackRecording() {
- return trackDataHub != null && trackDataHub.isSelectedTrackRecording();
- }
-
- /**
- * Updates the map by either zooming to the requested marker or showing the
- * track.
- *
- * @param track the track
- */
- private void updateMap(Track track) {
- if (track.getId() == markerTrackId) {
- // Show the marker
- showMarker(markerId);
-
- markerTrackId = -1L;
- markerId = -1L;
- } else {
- // Show the track
- showTrack(track);
- }
- }
-
- /**
- * Returns true if the location is visible.
- *
- * @param location the location
- */
- private boolean isVisible(Location location) {
- if (location == null || mapView == null) {
- return false;
- }
- GeoPoint mapCenter = mapView.getMapCenter();
- int latitudeSpan = mapView.getLatitudeSpan();
- int longitudeSpan = mapView.getLongitudeSpan();
-
- /*
- * The bottom of the mapView is obscured by the zoom controls, subtract its
- * height from the visible area.
- */
- GeoPoint zoomControlBottom = mapView.getProjection().fromPixels(0, mapView.getHeight());
- GeoPoint zoomControlTop = mapView.getProjection().fromPixels(
- 0, mapView.getHeight() - mapView.getZoomButtonsController().getZoomControls().getHeight());
- int zoomControlMargin = Math.abs(
- zoomControlTop.getLatitudeE6() - zoomControlBottom.getLatitudeE6());
- GeoRect geoRect = new GeoRect(mapCenter, latitudeSpan, longitudeSpan);
- geoRect.top += zoomControlMargin;
-
- GeoPoint geoPoint = LocationUtils.getGeoPoint(location);
- return geoRect.contains(geoPoint);
- }
-
- /**
- * Updates the current location and centers it if necessary.
- */
- private void updateCurrentLocation() {
- if (mapOverlay == null || mapView == null) {
- return;
- }
-
- mapOverlay.setMyLocation(currentLocation);
- mapView.postInvalidate();
-
- if (currentLocation != null && keepMyLocationVisible && !isVisible(currentLocation)) {
- GeoPoint geoPoint = LocationUtils.getGeoPoint(currentLocation);
- MapController mapController = mapView.getController();
- mapController.animateTo(geoPoint);
- if (zoomToMyLocation) {
- // Only zoom in the first time we show the location.
- zoomToMyLocation = false;
- if (mapView.getZoomLevel() < mapView.getMaxZoomLevel()) {
- mapController.setZoom(mapView.getMaxZoomLevel());
- }
- }
- }
- }
-
- /**
- * Shows the track.
- *
- * @param track the track
- */
- private void showTrack(Track track) {
- if (mapView == null || track == null || track.getNumberOfPoints() < 2) {
- return;
- }
-
- TripStatistics tripStatistics = track.getTripStatistics();
- int bottom = tripStatistics.getBottom();
- int left = tripStatistics.getLeft();
- int latitudeSpanE6 = tripStatistics.getTop() - bottom;
- int longitudeSpanE6 = tripStatistics.getRight() - left;
- if (latitudeSpanE6 > 0 && latitudeSpanE6 < 180E6 && longitudeSpanE6 > 0
- && longitudeSpanE6 < 360E6) {
- keepMyLocationVisible = false;
- GeoPoint center = new GeoPoint(bottom + latitudeSpanE6 / 2, left + longitudeSpanE6 / 2);
- if (LocationUtils.isValidGeoPoint(center)) {
- mapView.getController().setCenter(center);
- mapView.getController().zoomToSpan(latitudeSpanE6, longitudeSpanE6);
- }
- }
- }
-}
diff --git a/MyTracks/src/com/google/android/apps/mytracks/fragments/MyTracksMapFragment.java b/MyTracks/src/com/google/android/apps/mytracks/fragments/MyTracksMapFragment.java
new file mode 100644
index 000000000..e682de56f
--- /dev/null
+++ b/MyTracks/src/com/google/android/apps/mytracks/fragments/MyTracksMapFragment.java
@@ -0,0 +1,667 @@
+/*
+ * Copyright 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.google.android.apps.mytracks.fragments;
+
+import com.google.android.apps.mytracks.MapOverlay;
+import com.google.android.apps.mytracks.MarkerDetailActivity;
+import com.google.android.apps.mytracks.TrackDetailActivity;
+import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
+import com.google.android.apps.mytracks.content.MyTracksProviderUtils.Factory;
+import com.google.android.apps.mytracks.content.Track;
+import com.google.android.apps.mytracks.content.TrackDataHub;
+import com.google.android.apps.mytracks.content.TrackDataListener;
+import com.google.android.apps.mytracks.content.TrackDataType;
+import com.google.android.apps.mytracks.content.Waypoint;
+import com.google.android.apps.mytracks.stats.TripStatistics;
+import com.google.android.apps.mytracks.util.ApiAdapterFactory;
+import com.google.android.apps.mytracks.util.GoogleLocationUtils;
+import com.google.android.apps.mytracks.util.IntentUtils;
+import com.google.android.apps.mytracks.util.LocationUtils;
+import com.google.android.gms.maps.CameraUpdate;
+import com.google.android.gms.maps.CameraUpdates;
+import com.google.android.gms.maps.GoogleMap;
+import com.google.android.gms.maps.LocationSource;
+import com.google.android.gms.maps.LocationSource.OnLocationChangedListener;
+import com.google.android.gms.maps.OnMapInitializeListener;
+import com.google.android.gms.maps.SupportMapFragment;
+import com.google.android.gms.maps.model.CameraPosition;
+import com.google.android.gms.maps.model.LatLng;
+import com.google.android.gms.maps.model.LatLngBounds;
+import com.google.android.gms.maps.model.Marker;
+import com.google.android.gms.maps.model.Model;
+import com.google.android.gms.maps.model.Polyline;
+import com.google.android.maps.mytracks.R;
+
+import android.content.Context;
+import android.content.Intent;
+import android.location.Location;
+import android.os.Bundle;
+import android.provider.Settings;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.widget.ImageButton;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import java.util.ArrayList;
+import java.util.EnumSet;
+
+/**
+ * A fragment to display map to the user.
+ *
+ * @author Leif Hendrik Wilden
+ * @author Rodrigo Damazio
+ */
+public class MyTracksMapFragment extends SupportMapFragment
+ implements OnMapInitializeListener, TrackDataListener {
+
+ public static final String MAP_FRAGMENT_TAG = "mapFragment";
+
+ private static final String CURRENT_LOCATION_KEY = "current_location_key";
+ private static final String
+ KEEP_CURRENT_LOCATION_VISIBLE_KEY = "keep_current_location_visible_key";
+ private static final String ZOOM_TO_CURRENT_LOCATION_KEY = "zoom_to_current_location_key";
+
+ private static final float DEFAULT_ZOOM_LEVEL = 18f;
+
+ // If current zoom level is above this, no need to zoom to DEFAULT_ZOOM_LEVEL
+ private static final float MIN_ALLOWED_ZOOM_LEVEL = 10f;
+
+ // Google's latitude and longitude
+ private static final double DEFAULT_LATITUDE = 37.423;
+ private static final double DEFAULT_LONGITUDE = -122.084;
+
+ private TrackDataHub trackDataHub;
+
+ // Current location
+ private Location currentLocation;
+
+ // True to keep the currentLocation visible
+ private boolean keepCurrentLocationVisible;
+
+ // True to zoom to currentLocation when it is available
+ private boolean zoomToCurrentLocation;
+
+ private OnLocationChangedListener onLocationChangedListener;
+
+ // For showing a marker
+ private long markerTrackId = -1L;
+ private long markerId = -1L;
+
+ // Current track
+ private Track currentTrack;
+
+ // Current paths
+ private ArrayList paths = new ArrayList();
+ boolean reloadPaths = true;
+
+ // UI elements
+ private GoogleMap googleMap;
+ private MapOverlay mapOverlay;
+ private ImageButton myLocationImageButton;
+ private TextView messageTextView;
+
+ @Override
+ public void onCreate(Bundle bundle) {
+ super.onCreate(bundle);
+ setHasOptionsMenu(true);
+ ApiAdapterFactory.getApiAdapter().invalidMenu(getActivity());
+ mapOverlay = new MapOverlay(getActivity());
+ setOnMapInitializeListener(this);
+ }
+
+ @Override
+ public View onCreateView(
+ LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ View view = super.onCreateView(inflater, container, savedInstanceState);
+ View layout = inflater.inflate(R.layout.map, container, false);
+ RelativeLayout mapContainer = (RelativeLayout) layout.findViewById(R.id.map_container);
+ mapContainer.addView(view, 0);
+
+ myLocationImageButton = (ImageButton) layout.findViewById(R.id.map_my_location);
+ myLocationImageButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ forceUpdateLocation();
+ keepCurrentLocationVisible = true;
+ zoomToCurrentLocation = true;
+ updateCurrentLocation();
+ }
+ });
+ messageTextView = (TextView) layout.findViewById(R.id.map_message);
+ return layout;
+ }
+
+ @Override
+ public void onMapInitialize(GoogleMap map) {
+ googleMap = map;
+ googleMap.setMyLocationEnabled(true);
+ googleMap.getUiSettings().setMyLocationButtonEnabled(false);
+ googleMap.setIndoorEnabled(true);
+ googleMap.setOnMarkerClickListener(new OnMarkerClickListener() {
+
+ @Override
+ public boolean onMarkerClick(Marker marker) {
+ if (isResumed()) {
+ String title = marker.getTitle();
+ if (title != null && title.length() > 0) {
+ long id = Long.valueOf(title);
+ Context context = getActivity();
+ Intent intent = IntentUtils.newIntent(context, MarkerDetailActivity.class)
+ .putExtra(MarkerDetailActivity.EXTRA_MARKER_ID, id);
+ context.startActivity(intent);
+ }
+ }
+ return true;
+ }
+ });
+ googleMap.setLocationSource(new LocationSource() {
+
+ @Override
+ public void activate(OnLocationChangedListener listener) {
+ onLocationChangedListener = listener;
+ }
+
+ @Override
+ public void deactivate() {
+ onLocationChangedListener = null;
+ }
+ });
+ googleMap.setOnCameraChangeListener(new OnCameraChangeListener() {
+
+ @Override
+ public void onCameraChange(CameraPosition cameraPosition) {
+ if (keepCurrentLocationVisible && currentLocation != null
+ && !isLocationVisible(currentLocation)) {
+ keepCurrentLocationVisible = false;
+ zoomToCurrentLocation = false;
+ }
+ }
+ });
+ LatLng latLng = getDefaultLatLng();
+ if (latLng != null) {
+ googleMap.moveCamera(CameraUpdates.newLatLngZoom(latLng, googleMap.getMinZoomLevel()));
+ }
+ if (isResumed()) {
+ resetTrackDataHub();
+ }
+ }
+
+ @Override
+ public void onActivityCreated(Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+ if (savedInstanceState != null) {
+ keepCurrentLocationVisible = savedInstanceState.getBoolean(
+ KEEP_CURRENT_LOCATION_VISIBLE_KEY, false);
+ zoomToCurrentLocation = savedInstanceState.getBoolean(ZOOM_TO_CURRENT_LOCATION_KEY, false);
+ currentLocation = (Location) savedInstanceState.getParcelable(CURRENT_LOCATION_KEY);
+ updateCurrentLocation();
+ }
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ resumeTrackDataHub();
+ }
+
+ @Override
+ public void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ if (currentLocation != null) {
+ outState.putParcelable(CURRENT_LOCATION_KEY, currentLocation);
+ }
+ outState.putBoolean(KEEP_CURRENT_LOCATION_VISIBLE_KEY, keepCurrentLocationVisible);
+ outState.putBoolean(ZOOM_TO_CURRENT_LOCATION_KEY, zoomToCurrentLocation);
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ pauseTrackDataHub();
+ }
+
+ /**
+ * Shows the marker on the map.
+ *
+ * @param trackId the track id
+ * @param id the marker id
+ */
+ public void showMarker(long trackId, long id) {
+ /*
+ * Synchronize to prevent race condition in changing markerTrackId and
+ * markerId variables.
+ */
+ synchronized (this) {
+ if (currentTrack != null && currentTrack.getId() == trackId) {
+ showMarker(id);
+ markerTrackId = -1L;
+ markerId = -1L;
+ return;
+ }
+ markerTrackId = trackId;
+ markerId = id;
+ }
+ }
+
+ @Override
+ public void onCreateOptionsMenu(Menu menu, MenuInflater menuInflator) {
+ menuInflator.inflate(R.menu.map, menu);
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem menuItem) {
+ int type = MAP_TYPE_NORMAL;
+ switch (menuItem.getItemId()) {
+ case R.id.menu_map:
+ type = MAP_TYPE_NORMAL;
+ break;
+ case R.id.menu_satellite:
+ type = MAP_TYPE_SATELLITE;
+ break;
+ case R.id.menu_terrain:
+ type = MAP_TYPE_TERRAIN;
+ break;
+ default:
+ return super.onOptionsItemSelected(menuItem);
+ }
+ if (googleMap != null) {
+ googleMap.setMapType(type);
+ }
+ return true;
+ }
+
+ @Override
+ public void onLocationStateChanged(final LocationState state) {
+ if (isResumed()) {
+ getActivity().runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ if (!isResumed() || googleMap == null) {
+ return;
+ }
+ boolean myLocationEnabled = true;
+ if (state == LocationState.DISABLED) {
+ currentLocation = null;
+ myLocationEnabled = false;
+ }
+ googleMap.setMyLocationEnabled(myLocationEnabled);
+
+ String message;
+ boolean isGpsDisabled;
+ if (!isSelectedTrackRecording()) {
+ message = null;
+ isGpsDisabled = false;
+ } else {
+ switch (state) {
+ case DISABLED:
+ String setting = getString(GoogleLocationUtils.isAvailable(getActivity())
+ ? R.string.gps_google_location_settings
+ : R.string.gps_location_access);
+ message = getString(R.string.gps_disabled, setting);
+ isGpsDisabled = true;
+ break;
+ case NO_FIX:
+ message = getString(R.string.gps_wait_for_signal);
+ isGpsDisabled = false;
+ break;
+ case BAD_FIX:
+ message = getString(R.string.gps_wait_for_better_signal);
+ isGpsDisabled = false;
+ break;
+ case GOOD_FIX:
+ message = null;
+ isGpsDisabled = false;
+ break;
+ default:
+ throw new IllegalArgumentException("Unexpected state: " + state);
+ }
+ }
+ if (message == null) {
+ messageTextView.setVisibility(View.GONE);
+ return;
+ }
+ messageTextView.setText(message);
+ messageTextView.setVisibility(View.VISIBLE);
+ if (isGpsDisabled) {
+ Toast.makeText(getActivity(), R.string.gps_not_found, Toast.LENGTH_LONG).show();
+
+ // Click to show the location source settings
+ messageTextView.setOnClickListener(new OnClickListener() {
+
+ @Override
+ public void onClick(View v) {
+ Intent intent = GoogleLocationUtils.isAvailable(getActivity()) ? new Intent(
+ GoogleLocationUtils.ACTION_GOOGLE_LOCATION_SETTINGS)
+ : new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ startActivity(intent);
+ }
+ });
+ } else {
+ messageTextView.setOnClickListener(null);
+ }
+ }
+ });
+ }
+ }
+
+ @Override
+ public void onLocationChanged(final Location location) {
+ if (isResumed()) {
+ if (isSelectedTrackRecording() && currentLocation == null && location != null) {
+ zoomToCurrentLocation = true;
+ }
+ currentLocation = location;
+ updateCurrentLocation();
+ }
+ }
+
+ @Override
+ public void onHeadingChanged(double heading) {
+ // We don't care.
+ }
+
+ @Override
+ public void onSelectedTrackChanged(final Track track) {
+ if (isResumed()) {
+ currentTrack = track;
+ boolean hasTrack = track != null;
+ if (hasTrack) {
+ mapOverlay.setShowEndMarker(!isSelectedTrackRecording());
+ synchronized (this) {
+ /*
+ * Synchronize to prevent race condition in changing markerTrackId and
+ * markerId variables.
+ */
+ if (track.getId() == markerTrackId) {
+ // Show the marker
+ showMarker(markerId);
+
+ markerTrackId = -1L;
+ markerId = -1L;
+ } else {
+ // Show the track
+ showTrack();
+ }
+ }
+ }
+ }
+ }
+
+ @Override
+ public void onTrackUpdated(Track track) {
+ // We don't care.
+ }
+
+ @Override
+ public void clearTrackPoints() {
+ if (isResumed()) {
+ mapOverlay.clearPoints();
+ reloadPaths = true;
+ }
+ }
+
+ @Override
+ public void onSampledInTrackPoint(final Location location) {
+ if (isResumed()) {
+ mapOverlay.addLocation(location);
+ }
+ }
+
+ @Override
+ public void onSampledOutTrackPoint(Location location) {
+ // We don't care.
+ }
+
+ @Override
+ public void onSegmentSplit(Location location) {
+ if (isResumed()) {
+ mapOverlay.addSegmentSplit();
+ }
+ }
+
+ @Override
+ public void onNewTrackPointsDone() {
+ if (isResumed()) {
+ getActivity().runOnUiThread(new Runnable() {
+ public void run() {
+ if (isResumed() && googleMap != null) {
+ mapOverlay.update(googleMap, paths, reloadPaths);
+ reloadPaths = false;
+ }
+ }
+ });
+ }
+ }
+
+ @Override
+ public void clearWaypoints() {
+ if (isResumed()) {
+ mapOverlay.clearWaypoints();
+ }
+ }
+
+ @Override
+ public void onNewWaypoint(Waypoint waypoint) {
+ if (isResumed() && waypoint != null && LocationUtils.isValidLocation(waypoint.getLocation())) {
+ mapOverlay.addWaypoint(waypoint);
+ }
+ }
+
+ @Override
+ public void onNewWaypointsDone() {
+ if (isResumed()) {
+ getActivity().runOnUiThread(new Runnable() {
+ public void run() {
+ if (isResumed() && googleMap != null) {
+ mapOverlay.update(googleMap, paths, true);
+ }
+ }
+ });
+ }
+ }
+
+ @Override
+ public boolean onMetricUnitsChanged(boolean metric) {
+ // We don't care.
+ return false;
+ }
+
+ @Override
+ public boolean onReportSpeedChanged(boolean reportSpeed) {
+ // We don't care.
+ return false;
+ }
+
+ @Override
+ public boolean onMinRecordingDistanceChanged(int minRecordingDistance) {
+ // We don't care.
+ return false;
+ }
+
+ /**
+ * Resumes the trackDataHub. Needs to be synchronized because the trackDataHub
+ * can be accessed by multiple threads.
+ */
+ private synchronized void resumeTrackDataHub() {
+ trackDataHub = ((TrackDetailActivity) getActivity()).getTrackDataHub();
+ trackDataHub.registerTrackDataListener(this, EnumSet.of(TrackDataType.SELECTED_TRACK,
+ TrackDataType.WAYPOINTS_TABLE, TrackDataType.SAMPLED_IN_TRACK_POINTS_TABLE,
+ TrackDataType.LOCATION, TrackDataType.HEADING));
+ }
+
+ /**
+ * Pauses the trackDataHub. Needs to be synchronized because the trackDataHub
+ * can be accessed by multiple threads.
+ */
+ private synchronized void pauseTrackDataHub() {
+ if (trackDataHub != null) {
+ trackDataHub.unregisterTrackDataListener(this);
+ }
+ trackDataHub = null;
+ }
+
+ /**
+ * Resets the trackDataHub. Needs to be synchronized because the trackDataHub
+ * can be accessed by multiple threads.
+ */
+ private synchronized void resetTrackDataHub() {
+ pauseTrackDataHub();
+ resumeTrackDataHub();
+ }
+
+ /**
+ * Returns true if the selected track is recording. Needs to be synchronized
+ * because the trackDataHub can be accessed by multiple threads.
+ */
+ private synchronized boolean isSelectedTrackRecording() {
+ return trackDataHub != null && trackDataHub.isSelectedTrackRecording();
+ }
+
+ /**
+ * Forces update location. Needs to be synchronized because the trackDataHub
+ * can be accessed by multiple threads.
+ */
+ private synchronized void forceUpdateLocation() {
+ if (trackDataHub != null) {
+ trackDataHub.forceUpdateLocation();
+ }
+ }
+
+ /**
+ * Updates the current location and zoom to it if necessary.
+ */
+ private void updateCurrentLocation() {
+ getActivity().runOnUiThread(new Runnable() {
+ public void run() {
+ if (!isResumed() || googleMap == null || onLocationChangedListener == null
+ || currentLocation == null) {
+ return;
+ }
+ onLocationChangedListener.onLocationChanged(currentLocation);
+ if (zoomToCurrentLocation
+ || (keepCurrentLocationVisible && !isLocationVisible(currentLocation))) {
+ LatLng latLng = new LatLng(currentLocation.getLatitude(), currentLocation.getLongitude());
+ googleMap.animateCamera(CameraUpdates.newLatLngZoom(latLng, getDefaultZoomLevel()));
+ zoomToCurrentLocation = false;
+ }
+ };
+ });
+ }
+
+ /**
+ * Sets the camera over a track.
+ */
+ private void showTrack() {
+ getActivity().runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ if (!isResumed() || googleMap == null || currentTrack == null
+ || currentTrack.getNumberOfPoints() < 2) {
+ return;
+ }
+
+ TripStatistics tripStatistics = currentTrack.getTripStatistics();
+ int latitudeSpanE6 = tripStatistics.getTop() - tripStatistics.getBottom();
+ int longitudeSpanE6 = tripStatistics.getRight() - tripStatistics.getLeft();
+ if (latitudeSpanE6 > 0 && latitudeSpanE6 < 180E6 && longitudeSpanE6 > 0
+ && longitudeSpanE6 < 360E6) {
+ LatLng southWest = new LatLng(
+ tripStatistics.getBottomDegrees(), tripStatistics.getLeftDegrees());
+ LatLng northEast = new LatLng(
+ tripStatistics.getTopDegrees(), tripStatistics.getRightDegrees());
+ LatLngBounds bounds = Model.newLatLngBounds(southWest, northEast);
+ CameraUpdate cameraUpdate = CameraUpdates.newLatLngBounds(bounds, 32);
+ googleMap.moveCamera(cameraUpdate);
+ }
+ }
+ });
+ }
+
+ /**
+ * Sets the camera over a marker.
+ *
+ * @param id the marker id
+ */
+ private void showMarker(final long id) {
+ getActivity().runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ if (!isResumed() || googleMap == null) {
+ return;
+ }
+ MyTracksProviderUtils MyTracksProviderUtils = Factory.get(getActivity());
+ Waypoint waypoint = MyTracksProviderUtils.getWaypoint(id);
+ if (waypoint != null && waypoint.getLocation() != null) {
+ Location location = waypoint.getLocation();
+ LatLng latLng = new LatLng(location.getLatitude(), location.getLongitude());
+ keepCurrentLocationVisible = false;
+ zoomToCurrentLocation = false;
+ CameraUpdate cameraUpdate = CameraUpdates.newLatLngZoom(latLng, getDefaultZoomLevel());
+ googleMap.moveCamera(cameraUpdate);
+ }
+ }
+ });
+ }
+
+ /**
+ * Gets the default LatLng.
+ */
+ private LatLng getDefaultLatLng() {
+ MyTracksProviderUtils myTracksProviderUtils = MyTracksProviderUtils.Factory.get(getActivity());
+ Location location = myTracksProviderUtils.getLastValidTrackPoint();
+ if (location != null) {
+ return new LatLng(location.getLatitude(), location.getLongitude());
+ } else {
+ return new LatLng(DEFAULT_LATITUDE, DEFAULT_LONGITUDE);
+ }
+ }
+
+ /**
+ * Gets the default zoom level. Needs to run on the UI thread.
+ */
+ private float getDefaultZoomLevel() {
+ if (googleMap == null) {
+ return DEFAULT_ZOOM_LEVEL;
+ }
+ float zoom = googleMap.getCameraPosition().getZoom();
+ if (zoom <= MIN_ALLOWED_ZOOM_LEVEL) {
+ return DEFAULT_ZOOM_LEVEL;
+ }
+ return zoom;
+ }
+
+ /**
+ * Returns true if the location is visible. Needs to run on the UI thread.
+ *
+ * @param location the location
+ */
+ private boolean isLocationVisible(Location location) {
+ if (location == null || googleMap == null) {
+ return false;
+ }
+ LatLng latLng = new LatLng(location.getLatitude(), location.getLongitude());
+ return googleMap.getProjection().getVisibleRegion().getLatLngBounds().contains(latLng);
+ }
+}
\ 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
deleted file mode 100644
index 9609d1fe6..000000000
--- a/MyTracks/src/com/google/android/apps/mytracks/maps/DynamicSpeedTrackPathPainter.java
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * 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 com.google.common.annotations.VisibleForTesting;
-
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-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 TrackPathDescriptor trackPathDescriptor;
- private final Paint slowPaint;
- private final Paint mediumPaint;
- private final Paint fastPaint;
- private final List coloredPaths;
-
- public DynamicSpeedTrackPathPainter(Context context, TrackPathDescriptor trackPathDescriptor) {
- this.trackPathDescriptor = trackPathDescriptor;
- slowPaint = TrackPathUtils.getPaint(context, R.color.slow_path);
- mediumPaint = TrackPathUtils.getPaint(context, R.color.normal_path);
- fastPaint = TrackPathUtils.getPaint(context, R.color.fast_path);
- coloredPaths = new ArrayList();
- }
-
- @Override
- public boolean hasPath() {
- return !coloredPaths.isEmpty();
- }
-
- @Override
- public boolean updateState() {
- return trackPathDescriptor.updateState();
- }
-
- @Override
- public void updatePath(
- Projection projection, Rect viewRect, int startIndex, List 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();
-
- 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;
- continue;
- }
-
- GeoPoint geoPoint = cachedLocation.getGeoPoint();
- // Check if this breaks the existing segment.
- boolean pointVisible = viewRect.contains(geoPoint.getLongitudeE6(), geoPoint.getLatitudeE6());
- if (!pointVisible && !lastPointVisible) {
- // This point and the last point are both outside visible area.
- newSegment = true;
- }
- lastPointVisible = pointVisible;
-
- // Either update point or draw a line from the last point
- if (newSegment) {
- projection.toPixels(geoPoint, point);
- newSegment = false;
- } else {
- ColoredPath coloredPath;
- if (cachedLocation.getSpeed() <= slowSpeed) {
- coloredPath = new ColoredPath(slowPaint);
- } else if (cachedLocation.getSpeed() <= normalSpeed) {
- coloredPath = new ColoredPath(mediumPaint);
- } else {
- coloredPath = new ColoredPath(fastPaint);
- }
- coloredPath.getPath().moveTo(point.x, point.y);
- projection.toPixels(geoPoint, point);
- coloredPath.getPath().lineTo(point.x, point.y);
- coloredPaths.add(coloredPath);
- }
- }
- }
-
- @Override
- public void clearPath() {
- coloredPaths.clear();
- }
-
- @Override
- public void drawPath(Canvas canvas) {
- for (int i = 0; i < coloredPaths.size(); i++) {
- ColoredPath coloredPath = coloredPaths.get(i);
- canvas.drawPath(coloredPath.getPath(), coloredPath.getPathPaint());
- }
- }
-
- /**
- * Gets the colored paths.
- */
- @VisibleForTesting
- List getColoredPaths() {
- return coloredPaths;
- }
-}
\ No newline at end of file
diff --git a/MyTracks/src/com/google/android/apps/mytracks/maps/MultiColorTrackPath.java b/MyTracks/src/com/google/android/apps/mytracks/maps/MultiColorTrackPath.java
new file mode 100644
index 000000000..a16785398
--- /dev/null
+++ b/MyTracks/src/com/google/android/apps/mytracks/maps/MultiColorTrackPath.java
@@ -0,0 +1,114 @@
+/*
+ * 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.gms.maps.GoogleMap;
+import com.google.android.gms.maps.model.LatLng;
+import com.google.android.gms.maps.model.Polyline;
+import com.google.android.maps.mytracks.R;
+
+import android.content.Context;
+
+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 MultiColorTrackPath implements TrackPath {
+ private final TrackPathDescriptor trackPathDescriptor;
+ private final int slowColor;
+ private final int normalColor;
+ private final int fastColor;
+
+ public MultiColorTrackPath(Context context, TrackPathDescriptor trackPathDescriptor) {
+ this.trackPathDescriptor = trackPathDescriptor;
+ slowColor = context.getResources().getColor(R.color.slow_path);
+ normalColor = context.getResources().getColor(R.color.normal_path);
+ fastColor = context.getResources().getColor(R.color.fast_path);
+ }
+
+ @Override
+ public boolean updateState() {
+ return trackPathDescriptor.updateState();
+ }
+
+ @Override
+ public void updatePath(GoogleMap googleMap, ArrayList paths, int startIndex,
+ List locations) {
+ if (googleMap == null) {
+ return;
+ }
+ if (startIndex >= locations.size()) {
+ return;
+ }
+
+ boolean newSegment = startIndex == 0 || !locations.get(startIndex - 1).isValid();
+ LatLng lastLatLng = startIndex != 0 ? locations.get(startIndex -1).getLatLng() : null;
+
+ ArrayList lastSegmentPoints = new ArrayList();
+ int lastSegmentColor = paths.size() != 0 ? paths.get(paths.size() - 1).getColor() : slowColor;
+ boolean useLastPolyline = true;
+
+ for (int i = startIndex; i < locations.size(); ++i) {
+ CachedLocation cachedLocation = locations.get(i);
+
+ // If not valid, start a new segment
+ if (!cachedLocation.isValid()) {
+ newSegment = true;
+ lastLatLng = null;
+ continue;
+ }
+ LatLng latLng = cachedLocation.getLatLng();
+ int color = getColor(cachedLocation.getSpeed());
+
+ // Either update point or draw a line from the last point
+ if (newSegment) {
+ TrackPathUtils.addPath(googleMap, paths, lastSegmentPoints, lastSegmentColor, useLastPolyline);
+ useLastPolyline = false;
+ lastSegmentColor = color;
+ newSegment = false;
+ }
+ if (lastSegmentColor == color) {
+ lastSegmentPoints.add(latLng);
+ } else {
+ TrackPathUtils.addPath(googleMap, paths, lastSegmentPoints, lastSegmentColor, useLastPolyline);
+ useLastPolyline = false;
+ if (lastLatLng != null) {
+ lastSegmentPoints.add(lastLatLng);
+ }
+ lastSegmentPoints.add(latLng);
+ lastSegmentColor = color;
+ }
+ lastLatLng = latLng;
+ }
+ TrackPathUtils.addPath(googleMap, paths, lastSegmentPoints, lastSegmentColor, useLastPolyline);
+ }
+
+ private int getColor(int speed) {
+ if (speed <= trackPathDescriptor.getSlowSpeed()) {
+ return slowColor;
+ } else if (speed <= trackPathDescriptor.getNormalSpeed()) {
+ return normalColor;
+ } else {
+ return fastColor;
+ }
+ }
+}
\ No newline at end of file
diff --git a/MyTracks/src/com/google/android/apps/mytracks/maps/SingleColorTrackPath.java b/MyTracks/src/com/google/android/apps/mytracks/maps/SingleColorTrackPath.java
new file mode 100644
index 000000000..caf03b801
--- /dev/null
+++ b/MyTracks/src/com/google/android/apps/mytracks/maps/SingleColorTrackPath.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2012 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.gms.maps.GoogleMap;
+import com.google.android.gms.maps.model.LatLng;
+import com.google.android.gms.maps.model.Polyline;
+import com.google.android.maps.mytracks.R;
+
+import android.content.Context;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A single color track path.
+ *
+ * @author Jimmy Shih
+ */
+public class SingleColorTrackPath implements TrackPath {
+
+ final int color;
+
+ public SingleColorTrackPath(Context context) {
+ color = context.getResources().getColor(R.color.fast_path);
+ }
+
+ @Override
+ public boolean updateState() {
+ return false;
+ }
+
+ @Override
+ public void updatePath(GoogleMap googleMap, ArrayList paths, int startIndex,
+ List locations) {
+ if (googleMap == null) {
+ return;
+ }
+ if (startIndex >= locations.size()) {
+ return;
+ }
+
+ boolean newSegment = startIndex == 0 || !locations.get(startIndex - 1).isValid();
+ ArrayList lastSegmentPoints = new ArrayList();
+ boolean useLastPolyline = true;
+ for (int i = startIndex; i < locations.size(); i++) {
+ CachedLocation cachedLocation = locations.get(i);
+
+ // If not valid, start a new segment
+ if (!cachedLocation.isValid()) {
+ newSegment = true;
+ continue;
+ }
+ LatLng latLng = cachedLocation.getLatLng();
+ if (newSegment) {
+ TrackPathUtils.addPath(googleMap, paths, lastSegmentPoints, color, useLastPolyline);
+ useLastPolyline = false;
+ newSegment = false;
+ }
+ lastSegmentPoints.add(latLng);
+ }
+ TrackPathUtils.addPath(googleMap, paths, lastSegmentPoints, color, useLastPolyline);
+ }
+}
\ 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
deleted file mode 100644
index d29f86edf..000000000
--- a/MyTracks/src/com/google/android/apps/mytracks/maps/SingleColorTrackPathPainter.java
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * 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 com.google.common.annotations.VisibleForTesting;
-
-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 = TrackPathUtils.getPaint(context, R.color.red);
- }
-
- @Override
- public boolean hasPath() {
- return path != null;
- }
-
- @Override
- public boolean updateState() {
- return false;
- }
-
- @Override
- public void updatePath(
- Projection projection, Rect viewRect, int startIndex, List 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) {
- canvas.drawPath(path, selectedTrackPaint);
- }
- }
-
- /**
- * Updates the path.
- *
- * @param projection the projection
- * @param viewRect the view rectangle
- * @param startIndex the start index
- * @param points the points
- * @param pathToUpdate the path to update
- */
- @VisibleForTesting
- void updatePath(Projection projection, Rect viewRect, int startIndex, List points,
- Path pathToUpdate) {
- pathToUpdate.incReserve(points.size() - startIndex);
-
- boolean hasLastPoint = startIndex != 0 && points.get(startIndex - 1).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;
- continue;
- }
-
- GeoPoint geoPoint = cachedLocation.getGeoPoint();
- // Check if this breaks the existing segment.
- boolean pointVisible = viewRect.contains(geoPoint.getLongitudeE6(), geoPoint.getLatitudeE6());
- if (!pointVisible && !lastPointVisible) {
- // This point and the last point are both outside visible area.
- newSegment = true;
- }
- lastPointVisible = pointVisible;
-
- // Either update point or draw a line from the last point
- projection.toPixels(geoPoint, point);
- if (newSegment) {
- pathToUpdate.moveTo(point.x, point.y);
- newSegment = false;
- } else {
- pathToUpdate.lineTo(point.x, point.y);
- }
- }
- }
-
- /**
- * Creates a new path.
- */
- @VisibleForTesting
- protected Path newPath() {
- return new Path();
- }
-
- /**
- * Gets the path.
- */
- @VisibleForTesting
- public Path getPath() {
- return path;
- }
-
-}
\ 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/TrackPath.java
similarity index 50%
rename from MyTracks/src/com/google/android/apps/mytracks/maps/TrackPathPainter.java
rename to MyTracks/src/com/google/android/apps/mytracks/maps/TrackPath.java
index 2f6b31fde..050a1f705 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/maps/TrackPathPainter.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/maps/TrackPath.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2011 Google Inc.
+ * Copyright 2012 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
@@ -17,50 +17,27 @@
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.Rect;
+import com.google.android.gms.maps.GoogleMap;
+import com.google.android.gms.maps.model.Polyline;
+import java.util.ArrayList;
import java.util.List;
/**
- * An interface for classes which paint the track path.
+ * A track path.
*
- * @author Vangelis S.
+ * @author Jimmy Shih
*/
-public interface TrackPathPainter {
+public interface TrackPath {
- /**
- * Returns true if has path.
- */
- public boolean hasPath();
-
- /**
- * Updates state. Returns true if the state is updated.
- */
public boolean updateState();
/**
- * Updates the path. Creates a new path if necessary
+ * Updates the path.
*
- * @param projection the projection
- * @param viewRect the view rectangle
* @param startIndex the start index
* @param points the points
*/
- public void updatePath(
- Projection projection, Rect viewRect, int startIndex, List points);
-
- /**
- * Clears the path.
- */
- public void clearPath();
-
- /**
- * Draws the path.
- *
- * @param canvas the canvas
- */
- public void drawPath(Canvas canvas);
+ public void updatePath(GoogleMap googleMap, ArrayList paths, int startIndex,
+ List points);
}
diff --git a/MyTracks/src/com/google/android/apps/mytracks/maps/TrackPathPainterFactory.java b/MyTracks/src/com/google/android/apps/mytracks/maps/TrackPathFactory.java
similarity index 65%
rename from MyTracks/src/com/google/android/apps/mytracks/maps/TrackPathPainterFactory.java
rename to MyTracks/src/com/google/android/apps/mytracks/maps/TrackPathFactory.java
index 460d4b280..15a16a092 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/maps/TrackPathPainterFactory.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/maps/TrackPathFactory.java
@@ -16,42 +16,37 @@
package com.google.android.apps.mytracks.maps;
-import static com.google.android.apps.mytracks.Constants.TAG;
-
import com.google.android.apps.mytracks.util.PreferencesUtils;
import com.google.android.maps.mytracks.R;
import android.content.Context;
-import android.util.Log;
/**
- * A factory for {@link TrackPathPainter}.
+ * A factory for {@link TrackPath}.
*
* @author Vangelis S.
*/
-public class TrackPathPainterFactory {
+public class TrackPathFactory {
- private TrackPathPainterFactory() {}
+ private TrackPathFactory() {}
/**
- * Get a new {@link TrackPathPainter}.
+ * Get a new {@link TrackPath}.
*
* @param context the context
*/
- public static TrackPathPainter getTrackPathPainter(Context context) {
+ public static TrackPath getTrackPath(Context context) {
String trackColorMode = PreferencesUtils.getString(
context, R.string.track_color_mode_key, PreferencesUtils.TRACK_COLOR_MODE_DEFAULT);
- Log.i(TAG, "Creating track path painter of type: " + trackColorMode);
if (context.getString(R.string.settings_map_track_color_mode_dynamic_value)
.equals(trackColorMode)) {
- return new DynamicSpeedTrackPathPainter(context, new DynamicSpeedTrackPathDescriptor(
- context));
+ return new MultiColorTrackPath(context, new DynamicSpeedTrackPathDescriptor(context));
} else if (context.getString(R.string.settings_map_track_color_mode_fixed_value)
.equals(trackColorMode)) {
- return new DynamicSpeedTrackPathPainter(context, new FixedSpeedTrackPathDescriptor(context));
+ return new MultiColorTrackPath(context, new FixedSpeedTrackPathDescriptor(context));
} else {
- return new SingleColorTrackPathPainter(context);
+ return new SingleColorTrackPath(context);
}
}
}
\ No newline at end of file
diff --git a/MyTracks/src/com/google/android/apps/mytracks/maps/TrackPathUtils.java b/MyTracks/src/com/google/android/apps/mytracks/maps/TrackPathUtils.java
index a9cb03cf0..1818a2262 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/maps/TrackPathUtils.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/maps/TrackPathUtils.java
@@ -16,8 +16,12 @@
package com.google.android.apps.mytracks.maps;
-import android.content.Context;
-import android.graphics.Paint;
+import com.google.android.gms.maps.GoogleMap;
+import com.google.android.gms.maps.model.LatLng;
+import com.google.android.gms.maps.model.Model;
+import com.google.android.gms.maps.model.Polyline;
+
+import java.util.ArrayList;
/**
* Various utility functions for track path painting.
@@ -29,17 +33,32 @@ public class TrackPathUtils {
private TrackPathUtils() {}
/**
- * Gets a paint.
+ * Add a path.
*
- * @param context the context
- * @param colorId the color id
+ * @param googleMap the google map
+ * @param paths the existing paths
+ * @param points the path points
+ * @param color the path color
+ * @param append true to append to the last path
*/
- public static Paint getPaint(Context context, int colorId) {
- Paint paint = new Paint();
- paint.setColor(context.getResources().getColor(colorId));
- paint.setStrokeWidth(3);
- paint.setStyle(Paint.Style.STROKE);
- paint.setAntiAlias(true);
- return paint;
+ @SuppressWarnings("unchecked")
+ public static void addPath(GoogleMap googleMap, ArrayList paths,
+ ArrayList points, int color, boolean append) {
+ if (points.size() == 0) {
+ return;
+ }
+ if (append && paths.size() != 0) {
+ Polyline lastPolyline = paths.get(paths.size() - 1);
+ ArrayList pathPoints = new ArrayList();
+ pathPoints.addAll(lastPolyline.getPoints());
+ pathPoints.addAll(points);
+ lastPolyline.setPoints(pathPoints);
+ } else {
+ Polyline.Options options = Model.newPolylineOptions()
+ .addAll(points).width(5).color(color);
+ Polyline polyline = googleMap.addPolyline(options);
+ paths.add(polyline);
+ }
+ points.clear();
}
}
\ No newline at end of file
diff --git a/MyTracksLib/.classpath b/MyTracksLib/.classpath
index 0ca188f97..d3bb07b44 100644
--- a/MyTracksLib/.classpath
+++ b/MyTracksLib/.classpath
@@ -1,8 +1,8 @@
+
-
diff --git a/MyTracksLib/src/com/google/android/apps/mytracks/content/MyTracksProviderUtils.java b/MyTracksLib/src/com/google/android/apps/mytracks/content/MyTracksProviderUtils.java
index 76eb8b6ae..538170768 100644
--- a/MyTracksLib/src/com/google/android/apps/mytracks/content/MyTracksProviderUtils.java
+++ b/MyTracksLib/src/com/google/android/apps/mytracks/content/MyTracksProviderUtils.java
@@ -232,6 +232,11 @@ public interface MyTracksProviderUtils {
*/
public Location getLastValidTrackPoint(long trackId);
+ /**
+ * Gets the last valid location recorded. Returns null if it doesn't exist.
+ */
+ public Location getLastValidTrackPoint();
+
/**
* Creates a location cursor. The caller owns the returned cursor and is
* responsible for closing it.
diff --git a/MyTracksLib/src/com/google/android/apps/mytracks/content/MyTracksProviderUtilsImpl.java b/MyTracksLib/src/com/google/android/apps/mytracks/content/MyTracksProviderUtilsImpl.java
index 30c63939c..6f45d3931 100644
--- a/MyTracksLib/src/com/google/android/apps/mytracks/content/MyTracksProviderUtilsImpl.java
+++ b/MyTracksLib/src/com/google/android/apps/mytracks/content/MyTracksProviderUtilsImpl.java
@@ -40,6 +40,8 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
private static final String TAG = MyTracksProviderUtilsImpl.class.getSimpleName();
+ private static final int MAX_LATITUDE = 90000000;
+
private final ContentResolver contentResolver;
private int defaultCursorBatchSize = 2000;
@@ -74,7 +76,7 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
int mapIdIndex = cursor.getColumnIndexOrThrow(TracksColumns.MAPID);
int tableIdIndex = cursor.getColumnIndexOrThrow(TracksColumns.TABLEID);
int iconIndex = cursor.getColumnIndexOrThrow(TracksColumns.ICON);
-
+
Track track = new Track();
TripStatistics tripStatistics = track.getTripStatistics();
if (!cursor.isNull(idIndex)) {
@@ -155,7 +157,7 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
public void deleteAllTracks() {
contentResolver.delete(TrackPointsColumns.CONTENT_URI, null, null);
contentResolver.delete(WaypointsColumns.CONTENT_URI, null, null);
- // Delete tracks last since it triggers a database vaccum call
+ // Delete tracks last since it triggers a database vaccum call
contentResolver.delete(TracksColumns.CONTENT_URI, null, null);
}
@@ -164,15 +166,15 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
Track track = getTrack(trackId);
if (track != null) {
String where = TrackPointsColumns._ID + ">=? AND " + TrackPointsColumns._ID + "<=?";
- String[] selectionArgs = new String[] { Long.toString(track.getStartId()), Long.toString(
- track.getStopId()) };
+ String[] selectionArgs = new String[] {
+ Long.toString(track.getStartId()), Long.toString(track.getStopId()) };
contentResolver.delete(TrackPointsColumns.CONTENT_URI, where, selectionArgs);
}
contentResolver.delete(WaypointsColumns.CONTENT_URI, WaypointsColumns.TRACKID + "=?",
new String[] { Long.toString(trackId) });
// Delete tracks last since it triggers a database vaccum call
- contentResolver.delete(TracksColumns.CONTENT_URI, TracksColumns._ID + "=?", new String[] {
- Long.toString(trackId) });
+ contentResolver.delete(TracksColumns.CONTENT_URI, TracksColumns._ID + "=?",
+ new String[] { Long.toString(trackId) });
}
@Override
@@ -326,9 +328,9 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
int elevationGainIndex = cursor.getColumnIndexOrThrow(WaypointsColumns.ELEVATIONGAIN);
int minGradeIndex = cursor.getColumnIndexOrThrow(WaypointsColumns.MINGRADE);
int maxGradeIndex = cursor.getColumnIndexOrThrow(WaypointsColumns.MAXGRADE);
-
+
Waypoint waypoint = new Waypoint();
-
+
if (!cursor.isNull(idIndex)) {
waypoint.setId(cursor.getLong(idIndex));
}
@@ -362,7 +364,7 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
if (!cursor.isNull(stopIdIndex)) {
waypoint.setStopId(cursor.getLong(stopIdIndex));
}
-
+
Location location = new Location("");
if (!cursor.isNull(longitudeIndex) && !cursor.isNull(latitudeIndex)) {
location.setLongitude(((double) cursor.getInt(longitudeIndex)) / 1E6);
@@ -384,7 +386,7 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
location.setBearing(cursor.getFloat(bearingIndex));
}
waypoint.setLocation(location);
-
+
TripStatistics tripStatistics = new TripStatistics();
boolean hasTripStatistics = false;
if (!cursor.isNull(startTimeIndex)) {
@@ -427,7 +429,7 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
tripStatistics.setMaxGrade(cursor.getFloat(maxGradeIndex));
hasTripStatistics = true;
}
-
+
if (hasTripStatistics) {
waypoint.setTripStatistics(tripStatistics);
}
@@ -485,8 +487,7 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
String selection = WaypointsColumns.TRACKID + "=? AND " + WaypointsColumns.TYPE + "="
+ Waypoint.TYPE_STATISTICS;
String[] selectionArgs = new String[] { Long.toString(trackId) };
- cursor = getWaypointCursor(
- null, selection, selectionArgs, WaypointsColumns._ID + " DESC", 1);
+ cursor = getWaypointCursor(null, selection, selectionArgs, WaypointsColumns._ID + " DESC", 1);
if (cursor != null && cursor.moveToFirst()) {
return createWaypoint(cursor);
}
@@ -585,7 +586,7 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
ContentValues createContentValues(Waypoint waypoint) {
ContentValues values = new ContentValues();
-
+
// Value < 0 indicates no id is available
if (waypoint.getId() >= 0) {
values.put(WaypointsColumns._ID, waypoint.getId());
@@ -600,7 +601,7 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
values.put(WaypointsColumns.DURATION, waypoint.getDuration());
values.put(WaypointsColumns.STARTID, waypoint.getStartId());
values.put(WaypointsColumns.STOPID, waypoint.getStopId());
-
+
Location location = waypoint.getLocation();
if (location != null) {
values.put(WaypointsColumns.LONGITUDE, (int) (location.getLongitude() * 1E6));
@@ -619,7 +620,7 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
values.put(WaypointsColumns.BEARING, location.getBearing());
}
}
-
+
TripStatistics tripStatistics = waypoint.getTripStatistics();
if (tripStatistics != null) {
values.put(WaypointsColumns.STARTTIME, tripStatistics.getStartTime());
@@ -720,7 +721,7 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
}
return -1L;
}
-
+
@Override
public long getLastTrackPointId(long trackId) {
if (trackId < 0) {
@@ -752,18 +753,26 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
}
String selection = TrackPointsColumns._ID + "=(select max(" + TrackPointsColumns._ID + ") from "
+ TrackPointsColumns.TABLE_NAME + " WHERE " + TrackPointsColumns.TRACKID + "=? AND "
- + TrackPointsColumns.LATITUDE + "<=90000000)";
+ + TrackPointsColumns.LATITUDE + "<=" + MAX_LATITUDE + ")";
String[] selectionArgs = new String[] { Long.toString(trackId) };
return findTrackPointBy(selection, selectionArgs);
}
+ @Override
+ public Location getLastValidTrackPoint() {
+ String selection = TrackPointsColumns._ID + "=(select max(" + TrackPointsColumns._ID + ") from "
+ + TrackPointsColumns.TABLE_NAME + " WHERE " + TrackPointsColumns.LATITUDE + "<="
+ + MAX_LATITUDE + ")";
+ return findTrackPointBy(selection, null);
+ }
+
@Override
public Cursor getTrackPointCursor(
long trackId, long startTrackPointId, int maxLocations, boolean descending) {
if (trackId < 0) {
return null;
}
-
+
String selection;
String[] selectionArgs;
if (startTrackPointId >= 0) {
@@ -775,7 +784,7 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
selection = TrackPointsColumns.TRACKID + "=?";
selectionArgs = new String[] { Long.toString(trackId) };
}
-
+
String sortOrder = TrackPointsColumns._ID;
if (descending) {
sortOrder += " DESC";
@@ -787,8 +796,9 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
}
@Override
- public LocationIterator getTrackPointLocationIterator(final long trackId, final long startTrackPointId,
- final boolean descending, final LocationFactory locationFactory) {
+ public LocationIterator getTrackPointLocationIterator(final long trackId,
+ final long startTrackPointId, final boolean descending,
+ final LocationFactory locationFactory) {
if (locationFactory == null) {
throw new IllegalArgumentException("locationFactory is null");
}
@@ -798,7 +808,7 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
private final CachedTrackPointsIndexes
indexes = cursor != null ? new CachedTrackPointsIndexes(cursor)
: null;
-
+
/**
* Gets the track point cursor.
*
@@ -807,24 +817,24 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
private Cursor getCursor(long trackPointId) {
return getTrackPointCursor(trackId, trackPointId, defaultCursorBatchSize, descending);
}
-
+
/**
* Advances the cursor to the next batch. Returns true if successful.
*/
private boolean advanceCursorToNextBatch() {
- long trackPointId = lastTrackPointId == -1L ? -1L : lastTrackPointId + (descending ? -1
- : 1);
+ long trackPointId = lastTrackPointId == -1L ? -1L
+ : lastTrackPointId + (descending ? -1 : 1);
Log.d(TAG, "Advancing track point id: " + trackPointId);
cursor.close();
cursor = getCursor(trackPointId);
return cursor != null;
}
-
+
@Override
public long getLocationId() {
return lastTrackPointId;
}
-
+
@Override
public boolean hasNext() {
if (cursor == null) {
@@ -841,7 +851,7 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
}
return true;
}
-
+
@Override
public Location next() {
if (cursor == null) {
@@ -857,7 +867,7 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
fillTrackPoint(cursor, indexes, location);
return location;
}
-
+
@Override
public void close() {
if (cursor != null) {
@@ -865,7 +875,7 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
cursor = null;
}
}
-
+
@Override
public void remove() {
throw new UnsupportedOperationException();
@@ -890,7 +900,7 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
values.put(TrackPointsColumns.TRACKID, trackId);
values.put(TrackPointsColumns.LONGITUDE, (int) (location.getLongitude() * 1E6));
values.put(TrackPointsColumns.LATITUDE, (int) (location.getLatitude() * 1E6));
-
+
// Hack for Samsung phones that don't properly populate the time field
long time = location.getTime();
if (time == 0) {
@@ -909,7 +919,7 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
if (location.hasBearing()) {
values.put(TrackPointsColumns.BEARING, location.getBearing());
}
-
+
if (location instanceof MyTracksLocation) {
MyTracksLocation myTracksLocation = (MyTracksLocation) location;
if (myTracksLocation.getSensorDataSet() != null) {
@@ -928,7 +938,7 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
*/
private void fillTrackPoint(Cursor cursor, CachedTrackPointsIndexes indexes, Location location) {
location.reset();
-
+
if (!cursor.isNull(indexes.longitudeIndex)) {
location.setLongitude(((double) cursor.getInt(indexes.longitudeIndex)) / 1E6);
}
diff --git a/MyTracksTest/.classpath b/MyTracksTest/.classpath
index 17b7b5ec6..a67371fb4 100644
--- a/MyTracksTest/.classpath
+++ b/MyTracksTest/.classpath
@@ -1,8 +1,6 @@
-
-
@@ -10,5 +8,7 @@
+
+
diff --git a/MyTracksTest/src/com/google/android/apps/mytracks/MapOverlayTest.java b/MyTracksTest/src/com/google/android/apps/mytracks/MapOverlayTest.java
deleted file mode 100644
index bcc24231f..000000000
--- a/MyTracksTest/src/com/google/android/apps/mytracks/MapOverlayTest.java
+++ /dev/null
@@ -1,192 +0,0 @@
-/*
- * Copyright 2010 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.google.android.apps.mytracks;
-
-import com.google.android.apps.mytracks.content.Waypoint;
-import com.google.android.apps.mytracks.maps.SingleColorTrackPathPainter;
-import com.google.android.maps.MapView;
-
-import android.graphics.Canvas;
-import android.graphics.Path;
-import android.location.Location;
-import android.test.AndroidTestCase;
-
-/**
- * Tests {@link MapOverlay}.
- *
- * @author Bartlomiej Niechwiej
- * @author Vangelis S.
- */
-public class MapOverlayTest extends AndroidTestCase {
- private Canvas canvas;
- private MockMyTracksOverlay mockMyTracksOverlay;
- private MapView mapView;
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
- canvas = new Canvas();
- mockMyTracksOverlay = new MockMyTracksOverlay(getContext());
-
- // Enable drawing.
- mockMyTracksOverlay.setTrackDrawingEnabled(true);
-
- // Set a TrackPathPainter with a MockPath.
- mockMyTracksOverlay.setTrackPathPainter(new SingleColorTrackPathPainter(getContext()) {
- @Override
- public Path newPath() {
- return new MockPath();
- }
- });
-
- mapView = null;
- }
-
- /**
- * Tests {@link MapOverlay#addLocation(Location)}.
- */
- public void testAddLocation() throws Exception {
- Location location = new Location("gps");
- location.setLatitude(10);
- location.setLongitude(20);
- mockMyTracksOverlay.addLocation(location);
- assertEquals(1, mockMyTracksOverlay.getNumLocations());
- assertEquals(0, mockMyTracksOverlay.getNumWaypoints());
-
- location.setLatitude(20);
- location.setLongitude(30);
- mockMyTracksOverlay.addLocation(location);
- assertEquals(2, mockMyTracksOverlay.getNumLocations());
- assertEquals(0, mockMyTracksOverlay.getNumWaypoints());
- assertFalse(mockMyTracksOverlay.getTrackPathPainter().hasPath());
-
- // Draw and make sure that we don't lose any point.
- mockMyTracksOverlay.draw(canvas, mapView, false);
- assertEquals(2, mockMyTracksOverlay.getNumLocations());
- assertEquals(0, mockMyTracksOverlay.getNumWaypoints());
- assertTrue(mockMyTracksOverlay.getTrackPathPainter().hasPath());
- SingleColorTrackPathPainter trackPathPainter = (SingleColorTrackPathPainter) mockMyTracksOverlay
- .getTrackPathPainter();
- MockPath path = (MockPath) trackPathPainter.getPath();
- assertEquals(2, path.getTotalPoints());
-
- mockMyTracksOverlay.draw(canvas, mapView, true);
- assertEquals(2, mockMyTracksOverlay.getNumLocations());
- assertEquals(0, mockMyTracksOverlay.getNumWaypoints());
- assertTrue(mockMyTracksOverlay.getTrackPathPainter().hasPath());
- }
-
- /**
- * Tests {@link MapOverlay#clearPoints()}.
- */
- public void testClearPoints() throws Exception {
- Location location = new Location("gps");
- location.setLatitude(10);
- location.setLongitude(20);
- mockMyTracksOverlay.addLocation(location);
- assertEquals(1, mockMyTracksOverlay.getNumLocations());
- mockMyTracksOverlay.clearPoints();
- assertEquals(0, mockMyTracksOverlay.getNumLocations());
-
- // Test after drawing on canvas
- final int locations = 100;
- for (int i = 0; i < locations; ++i) {
- mockMyTracksOverlay.addLocation(location);
- }
- assertEquals(locations, mockMyTracksOverlay.getNumLocations());
- mockMyTracksOverlay.draw(canvas, mapView, false);
- mockMyTracksOverlay.draw(canvas, mapView, true);
- mockMyTracksOverlay.clearPoints();
- assertEquals(0, mockMyTracksOverlay.getNumLocations());
- }
-
- /**
- * Tests {@link MapOverlay#addWaypoint(Waypoint)}.
- */
- public void testAddWaypoint() throws Exception {
- Location location = new Location("gps");
- location.setLatitude(10);
- location.setLongitude(20);
- Waypoint waypoint = new Waypoint();
- waypoint.setLocation(location);
- mockMyTracksOverlay.addWaypoint(waypoint);
- assertEquals(1, mockMyTracksOverlay.getNumWaypoints());
- assertEquals(0, mockMyTracksOverlay.getNumLocations());
- assertFalse(mockMyTracksOverlay.getTrackPathPainter().hasPath());
-
- final int waypoints = 10;
- for (int i = 0; i < waypoints; ++i) {
- waypoint = new Waypoint();
- waypoint.setLocation(location);
- mockMyTracksOverlay.addWaypoint(waypoint);
- }
- assertEquals(1 + waypoints, mockMyTracksOverlay.getNumWaypoints());
- assertEquals(0, mockMyTracksOverlay.getNumLocations());
- assertFalse(mockMyTracksOverlay.getTrackPathPainter().hasPath());
- }
-
- /**
- * Tests {@link MapOverlay#clearWaypoints()}.
- */
- public void testClearWaypoints() throws Exception {
- Location location = new Location("gps");
- location.setLatitude(10);
- location.setLongitude(20);
- Waypoint waypoint = new Waypoint();
- waypoint.setLocation(location);
- mockMyTracksOverlay.addWaypoint(waypoint);
- assertEquals(1, mockMyTracksOverlay.getNumWaypoints());
- mockMyTracksOverlay.clearWaypoints();
- assertEquals(0, mockMyTracksOverlay.getNumWaypoints());
- }
-
- /**
- * Tests {@link MapOverlay#draw(Canvas, MapView, boolean)}.
- */
- public void testDrawing() {
- Location location = new Location("gps");
- location.setLatitude(10);
- for (int i = 0; i < 40; ++i) {
- location.setLongitude(20 + i);
- Waypoint waypoint = new Waypoint();
- waypoint.setLocation(location);
- mockMyTracksOverlay.addWaypoint(waypoint);
- }
- for (int i = 0; i < 100; ++i) {
- location = new Location("gps");
- location.setLatitude(20 + i / 2);
- location.setLongitude(150 - i);
- mockMyTracksOverlay.addLocation(location);
- }
-
- // Shadow.
- mockMyTracksOverlay.draw(canvas, mapView, true);
- // We don't expect to do anything if
- assertFalse(mockMyTracksOverlay.getTrackPathPainter().hasPath());
- assertEquals(40, mockMyTracksOverlay.getNumWaypoints());
- assertEquals(100, mockMyTracksOverlay.getNumLocations());
-
- // No shadow.
- mockMyTracksOverlay.draw(canvas, mapView, false);
- assertTrue(mockMyTracksOverlay.getTrackPathPainter().hasPath());
- SingleColorTrackPathPainter trackPathPainter = (SingleColorTrackPathPainter) mockMyTracksOverlay
- .getTrackPathPainter();
- MockPath path = (MockPath) trackPathPainter.getPath();
- assertEquals(40, mockMyTracksOverlay.getNumWaypoints());
- assertEquals(100, mockMyTracksOverlay.getNumLocations());
- assertEquals(100, path.getTotalPoints());
- }
-}
diff --git a/MyTracksTest/src/com/google/android/apps/mytracks/MockMyTracksOverlay.java b/MyTracksTest/src/com/google/android/apps/mytracks/MockMyTracksOverlay.java
deleted file mode 100644
index d9a393498..000000000
--- a/MyTracksTest/src/com/google/android/apps/mytracks/MockMyTracksOverlay.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright 2011 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.google.android.apps.mytracks;
-
-import com.google.android.maps.MapView;
-import com.google.android.maps.Projection;
-
-import android.content.Context;
-import android.graphics.Rect;
-
-/**
- * A mock {@link MapOverlay} for testing.
- *
- * @author Bartlomiej Niechwiej
- * @author Vangelis S.
- *
- */
-public class MockMyTracksOverlay extends MapOverlay {
-
- private Projection projection;
-
- public MockMyTracksOverlay(Context context) {
- super(context);
- projection = new MockProjection();
- }
-
- @Override
- public Projection getMapProjection(MapView mapView) {
- return projection;
- }
-
- @Override
- public Rect getMapViewRect(MapView mapView) {
- return new Rect(0, 0, (int) (100 * 1E6), (int) (100 * 1E6));
- }
-}
\ 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
deleted file mode 100644
index 0a7ed511c..000000000
--- a/MyTracksTest/src/com/google/android/apps/mytracks/MockPath.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * 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;
-
-/**
- * A mock {@link Path}. Records calls to {@link Path#lineTo(float, float)} and
- * {@link Path#moveTo(float, float)}.
- *
- * @author Bartlomiej Niechwiej
- * @author Vangelis S.
- */
-public class MockPath extends Path {
-
- // A list of disjointed path segments.
- private final List> segments = new LinkedList>();
-
- // The total number of points in this path.
- private 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);
- currentSegment = new ArrayList(Arrays.asList(new PointF(x, y)));
- segments.add(currentSegment);
- totalPoints++;
- }
-
- /**
- * Gets the total number of points in this path.
- */
- public int getTotalPoints() {
- return 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
deleted file mode 100644
index b1dbc5bdd..000000000
--- a/MyTracksTest/src/com/google/android/apps/mytracks/MockProjection.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * 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;
-
-/**
- * A mock {@link Projection}. Acts as an identity matrix.
- *
- * @author Bartlomiej Niechwiej
- * @author Vangelis S.
- *
- */
-public class MockProjection implements Projection {
-
- @Override
- public Point toPixels(GeoPoint geoPoint, Point point) {
- return point;
- }
-
- @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/endtoendtest/ViewsTest.java b/MyTracksTest/src/com/google/android/apps/mytracks/endtoendtest/ViewsTest.java
index 59e563924..ba266aa35 100644
--- a/MyTracksTest/src/com/google/android/apps/mytracks/endtoendtest/ViewsTest.java
+++ b/MyTracksTest/src/com/google/android/apps/mytracks/endtoendtest/ViewsTest.java
@@ -16,7 +16,7 @@
package com.google.android.apps.mytracks.endtoendtest;
import com.google.android.apps.mytracks.TrackListActivity;
-import com.google.android.apps.mytracks.fragments.MapFragment;
+import com.google.android.apps.mytracks.fragments.MyTracksMapFragment;
import com.google.android.maps.MapView;
import com.google.android.maps.mytracks.R;
@@ -51,8 +51,8 @@ public class ViewsTest extends ActivityInstrumentationTestCase2 points = createCachedLocations(NUMBER_OF_LOCATIONS, INVALID_LATITUDE, -1);
- dynamicSpeedTrackPathPainter.updatePath(myTracksOverlay.getMapProjection(mockView),
- myTracksOverlay.getMapViewRect(mockView), 1, points);
- AndroidMock.verify(trackPathDescriptor);
- // Should be zero for there is no valid locations.
- assertEquals(0, dynamicSpeedTrackPathPainter.getColoredPaths().size());
- }
-
- /**
- * Tests the
- * {@link DynamicSpeedTrackPathPainter#updatePath(Projection, Rect, int, List)}
- * when all locations are valid.
- */
- public void testUpdatePath_AllValidLocation() {
- List points = createCachedLocations(NUMBER_OF_LOCATIONS,
- TrackStubUtils.INITIAL_LATITUDE, -1);
-
- // Gets a number as the start index of points.
- int startLocationIdx = NUMBER_OF_LOCATIONS / 2;
- dynamicSpeedTrackPathPainter.updatePath(myTracksOverlay.getMapProjection(mockView),
- myTracksOverlay.getMapViewRect(mockView), startLocationIdx, points);
-
- AndroidMock.verify(trackPathDescriptor);
- assertEquals(NUMBER_OF_LOCATIONS - startLocationIdx, dynamicSpeedTrackPathPainter
- .getColoredPaths().size());
- }
-
- /**
- * Tests the
- * {@link DynamicSpeedTrackPathPainter#updatePath(Projection, Rect, int, List)}
- * when all locations are valid. This test setups 4 segments with 25 points
- * each. The first segment has slow speed, the second segment has normal
- * speed, the third segment has fast speed, and the fourth segment has slow
- * speed.
- */
- public void testUpdatePath_CheckColoredPath() {
- // Gets the slow speed. Divide SLOW_SPEED by 2 to make it smaller than
- // SLOW_SPEED. Speed in MyTracksLocation use MS, but speed in CachedLocation
- // use KMH.
- int slowSpeed = SLOW_SPEED_MS / 2;
- // Gets the normal speed. Makes it smaller than SLOW_SPEED and bigger than
- // NORMAL_SPEED. Speed in MyTracksLocation use MS, but speed in
- // CachedLocation use KMH.
- int normalSpeed = (SLOW_SPEED_MS + NORMAL_SPEED_MS) / 2;
- // Gets the fast speed. Multiply it by 2 to make it bigger than
- // NORMAL_SPEED. Speed in MyTracksLocation use MS, but speed in
- // CachedLocation use KMH.
- int fastSpeed = NORMAL_SPEED_MS * 2;
-
- // Get a number of startLocationIdx. And divide NUMBER_OF_LOCATIONS by 8 to
- // make sure it is less than numberOfFirstThreeSegments.
- int startLocationIdx = LOCATIONS_PER_SEGMENT / 2;
-
- List points = createCachedLocations(LOCATIONS_PER_SEGMENT,
- TrackStubUtils.INITIAL_LATITUDE, slowSpeed);
- points.addAll(createCachedLocations(LOCATIONS_PER_SEGMENT, TrackStubUtils.INITIAL_LATITUDE,
- normalSpeed));
- points.addAll(createCachedLocations(LOCATIONS_PER_SEGMENT, TrackStubUtils.INITIAL_LATITUDE,
- fastSpeed));
- points.addAll(createCachedLocations(LOCATIONS_PER_SEGMENT, TrackStubUtils.INITIAL_LATITUDE,
- slowSpeed));
-
- dynamicSpeedTrackPathPainter.updatePath(myTracksOverlay.getMapProjection(mockView),
- myTracksOverlay.getMapViewRect(mockView), startLocationIdx, points);
-
- AndroidMock.verify(trackPathDescriptor);
- List coloredPath = dynamicSpeedTrackPathPainter.getColoredPaths();
- assertEquals(NUMBER_OF_LOCATIONS - startLocationIdx, coloredPath.size());
-
- // Checks different speeds with different color in the coloredPath.
- for (int i = 0; i < NUMBER_OF_LOCATIONS - startLocationIdx; i++) {
- if (i < LOCATIONS_PER_SEGMENT - startLocationIdx) {
- // Slow.
- assertEquals(getContext().getResources().getColor(R.color.slow_path), coloredPath.get(i)
- .getPathPaint().getColor());
- } else if (i < LOCATIONS_PER_SEGMENT * 2 - startLocationIdx) {
- // Normal.
- assertEquals(getContext().getResources().getColor(R.color.normal_path), coloredPath.get(i)
- .getPathPaint().getColor());
- } else if (i < LOCATIONS_PER_SEGMENT * 3 - startLocationIdx) {
- // Fast.
- assertEquals(getContext().getResources().getColor(R.color.fast_path), coloredPath.get(i)
- .getPathPaint().getColor());
- } else {
- // Slow.
- assertEquals(getContext().getResources().getColor(R.color.slow_path), coloredPath.get(i)
- .getPathPaint().getColor());
- }
- }
- }
-
- /**
- * Initials a mocked TrackPathDescriptor object.
- */
- @UsesMocks(TrackPathDescriptor.class)
- private void initialTrackPathDescriptorMock() {
- trackPathDescriptor = AndroidMock.createMock(TrackPathDescriptor.class);
- AndroidMock.expect(trackPathDescriptor.getSlowSpeed()).andReturn(SLOW_SPEED_KMH);
- AndroidMock.expect(trackPathDescriptor.getNormalSpeed()).andReturn(NORMAL_SPEED_KMH);
- AndroidMock.replay(trackPathDescriptor);
- }
-
-}
diff --git a/MyTracksTest/src/com/google/android/apps/mytracks/maps/SingleColorTrackPathPainterTest.java b/MyTracksTest/src/com/google/android/apps/mytracks/maps/SingleColorTrackPathPainterTest.java
deleted file mode 100644
index fa59e216b..000000000
--- a/MyTracksTest/src/com/google/android/apps/mytracks/maps/SingleColorTrackPathPainterTest.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright 2012 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.apps.mytracks.TrackStubUtils;
-import com.google.android.maps.Projection;
-import com.google.android.testing.mocking.AndroidMock;
-import com.google.android.testing.mocking.UsesMocks;
-
-import android.graphics.Path;
-import android.graphics.Rect;
-
-import java.util.List;
-
-/**
- * Tests for the {@link SingleColorTrackPathPainter}.
- *
- * @author Youtao Liu
- */
-public class SingleColorTrackPathPainterTest extends TrackPathPainterTestCase {
-
- private static final int NUMBER_OF_LOCATIONS = 10;
- private SingleColorTrackPathPainter singleColorTrackPathPainter;
- private Path pathMock;
-
-
- /**
- * Initials a mocked TrackPathDescriptor object and
- * singleColorTrackPathPainter.
- */
- @Override
- @UsesMocks(Path.class)
- protected void setUp() throws Exception {
- super.setUp();
-
- singleColorTrackPathPainter = new SingleColorTrackPathPainter(getContext());
- pathMock = AndroidMock.createStrictMock(Path.class);
- }
-
- /**
- * Tests the
- * {@link SingleColorTrackPathPainter#updatePath(Projection, Rect, int, List)}
- * method when all locations are valid.
- */
- public void testUpdatePath_AllValidLocation() {
- // Gets a number as the start index of points.
- int startLocationIdx = NUMBER_OF_LOCATIONS / 2;
-
- pathMock.incReserve(NUMBER_OF_LOCATIONS - startLocationIdx);
- List points = createCachedLocations(NUMBER_OF_LOCATIONS,
- TrackStubUtils.INITIAL_LATITUDE, -1);
-
- for (int i = startLocationIdx; i < NUMBER_OF_LOCATIONS; i++) {
- pathMock.lineTo(0, 0);
- }
-
- AndroidMock.replay(pathMock);
- singleColorTrackPathPainter.updatePath(myTracksOverlay.getMapProjection(mockView),
- myTracksOverlay.getMapViewRect(mockView), startLocationIdx, points, pathMock);
- AndroidMock.verify(pathMock);
- }
-
- /**
- * Tests the
- * {@link SingleColorTrackPathPainter#updatePath(Projection, Rect, int, List)}
- * method when all locations are invalid.
- */
- public void testUpdatePath_AllInvalidLocation() {
- int startLocationIdx = NUMBER_OF_LOCATIONS / 2;
- pathMock.incReserve(NUMBER_OF_LOCATIONS - startLocationIdx);
- List points = createCachedLocations(NUMBER_OF_LOCATIONS, INVALID_LATITUDE, -1);
- // Gets a random number from 1 to numberOfLocations.
- AndroidMock.replay(pathMock);
- singleColorTrackPathPainter.updatePath(myTracksOverlay.getMapProjection(mockView),
- myTracksOverlay.getMapViewRect(mockView), startLocationIdx, points, pathMock);
- AndroidMock.verify(pathMock);
- }
-
- /**
- * Tests the
- * {@link SingleColorTrackPathPainter#updatePath(Projection, Rect, int, List)}
- * method when there are three segments.
- */
- public void testUpdatePath_ThreeSegments() {
- // First segment.
- List points = createCachedLocations(NUMBER_OF_LOCATIONS,
- TrackStubUtils.INITIAL_LATITUDE, -1);
- points.addAll(createCachedLocations(1, INVALID_LATITUDE, -1));
- // Second segment.
- points.addAll(createCachedLocations(NUMBER_OF_LOCATIONS, TrackStubUtils.INITIAL_LATITUDE, -1));
- points.addAll(createCachedLocations(1, INVALID_LATITUDE, -1));
- // Third segment.
- points.addAll(createCachedLocations(NUMBER_OF_LOCATIONS, TrackStubUtils.INITIAL_LATITUDE, -1));
- // Gets a random number from 1 to numberOfLocations.
- int startLocationIdx = NUMBER_OF_LOCATIONS / 2;
- pathMock.incReserve(NUMBER_OF_LOCATIONS *3 + 1 +1 - startLocationIdx);
- for (int i = 0; i < NUMBER_OF_LOCATIONS - startLocationIdx; i++) {
- pathMock.lineTo(0, 0);
- }
- pathMock.moveTo(0, 0);
- for (int i = 0; i < NUMBER_OF_LOCATIONS - 1; i++) {
- pathMock.lineTo(0, 0);
- }
- pathMock.moveTo(0, 0);
- for (int i = 0; i < NUMBER_OF_LOCATIONS - 1; i++) {
- pathMock.lineTo(0, 0);
- }
-
- AndroidMock.replay(pathMock);
- singleColorTrackPathPainter.updatePath(myTracksOverlay.getMapProjection(mockView),
- myTracksOverlay.getMapViewRect(mockView), startLocationIdx, points, pathMock);
- AndroidMock.verify(pathMock);
- }
-}
diff --git a/MyTracksTest/src/com/google/android/apps/mytracks/maps/TrackPathDescriptorDynamicSpeedTest.java b/MyTracksTest/src/com/google/android/apps/mytracks/maps/TrackPathDescriptorDynamicSpeedTest.java
deleted file mode 100644
index ec3361dbf..000000000
--- a/MyTracksTest/src/com/google/android/apps/mytracks/maps/TrackPathDescriptorDynamicSpeedTest.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * 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.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()));
- myTracksOverlay.setTrackPathPainter(painter);
-
- int startLocationIdx = 0;
-
- assertNotNull(painter);
- painter.updatePath(myTracksOverlay.getMapProjection(mockView),
- myTracksOverlay.getMapViewRect(mockView), startLocationIdx,
- myTracksOverlay.getPoints());
- assertNotNull(myTracksOverlay.getTrackPathPainter().hasPath());
- painter.drawPath(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
deleted file mode 100644
index 668d1d741..000000000
--- a/MyTracksTest/src/com/google/android/apps/mytracks/maps/TrackPathDescriptorFixedSpeedTest.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * 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.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()));
- myTracksOverlay.setTrackPathPainter(painter);
-
- int startLocationIdx = 0;
-
- assertNotNull(painter);
- painter.updatePath(myTracksOverlay.getMapProjection(mockView),
- myTracksOverlay.getMapViewRect(mockView), startLocationIdx, myTracksOverlay.getPoints());
- assertNotNull(myTracksOverlay.getTrackPathPainter().hasPath());
- painter.drawPath(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
deleted file mode 100644
index 9d9622b6a..000000000
--- a/MyTracksTest/src/com/google/android/apps/mytracks/maps/TrackPathPainterFactoryTest.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * 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.util.PreferencesUtils;
-import com.google.android.maps.mytracks.R;
-
-import android.content.Context;
-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();
-
- testTrackPathPainterFactorySpecific(context,
- R.string.settings_map_track_color_mode_single_value, SingleColorTrackPathPainter.class);
- testTrackPathPainterFactorySpecific(context, R.string.settings_map_track_color_mode_fixed_value,
- DynamicSpeedTrackPathPainter.class);
- testTrackPathPainterFactorySpecific(context,
- R.string.settings_map_track_color_mode_dynamic_value, DynamicSpeedTrackPathPainter.class);
- }
-
- private void testTrackPathPainterFactorySpecific(
- Context context, int track_color_mode, Class> c) {
- PreferencesUtils.setString(
- context, R.string.track_color_mode_key, context.getString(track_color_mode));
-
- int startLocationIdx = 0;
-
- TrackPathPainter painter = TrackPathPainterFactory.getTrackPathPainter(context);
- myTracksOverlay.setTrackPathPainter(painter);
-
- assertNotNull(painter);
- assertTrue(c.isInstance(painter));
-
- painter.updatePath(myTracksOverlay.getMapProjection(mockView),
- myTracksOverlay.getMapViewRect(mockView), startLocationIdx,
- myTracksOverlay.getPoints());
- assertNotNull(myTracksOverlay.getTrackPathPainter().hasPath());
- painter.drawPath(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
deleted file mode 100644
index 32cce7438..000000000
--- a/MyTracksTest/src/com/google/android/apps/mytracks/maps/TrackPathPainterSingleColorTest.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * 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.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());
- myTracksOverlay.setTrackPathPainter(painter);
-
- int startLocationIdx = 0;
-
- assertNotNull(painter);
- painter.updatePath(myTracksOverlay.getMapProjection(mockView),
- myTracksOverlay.getMapViewRect(mockView), startLocationIdx,
- myTracksOverlay.getPoints());
- assertNotNull(myTracksOverlay.getTrackPathPainter().hasPath());
- painter.drawPath(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
deleted file mode 100644
index b53909b6e..000000000
--- a/MyTracksTest/src/com/google/android/apps/mytracks/maps/TrackPathPainterTestCase.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * 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;
-import com.google.android.apps.mytracks.MapOverlay.CachedLocation;
-import com.google.android.apps.mytracks.MockMyTracksOverlay;
-import com.google.android.apps.mytracks.TrackStubUtils;
-import com.google.android.maps.MapView;
-
-import android.graphics.Canvas;
-import android.location.Location;
-import android.test.AndroidTestCase;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * 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;
-
- final int INVALID_LATITUDE = 100;
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
- canvas = new Canvas();
- myTracksOverlay = new MockMyTracksOverlay(getContext());
- // Enable drawing.
- myTracksOverlay.setTrackDrawingEnabled(true);
- mockView = null;
- }
-
- /**
- * Creates a list of CachedLocations.
- *
- * @param number the number of locations
- * @param latitude the latitude value of locations.
- * @param speed the speed(meter per second) of locations, and will give a default valid value if
- * less than zero
- * @return the simulated locations
- */
- List createCachedLocations(int number, double latitude, float speed) {
- List points = new ArrayList();
- for (int i = 0; i < number; ++i) {
- Location location = TrackStubUtils.createMyTracksLocation(latitude,
- TrackStubUtils.INITIAL_LONGITUDE, TrackStubUtils.INITIAL_ALTITUDE);
- if (speed > 0) {
- location.setSpeed(speed);
- }
- CachedLocation cachedLocation = new CachedLocation(location);
- points.add(cachedLocation);
- }
- return points;
- }
-}
diff --git a/google_play_services_lib/.classpath b/google_play_services_lib/.classpath
new file mode 100644
index 000000000..3f9691c5d
--- /dev/null
+++ b/google_play_services_lib/.classpath
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/google_play_services_lib/.project b/google_play_services_lib/.project
new file mode 100755
index 000000000..0a85af4e7
--- /dev/null
+++ b/google_play_services_lib/.project
@@ -0,0 +1,33 @@
+
+
+ Google Maps Library Dynamic
+
+
+
+
+
+ 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
+
+
diff --git a/google_play_services_lib/AndroidManifest.xml b/google_play_services_lib/AndroidManifest.xml
new file mode 100755
index 000000000..5a6bc5dc7
--- /dev/null
+++ b/google_play_services_lib/AndroidManifest.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
diff --git a/google_play_services_lib/README.txt b/google_play_services_lib/README.txt
new file mode 100644
index 000000000..901da746e
--- /dev/null
+++ b/google_play_services_lib/README.txt
@@ -0,0 +1,14 @@
+Library Project including Google Play services client jar.
+
+This can be used by an Android project to use the API's provided
+by Google Play services.
+
+There is technically no source, but the src folder is necessary
+to ensure that the build system works. The content is actually
+located in libs/google-play-services.jar
+
+
+USAGE:
+
+Make sure you import this Android library project into your IDE
+and set this project as a dependency.
diff --git a/google_play_services_lib/libs/google-play-services.jar b/google_play_services_lib/libs/google-play-services.jar
new file mode 100644
index 000000000..81c3c56ef
Binary files /dev/null and b/google_play_services_lib/libs/google-play-services.jar differ
diff --git a/google_play_services_lib/libs/google-play-services.jar.properties b/google_play_services_lib/libs/google-play-services.jar.properties
new file mode 100644
index 000000000..429687b79
--- /dev/null
+++ b/google_play_services_lib/libs/google-play-services.jar.properties
@@ -0,0 +1 @@
+doc=../../../docs/reference
diff --git a/google_play_services_lib/project.properties b/google_play_services_lib/project.properties
new file mode 100755
index 000000000..db721fd89
--- /dev/null
+++ b/google_play_services_lib/project.properties
@@ -0,0 +1,15 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must be checked in Version Control Systems.
+#
+# To customize properties used by the Ant build system edit
+# "ant.properties", and override values to adapt the script to your
+# project structure.
+#
+# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
+#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
+
+# Project target.
+target=android-8
+android.library=true
diff --git a/google_play_services_lib/res/values/maps_attrs.xml b/google_play_services_lib/res/values/maps_attrs.xml
new file mode 100644
index 000000000..ade282e99
--- /dev/null
+++ b/google_play_services_lib/res/values/maps_attrs.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/google_play_services_lib/res/values/strings.xml b/google_play_services_lib/res/values/strings.xml
new file mode 100644
index 000000000..5bb77e14a
--- /dev/null
+++ b/google_play_services_lib/res/values/strings.xml
@@ -0,0 +1,47 @@
+
+
+
+
+ Get Google Play services
+
+
+ This app won\'t run without
+ Google Play services, which are missing from your phone.
+
+
+ This app won\'t run without
+ Google Play services, which are missing from your tablet.
+
+
+ Get Google Play services
+
+
+ Enable Google Play services
+
+
+ This app won\'t work unless you
+ enable Google Play services.
+
+
+ Enable Google Play services
+
+
+ Update Google Play services
+
+
+ This app won\'t run unless you
+ update Google Play services.
+
+
+ Update
+
+
diff --git a/google_play_services_lib/src/.readme b/google_play_services_lib/src/.readme
new file mode 100644
index 000000000..145ea525b
--- /dev/null
+++ b/google_play_services_lib/src/.readme
@@ -0,0 +1 @@
+This hidden file is here to ensure there is a src folder.