package com.arman.osmdroidmapsforge.map; import android.app.AlertDialog; import android.app.Dialog; import android.content.Context; import android.content.DialogInterface; import android.content.res.TypedArray; import android.graphics.Color; import android.graphics.drawable.Drawable; import android.location.Location; import android.location.LocationListener; import android.location.LocationManager; import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.util.AttributeSet; import android.view.View; import android.widget.Button; import android.widget.Toast; import com.arman.osmdroidmapsforge.Helper; import com.arman.osmdroidmapsforge.R; import com.arman.osmdroidmapsforge.map.overlays.MyLocationNewOverlay; import com.arman.osmdroidmapsforge.map.overlays.RotationGestureOverlay; import com.arman.osmdroidmapsforge.routing.RouteCalculator; import com.arman.osmdroidmapsforge.routing.RoutingSession; import com.arman.osmdroidmapsforge.map.overlays.MyMarker; import org.osmdroid.ResourceProxy; import org.osmdroid.bonuspack.overlays.FolderOverlay; import org.osmdroid.bonuspack.overlays.MapEventsOverlay; import org.osmdroid.bonuspack.overlays.MapEventsReceiver; import org.osmdroid.bonuspack.overlays.MarkerInfoWindow; import org.osmdroid.bonuspack.overlays.Polyline; import org.osmdroid.bonuspack.routing.Road; import org.osmdroid.bonuspack.routing.RoadNode; import org.osmdroid.tileprovider.MapTileProviderBase; import org.osmdroid.util.GeoPoint; import org.osmdroid.views.MapView; import org.osmdroid.views.overlay.Overlay; import org.osmdroid.views.overlay.mylocation.GpsMyLocationProvider; import java.util.ArrayList; import java.util.List; /** * Created by Arman on 5/14/2015. */ public class MFMapView extends org.osmdroid.views.MapView implements LocationListener { public static LocationManager locManager; private RotationGestureOverlay mRotationGestureOverlay; static GpsMyLocationProvider gpsLocationProvider; static MyLocationNewOverlay myLocationNewOverlay; private static boolean isCurrentPosLayerAdded = false; MyMarker longPressMarker; protected int rotationMode = 1; // 0 : Up to North, 1: equal to movement bearing boolean followMyLocation = true; boolean isRoutingStuffAdded = false; public static MFMapView mInstance; private static Context mContext; protected Polyline mRoadOverlay; Polyline mTrackingLineOverlay; protected FolderOverlay mRoadNodeMarkers; static final int OSRM=0, GRAPHHOPPER_FASTEST=1, GRAPHHOPPER_BICYCLE=2, GRAPHHOPPER_PEDESTRIAN=3, GOOGLE_FASTEST=4; RouteCalculator mRouteCalculator; int mWhichRouteProvider; public static Road mRoad; //made static to pass between activities boolean routingZoomToBoundingBox = true; Dialog longPressDlg; MyMarker startRouteMarker; ArrayList<MyMarker> intermediateMarkers; MyMarker endRouteMarker; public MFMapView(Context context, AttributeSet attrs) { super(context, attrs); initializeMap(); } public MFMapView(final Context context, final int tileSizePixels) { super(context, tileSizePixels); initializeMap(); } public MFMapView(final Context context, final int tileSizePixels, final ResourceProxy resourceProxy) { super(context, tileSizePixels, resourceProxy, null); initializeMap(); } public MFMapView(final Context context, final int tileSizePixels, final ResourceProxy resourceProxy, final MapTileProviderBase aTileProvider) { super(context, tileSizePixels, resourceProxy, aTileProvider, null); initializeMap(); } public MFMapView(final Context context, final int tileSizePixels, final ResourceProxy resourceProxy, final MapTileProviderBase aTileProvider, final Handler tileRequestCompleteHandler) { super(context, tileSizePixels, resourceProxy, aTileProvider, tileRequestCompleteHandler, null); initializeMap(); } protected void initializeMap() { this.setMultiTouchControls(true); mInstance = this; mContext = getContext(); // UnComment these lines to add a scale bar to your map: // ScaleBarOverlay scaleBarOverlay = new ScaleBarOverlay(this.getContext()); // scaleBarOverlay.drawLatitudeScale(true); // scaleBarOverlay.drawLongitudeScale(true); // mapView.getOverlays().add(scaleBarOverlay); mRotationGestureOverlay = new RotationGestureOverlay(this.getContext(), this); mRotationGestureOverlay.setEnabled(true); this.getOverlays().add(this.mRotationGestureOverlay); mRoadNodeMarkers = new FolderOverlay(mContext); mRoadNodeMarkers.setName("Route Steps"); mWhichRouteProvider = GRAPHHOPPER_FASTEST; mRouteCalculator = new RouteCalculator(mContext); mRouteCalculator.loadGraphStorage(); MapEventsOverlay mapEventsOverlay = new MapEventsOverlay(this.getContext(), new MapEventsReceiver() { @Override public boolean singleTapConfirmedHelper(GeoPoint arg0) { if (longPressMarker != null) longPressMarker.closeInfoWindow(); return false; } @Override public boolean longPressHelper(final GeoPoint position) { if (isRoutingStuffAdded) { if (longPressDlg == null) { longPressDlg = new Dialog(getContext()); longPressDlg.setTitle("Choose one"); longPressDlg.setContentView(R.layout.dlg_lng_press_choice); } if (intermediateMarkers == null) { intermediateMarkers = new ArrayList<MyMarker>(); } Button btn_set_start = (Button) longPressDlg.findViewById(R.id.btn_set_start); Button btn_set_end = (Button) longPressDlg.findViewById(R.id.btn_set_end); Button btn_add_poi = (Button) longPressDlg.findViewById(R.id.btn_add_poi); Button btn_add_intermediate_point = (Button) longPressDlg.findViewById(R.id.btn_add_intermediate_point); if (endRouteMarker != null) btn_add_intermediate_point.setVisibility(View.VISIBLE); else btn_add_intermediate_point.setVisibility(View.GONE); btn_add_intermediate_point.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { longPressDlg.dismiss(); final MyMarker myMarker = new MyMarker(mInstance); myMarker.setPosition(position); myMarker.setAnchor(MyMarker.ANCHOR_CENTER, MyMarker.ANCHOR_BOTTOM); myMarker.setIcon(getResources().getDrawable(R.drawable.marker_green)); myMarker.setInfoWindow(null); myMarker.setOnMarkerClickListener(new MyMarker.OnMarkerClickListener() { @Override public boolean onMarkerClick(MyMarker var1, MapView var2) { AlertDialog alertDialog = new AlertDialog.Builder(mContext).create(); alertDialog.setTitle("Delete marker"); alertDialog.setMessage("Are you sure?"); alertDialog.setButton(AlertDialog.BUTTON_POSITIVE, "Yes", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { mInstance.getOverlays().remove(myMarker); intermediateMarkers.remove(myMarker); mInstance.invalidate(); dialog.dismiss(); checkForRouteDrawRequest(); } }); alertDialog.setButton(AlertDialog.BUTTON_NEGATIVE, "No", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); } }); alertDialog.show(); return false; } }); intermediateMarkers.add(myMarker); mInstance.getOverlays().add(myMarker); mInstance.invalidate(); checkForRouteDrawRequest(); } }); btn_set_start.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if (startRouteMarker != null) mInstance.getOverlays().remove(startRouteMarker); startRouteMarker = new MyMarker(mInstance); startRouteMarker.setPosition(position); startRouteMarker.setAnchor(MyMarker.ANCHOR_CENTER, MyMarker.ANCHOR_BOTTOM); startRouteMarker.setIcon(getResources().getDrawable(R.drawable.marker_blue)); startRouteMarker.setInfoWindow(null); mInstance.getOverlays().add(startRouteMarker); mInstance.invalidate(); checkForRouteDrawRequest(); longPressDlg.dismiss(); } }); btn_set_end.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if (endRouteMarker != null) mInstance.getOverlays().remove(endRouteMarker); endRouteMarker = new MyMarker(mInstance); endRouteMarker.setPosition(position); endRouteMarker.setAnchor(MyMarker.ANCHOR_CENTER, MyMarker.ANCHOR_BOTTOM); endRouteMarker.setIcon(getResources().getDrawable(R.drawable.marker_red)); endRouteMarker.setInfoWindow(null); mInstance.getOverlays().add(endRouteMarker); mInstance.invalidate(); checkForRouteDrawRequest(); longPressDlg.dismiss(); } }); btn_add_poi.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Toast.makeText(mContext, "Add a POI to map", Toast.LENGTH_SHORT).show(); } }); longPressDlg.show(); } else { if (startRouteMarker == null) { startRouteMarker = new MyMarker(mInstance); startRouteMarker.setPosition(new GeoPoint(position)); startRouteMarker.setAnchor(MyMarker.ANCHOR_CENTER, MyMarker.ANCHOR_BOTTOM); startRouteMarker.setIcon(getResources().getDrawable(R.drawable.marker_blue)); mInstance.getOverlays().add(startRouteMarker); getController().animateTo(position); mInstance.invalidate(); } else { if (endRouteMarker != null) { endRouteMarker.closeInfoWindow(); mInstance.getOverlays().remove(endRouteMarker); } endRouteMarker = new MyMarker(mInstance); endRouteMarker.setPosition(position); endRouteMarker.setAnchor(MyMarker.ANCHOR_CENTER, MyMarker.ANCHOR_BOTTOM); endRouteMarker.setIcon(getResources().getDrawable(R.drawable.marker_red)); mInstance.getOverlays().add(endRouteMarker); getController().animateTo(position); mInstance.invalidate(); checkForRouteDrawRequest(); } } return false; } }); this.getOverlays().add(0, mapEventsOverlay); setLocationListener(); this.invalidate(); } private void checkForRouteDrawRequest() { ArrayList<GeoPoint> geoPoints = new ArrayList<GeoPoint>(); if (startRouteMarker != null) { geoPoints.add(startRouteMarker.getPosition()); } if (startRouteMarker != null && endRouteMarker != null) { if (intermediateMarkers != null) for (MyMarker myMarker : intermediateMarkers) { geoPoints.add(myMarker.getPosition()); } geoPoints.add(endRouteMarker.getPosition()); if (isRoutingStuffAdded) removeRoutingStuffFromUi(); calculateAndShowRoute(geoPoints, true); } } public void calculateAndShowRoute(ArrayList<GeoPoint> points, boolean showStartEndMarkers) { UpdateRoadTask updateRoadTask = new UpdateRoadTask(showStartEndMarkers); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) updateRoadTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, points); else updateRoadTask.execute(points); } private UpdateRoadTask updateRoadTask; private class UpdateRoadTask extends AsyncTask<ArrayList<GeoPoint>, Void, Road> { private ArrayList<GeoPoint> mPoints; boolean mShowStartEndMarkers; public UpdateRoadTask(boolean showStartEndMarkers) { mShowStartEndMarkers = showStartEndMarkers; } protected void onPreExecute() { Toast.makeText(mContext, "Calculating best route...", Toast.LENGTH_LONG).show(); } protected Road doInBackground(ArrayList<GeoPoint>... points) { mPoints = points[0]; return Helper.getRoutingRoad(mContext, RoutingSession.getRouteCalculator(mContext), mWhichRouteProvider, points[0]); } protected void onPostExecute(Road result) { if (mShowStartEndMarkers) setRoutingStart_EndMarkers(mPoints.get(0), mPoints.get(mPoints.size() - 1)); updateUIWithRoad(result); updateRoadTask = null; // getPOIAsync(poiTagText.getText().toString()); } } public void updateUIWithRoad(Road road){ isRoutingStuffAdded = true; mRoad = road; mRoadNodeMarkers.getItems().clear(); List<Overlay> mapOverlays = this.getOverlays(); if (mRoadOverlay != null){ mapOverlays.remove(mRoadOverlay); mRoadOverlay = null; } if (road == null) return; if (road.mStatus == Road.STATUS_TECHNICAL_ISSUE) { Toast.makeText(this.getContext(), "Technical error in calculating route", Toast.LENGTH_SHORT).show(); } else if (road.mStatus > Road.STATUS_TECHNICAL_ISSUE) //functional issues Toast.makeText(this.getContext(), "No routes found", Toast.LENGTH_SHORT).show(); mRoadOverlay = buildRoadOverlay(road, Color.parseColor("#004eff"), 7.0f, this.getContext()); String routeDesc = road.getLengthDurationText(-1); mRoadOverlay.setTitle("path" + " - " + routeDesc); mapOverlays.add(0, mRoadOverlay); //we dinsert the road overlay at the "bottom", just above the MapEventsOverlay, //to avoid covering the other overlays. if (routingZoomToBoundingBox) this.zoomToBoundingBox(road.mBoundingBox); putRoadNodes(road); this.invalidate(); } private void putRoadNodes(Road road){ mInstance.getOverlays().remove(mRoadNodeMarkers); mRoadNodeMarkers.getItems().clear(); Drawable icon = getResources().getDrawable(R.drawable.marker_node); int n = road.mNodes.size(); MarkerInfoWindow infoWindow = new MarkerInfoWindow(R.layout.bonuspack_bubble, this); TypedArray iconIds = getResources().obtainTypedArray(R.array.direction_icons); for (int i=0; i<n; i++){ RoadNode node = road.mNodes.get(i); String instructions = (node.mInstructions==null ? "" : node.mInstructions); MyMarker nodeMarker = new MyMarker(this); nodeMarker.setTitle("Step"+ " " + (i+1)); nodeMarker.setSnippet(instructions); nodeMarker.setSubDescription(Road.getLengthDurationText(node.mLength, node.mDuration)); nodeMarker.setPosition(node.mLocation); nodeMarker.setIcon(icon); nodeMarker.setInfoWindow(infoWindow); //use a shared infowindow. int iconId = iconIds.getResourceId(node.mManeuverType, R.drawable.ic_empty); if (iconId != R.drawable.ic_empty){ Drawable image = getResources().getDrawable(iconId); nodeMarker.setImage(image); } mRoadNodeMarkers.add(nodeMarker); } mInstance.getOverlays().add(1, mRoadNodeMarkers); iconIds.recycle(); if (mRoadNodeMarkers != null && mRoadOverlay != null) { if (mRoad.mNodes.size() > 0) { RoadNode node = mRoad.mNodes.get(0); String distance; if (node.mLength < 1) distance = String.format("%dm", (int) (node.mLength * 1000)); else distance = String.format("%.1fkm", node.mLength); } } } public static Polyline buildRoadOverlay(Road road, int color, float width, Context context){ Polyline roadOverlay = new Polyline(context); roadOverlay.setColor(color); roadOverlay.setWidth(width); if (road != null) { ArrayList<GeoPoint> polyline = road.mRouteHigh; roadOverlay.setPoints(polyline); } return roadOverlay; } public void setRoutingStart_EndMarkers(GeoPoint startPoint, GeoPoint endPoint) { if (endRouteMarker != null) { endRouteMarker.closeInfoWindow(); mInstance.getOverlays().remove(endRouteMarker); } endRouteMarker = new MyMarker(mInstance); endRouteMarker.setPosition(endPoint); endRouteMarker.setAnchor(MyMarker.ANCHOR_CENTER, MyMarker.ANCHOR_BOTTOM); endRouteMarker.setIcon(getResources().getDrawable(R.drawable.marker_red)); if (startRouteMarker != null) { startRouteMarker.closeInfoWindow(); mInstance.getOverlays().remove(startRouteMarker); } startRouteMarker = new MyMarker(mInstance); startRouteMarker.setPosition(startPoint); startRouteMarker.setAnchor(MyMarker.ANCHOR_CENTER, MyMarker.ANCHOR_BOTTOM); startRouteMarker.setIcon(getResources().getDrawable(R.drawable.marker_blue)); mInstance.getOverlays().add(startRouteMarker); mInstance.getOverlays().add(endRouteMarker); } public void removeRoutingStuffFromUi() { isRoutingStuffAdded = false; mInstance.getOverlays().remove(mRoadOverlay); mInstance.getOverlays().remove(mRoadNodeMarkers); mInstance.getOverlays().remove(endRouteMarker); mInstance.getOverlays().remove(startRouteMarker); if (intermediateMarkers != null) mInstance.getOverlays().removeAll(intermediateMarkers); startRouteMarker = null; endRouteMarker = null; mInstance.invalidate(); } public void setLocationListener() { locManager = (LocationManager)this.getContext().getSystemService(Context.LOCATION_SERVICE); locManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 5, 1f, this); } public void addMyLocationOverlay() { if (!isCurrentPosLayerAdded) { gpsLocationProvider = new GpsMyLocationProvider(this.getContext()); gpsLocationProvider.setLocationUpdateMinTime(2); gpsLocationProvider.setLocationUpdateMinDistance(5); myLocationNewOverlay = new MyLocationNewOverlay(this.getContext(), gpsLocationProvider, this); myLocationNewOverlay.enableMyLocation(gpsLocationProvider); // You can set info window for current location, it opens by clicking on it's marker // myLocationNewOverlay.setInfoWindow( // new CurrentPosInfoWindow(R.layout.bubble_new_poi, this, myLocationNewOverlay)); myLocationNewOverlay.enableCompass(); this.getOverlays().add( myLocationNewOverlay); isCurrentPosLayerAdded = true; this.invalidate(); } } public void setCurrentAsCenter() { if (locManager == null) locManager = (LocationManager)this.getContext().getSystemService(Context.LOCATION_SERVICE); Location location = getLastBestLocation(getContext()); if (location != null) { getController().animateTo(new GeoPoint(location)); this.getController().setZoom(15); } else { Location lastBestLocation = getLastBestLocation(getContext()); if (lastBestLocation != null) { getController().animateTo(new GeoPoint(lastBestLocation)); this.getController().setZoom(15); } else { Toast.makeText(this.getContext(), "Searching for your location", Toast.LENGTH_LONG).show(); this.getController().setCenter(new GeoPoint(32.653906, 51.659088)); // Iran, Isfahan this.getController().setZoom(15); } try { locManager.requestLocationUpdates( LocationManager.GPS_PROVIDER, 5000, 20, this); } catch (Exception e) { e.printStackTrace(); } } } public static Location getLastBestLocation(Context _context) { if (locManager == null) locManager = (LocationManager)_context.getSystemService(Context.LOCATION_SERVICE); Location bestResult = null; float bestAccuracy = Float.MAX_VALUE; // Iterate through all the providers on the system, keeping // note of the most accurate result within the acceptable time limit. // If no result is found within maxTime, return the newest Location. List<String> matchingProviders = locManager.getAllProviders(); for (String provider: matchingProviders) { Location location = locManager.getLastKnownLocation(provider); if (location != null) { float accuracy = location.getAccuracy(); if ( accuracy < bestAccuracy) { bestResult = location; bestAccuracy = accuracy; } } } return bestResult; } protected void setCurrentPositionMarker(Location location, boolean setCenter) { if (!isCurrentPosLayerAdded) { locManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 5, 1f, this); this.addMyLocationOverlay(); } else { if (followMyLocation) myLocationNewOverlay.enableFollowLocation(); else myLocationNewOverlay.disableFollowLocation(); myLocationNewOverlay.enableMyLocation(); } if (setCenter && location != null) { this.getController().animateTo(new GeoPoint(location.getLatitude(), location.getLongitude())); this.getController().setZoom(15); } this.invalidate(); } public Location getCurrentLocation() { return getCurrentLocation(true); } public Location getCurrentLocation(boolean isFirstAttempt) { Location loc = Helper.getLastBestLocation(this.getContext()); if (loc == null) { // locManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, this); locManager.requestLocationUpdates(LocationManager.PASSIVE_PROVIDER, 0, 0, this); if (isFirstAttempt) return getCurrentLocation(false); } return loc; } @Override public void onLocationChanged(Location location) { if (followMyLocation) { setCurrentPositionMarker(location, true); } else setCurrentPositionMarker(location, false); if (rotationMode == 1 && location.hasBearing() && location.getSpeed() * 3.6 > 10) { this.setMapOrientation(360 - location.getBearing()); } } @Override public void onProviderDisabled(String provider) { // TODO Auto-generated method stub } @Override public void onProviderEnabled(String provider) { // TODO Auto-generated method stub } @Override public void onStatusChanged(String provider, int status, Bundle extras) { // TODO Auto-generated method stub } }