Added animation to follow a route. This way it is easier to test

the voice navigation. Animation menu item is visible when 'Allow mock
location' is set in debug menu of android settings.
This commit is contained in:
Pavol Zibrita 2011-08-16 01:06:55 +02:00
parent e0799857cb
commit a2a1113791
6 changed files with 129 additions and 6 deletions

View file

@ -10,6 +10,7 @@
<!-- not visible by default --> <!-- not visible by default -->
<item android:id="@+id/map_navigate_to_point" android:title="@string/stop_navigation" android:visible="false" android:icon="@android:drawable/ic_menu_close_clear_cancel"></item> <item android:id="@+id/map_navigate_to_point" android:title="@string/stop_navigation" android:visible="false" android:icon="@android:drawable/ic_menu_close_clear_cancel"></item>
<item android:id="@+id/map_mute" android:title="@string/menu_mute_off" android:visible="false"></item> <item android:id="@+id/map_mute" android:title="@string/menu_mute_off" android:visible="false"></item>
<item android:id="@+id/map_animate_route" android:title="@string/animate_route" android:visible="false"></item>
<item android:id="@+id/map_get_directions" android:title="@string/get_directions" android:icon="@android:drawable/ic_menu_directions"></item> <item android:id="@+id/map_get_directions" android:title="@string/get_directions" android:icon="@android:drawable/ic_menu_directions"></item>
<item android:title="@string/map_specify_point" android:id="@+id/map_specify_point" android:icon="@android:drawable/ic_menu_search"></item> <item android:title="@string/map_specify_point" android:id="@+id/map_specify_point" android:icon="@android:drawable/ic_menu_search"></item>

View file

@ -1,5 +1,8 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?> <?xml version="1.0" encoding="utf-8" standalone="no"?>
<resources> <resources>
<string name="animate_route_off">Animate off</string>
<string name="animate_route">Animate on</string>
<string name="local_index_upload_gpx_description">Upload GPX files to OSM community. They will be used to improve maps.</string> <string name="local_index_upload_gpx_description">Upload GPX files to OSM community. They will be used to improve maps.</string>
<string name="local_index_items_uploaded">%1$d of %2$d item(s) successfully uploaded.</string> <string name="local_index_items_uploaded">%1$d of %2$d item(s) successfully uploaded.</string>
<string name="local_index_mi_upload_gpx">Contribute to OSM...</string> <string name="local_index_mi_upload_gpx">Contribute to OSM...</string>

View file

@ -0,0 +1,34 @@
package net.osmand;
import android.location.Location;
public class LatLonUtils {
public static Location middleLocation(Location start, Location end,
float meters) {
double lat1 = toRad(start.getLatitude());
double lon1 = toRad(start.getLongitude());
double R = 6371; // radius of earth in km
double d = meters / 1000; // in km
float brng = (float) (toRad(start.bearingTo(end)));
double lat2 = Math.asin(Math.sin(lat1) * Math.cos(d / R)
+ Math.cos(lat1) * Math.sin(d / R) * Math.cos(brng));
double lon2 = lon1
+ Math.atan2(Math.sin(brng) * Math.sin(d / R) * Math.cos(lat1),
Math.cos(d / R) - Math.sin(lat1) * Math.sin(lat2));
Location nl = new Location(start);
nl.setLatitude(toDegree(lat2));
nl.setLongitude(toDegree(lon2));
nl.setBearing(brng);
return nl;
}
private static double toDegree(double radians) {
return radians * 180 / Math.PI;
}
private static double toRad(double degree) {
return degree * Math.PI / 180;
}
}

View file

@ -28,12 +28,12 @@ import net.osmand.plus.views.OsmandMapTileView;
import net.osmand.plus.views.PointLocationLayer; import net.osmand.plus.views.PointLocationLayer;
import android.app.Activity; import android.app.Activity;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.app.Dialog; import android.app.Dialog;
import android.app.Notification; import android.app.Notification;
import android.app.NotificationManager; import android.app.NotificationManager;
import android.app.PendingIntent; import android.app.PendingIntent;
import android.app.ProgressDialog; import android.app.ProgressDialog;
import android.app.AlertDialog.Builder;
import android.content.ActivityNotFoundException; import android.content.ActivityNotFoundException;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.DialogInterface; import android.content.DialogInterface;
@ -58,6 +58,7 @@ import android.os.Bundle;
import android.os.Environment; import android.os.Environment;
import android.os.Handler; import android.os.Handler;
import android.os.Message; import android.os.Message;
import android.provider.Settings.Secure;
import android.util.Log; import android.util.Log;
import android.view.KeyEvent; import android.view.KeyEvent;
import android.view.Menu; import android.view.Menu;
@ -65,8 +66,8 @@ import android.view.MenuInflater;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.View; import android.view.View;
import android.view.Window;
import android.view.View.OnClickListener; import android.view.View.OnClickListener;
import android.view.Window;
import android.view.animation.AccelerateInterpolator; import android.view.animation.AccelerateInterpolator;
import android.view.animation.Animation; import android.view.animation.Animation;
import android.view.animation.Transformation; import android.view.animation.Transformation;
@ -121,6 +122,8 @@ public class MapActivity extends Activity implements IMapLocationListener, Senso
// Store previous map rotation settings for rotate button // Store previous map rotation settings for rotate button
private Integer previousMapRotate = null; private Integer previousMapRotate = null;
private RouteAnimation routeAnimation = new RouteAnimation();
private boolean isMapLinkedToLocation = false; private boolean isMapLinkedToLocation = false;
private ProgressDialog startProgressDialog; private ProgressDialog startProgressDialog;
@ -436,6 +439,7 @@ public class MapActivity extends Activity implements IMapLocationListener, Senso
protected void onDestroy() { protected void onDestroy() {
super.onDestroy(); super.onDestroy();
savingTrackHelper.close(); savingTrackHelper.close();
routeAnimation.close();
if(mNotificationManager != null){ if(mNotificationManager != null){
mNotificationManager.cancel(APP_NOTIFICATION_ID); mNotificationManager.cancel(APP_NOTIFICATION_ID);
} }
@ -948,6 +952,15 @@ public class MapActivity extends Activity implements IMapLocationListener, Senso
muteMenu.setVisible(false); muteMenu.setVisible(false);
} }
} }
MenuItem animateMenu = menu.findItem(R.id.map_animate_route);
if (animateMenu != null) {
animateMenu.setTitle(routeAnimation.isRouteAnimating() ? R.string.animate_route_off
: R.string.animate_route);
animateMenu.setVisible("1".equals(Secure.getString(
getContentResolver(), Secure.ALLOW_MOCK_LOCATION))
&& settings.getPointToNavigate() != null
&& routingHelper.isRouteCalculated());
}
return val; return val;
} }
@ -1003,6 +1016,10 @@ public class MapActivity extends Activity implements IMapLocationListener, Senso
case R.id.map_show_point_options: case R.id.map_show_point_options:
contextMenuPoint(mapView.getLatitude(), mapView.getLongitude()); contextMenuPoint(mapView.getLatitude(), mapView.getLongitude());
return true; return true;
case R.id.map_animate_route:
//animate moving on route
routeAnimation.startStopRouteAnimation(routingHelper, this);
return true;
default: default:
return super.onOptionsItemSelected(item); return super.onOptionsItemSelected(item);
} }
@ -1104,9 +1121,7 @@ public class MapActivity extends Activity implements IMapLocationListener, Senso
@Override @Override
public void onClick(DialogInterface dialog, int which) { public void onClick(DialogInterface dialog, int which) {
ApplicationMode mode = getAppMode(buttons); ApplicationMode mode = getAppMode(buttons);
Location location = new Location("map"); //$NON-NLS-1$ Location location = getLocationToStartFrom(lat, lon);
location.setLatitude(lat);
location.setLongitude(lon);
routingHelper.setAppMode(mode); routingHelper.setAppMode(mode);
settings.FOLLOW_TO_THE_ROUTE.set(false); settings.FOLLOW_TO_THE_ROUTE.set(false);
routingHelper.setFollowingMode(false); routingHelper.setFollowingMode(false);

View file

@ -0,0 +1,65 @@
package net.osmand.plus.activities;
import java.util.ArrayList;
import java.util.List;
import net.osmand.LatLonUtils;
import android.location.Location;
public class RouteAnimation {
private Thread routeAnimation;
public boolean isRouteAnimating() {
return routeAnimation != null;
}
public void startStopRouteAnimation(final RoutingHelper routingHelper,
final MapActivity ma) {
if (!isRouteAnimating()) {
routeAnimation = new Thread() {
public void run() {
final List<Location> directions = new ArrayList<Location>(
routingHelper.getCurrentRoute());
Location current = null;
float meters = 20.0f;
while (!directions.isEmpty() && routeAnimation != null) {
if (current == null) {
current = new Location(directions.remove(0));
} else {
if (current.distanceTo(directions.get(0)) > meters) {
current = LatLonUtils.middleLocation(current,
directions.get(0), meters);
} else {
current = new Location(directions.remove(0));
}
}
current.setSpeed(meters);
current.setTime(System.currentTimeMillis());
ma.setLocation(current);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// do nothing
}
}
RouteAnimation.this.stop();
};
};
routeAnimation.start();
} else {
// stop the animation
stop();
}
}
private void stop() {
routeAnimation = null;
}
public void close() {
if (isRouteAnimating()) {
stop();
}
}
}

View file

@ -117,13 +117,18 @@ public class RoutingHelper {
this.lastFixedLocation = null; this.lastFixedLocation = null;
this.isFollowingMode = false; this.isFollowingMode = false;
} }
} }
public List<Location> getCurrentGPXRoute() { public List<Location> getCurrentGPXRoute() {
return currentGPXRoute; return currentGPXRoute;
} }
public List<Location> getCurrentRoute() {
return currentGPXRoute == null || currentGPXRoute.isEmpty() ? Collections
.unmodifiableList(routeNodes) : Collections
.unmodifiableList(currentGPXRoute);
}
public void setAppMode(ApplicationMode mode){ public void setAppMode(ApplicationMode mode){
this.mode = mode; this.mode = mode;
voiceRouter.updateAppMode(); voiceRouter.updateAppMode();