package com.example.osmbonuspacktuto; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Bundle; import android.os.Environment; import android.os.StrictMode; import android.support.v4.content.res.ResourcesCompat; import android.view.LayoutInflater; import android.view.View; import android.widget.Button; import android.widget.ImageView; import android.widget.Toast; import org.osmdroid.api.IMapController; import org.osmdroid.bonuspack.clustering.RadiusMarkerClusterer; import org.osmdroid.bonuspack.clustering.StaticCluster; import org.osmdroid.bonuspack.kml.KmlDocument; import org.osmdroid.bonuspack.kml.KmlFeature; import org.osmdroid.bonuspack.kml.KmlFolder; import org.osmdroid.bonuspack.kml.KmlLineString; import org.osmdroid.bonuspack.kml.KmlPlacemark; import org.osmdroid.bonuspack.kml.KmlPoint; import org.osmdroid.bonuspack.kml.KmlPolygon; import org.osmdroid.bonuspack.kml.KmlTrack; import org.osmdroid.bonuspack.kml.Style; import org.osmdroid.bonuspack.location.NominatimPOIProvider; import org.osmdroid.bonuspack.location.OverpassAPIProvider; import org.osmdroid.bonuspack.location.POI; import org.osmdroid.bonuspack.overlays.GroundOverlay; import org.osmdroid.bonuspack.routing.OSRMRoadManager; import org.osmdroid.bonuspack.routing.Road; import org.osmdroid.bonuspack.routing.RoadManager; import org.osmdroid.bonuspack.routing.RoadNode; import org.osmdroid.config.Configuration; import org.osmdroid.events.MapEventsReceiver; import org.osmdroid.util.BoundingBox; import org.osmdroid.util.GeoPoint; import org.osmdroid.views.MapView; import org.osmdroid.views.overlay.FolderOverlay; import org.osmdroid.views.overlay.MapEventsOverlay; import org.osmdroid.views.overlay.Marker; import org.osmdroid.views.overlay.Marker.OnMarkerDragListener; import org.osmdroid.views.overlay.Overlay; import org.osmdroid.views.overlay.Polygon; import org.osmdroid.views.overlay.Polyline; import org.osmdroid.views.overlay.infowindow.BasicInfoWindow; import org.osmdroid.views.overlay.infowindow.InfoWindow; import org.osmdroid.views.overlay.infowindow.MarkerInfoWindow; import java.io.File; import java.util.ArrayList; /** * This is the implementation of OSMBonusPack tutorials. * Sections of code can be commented/uncommented depending on the progress in the tutorials. * * @author M.Kergall * @see <a href="https://github.com/MKergall/osmbonuspack">OSMBonusPack on GitHub</a> */ public class MainActivity extends Activity implements MapEventsReceiver, MapView.OnFirstLayoutListener { MapView map; KmlDocument mKmlDocument; @Override protected void onCreate(Bundle savedInstanceState) { //Disable StrictMode.ThreadPolicy to perform network calls in the UI thread. //Yes, it's not the good practice, but this is just a tutorial! StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build(); StrictMode.setThreadPolicy(policy); //Introduction super.onCreate(savedInstanceState); boolean hwAccelerationOK = com.example.osmbonuspacktuto.Polygon.SDKsupportsPathOp(); Configuration.getInstance().setMapViewHardwareAccelerated(hwAccelerationOK); LayoutInflater inflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE); View v = inflater.inflate(R.layout.main, null); setContentView(R.layout.main); map = (MapView) findViewById(R.id.map); map.setBuiltInZoomControls(true); map.setMultiTouchControls(true); GeoPoint startPoint = new GeoPoint(48.13, -1.63); IMapController mapController = map.getController(); mapController.setZoom(10); mapController.setCenter(startPoint); map.setMapOrientation(20.0f); //0. Using the Marker overlay Marker startMarker = new Marker(map); startMarker.setPosition(startPoint); startMarker.setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_BOTTOM); startMarker.setTitle("Start point"); //startMarker.setIcon(getResources().getDrawable(R.drawable.marker_kml_point).mutate()); //startMarker.setImage(getResources().getDrawable(R.drawable.ic_launcher)); //startMarker.setInfoWindow(new MarkerInfoWindow(R.layout.bonuspack_bubble_black, map)); startMarker.setDraggable(true); startMarker.setOnMarkerDragListener(new OnMarkerDragListenerDrawer()); map.getOverlays().add(startMarker); //1. "Hello, Routing World" RoadManager roadManager = new OSRMRoadManager(this); //2. Playing with the RoadManager //roadManager roadManager = new MapQuestRoadManager("YOUR_API_KEY"); //roadManager.addRequestOption("routeType=bicycle"); ArrayList<GeoPoint> waypoints = new ArrayList<GeoPoint>(); waypoints.add(startPoint); GeoPoint endPoint = new GeoPoint(48.4, -1.9); waypoints.add(endPoint); Road road = roadManager.getRoad(waypoints); if (road.mStatus != Road.STATUS_OK) Toast.makeText(this, "Error when loading the road - status=" + road.mStatus, Toast.LENGTH_SHORT).show(); Polyline roadOverlay = RoadManager.buildRoadOverlay(road); map.getOverlays().add(roadOverlay); //3. Showing the Route steps on the map FolderOverlay roadMarkers = new FolderOverlay(); map.getOverlays().add(roadMarkers); Drawable nodeIcon = ResourcesCompat.getDrawable(getResources(), R.drawable.marker_node, null); for (int i = 0; i < road.mNodes.size(); i++) { RoadNode node = road.mNodes.get(i); Marker nodeMarker = new Marker(map); nodeMarker.setPosition(node.mLocation); nodeMarker.setIcon(nodeIcon); //4. Filling the bubbles nodeMarker.setTitle("Step " + i); nodeMarker.setSnippet(node.mInstructions); nodeMarker.setSubDescription(Road.getLengthDurationText(this, node.mLength, node.mDuration)); Drawable iconContinue = ResourcesCompat.getDrawable(getResources(), R.drawable.ic_continue, null); nodeMarker.setImage(iconContinue); //4. end roadMarkers.add(nodeMarker); } //5. OpenStreetMap POIs with Nominatim NominatimPOIProvider poiProvider = new NominatimPOIProvider("OsmNavigator/1.0"); ArrayList<POI> pois = poiProvider.getPOICloseTo(startPoint, "cinema", 50, 0.1); //or : ArrayList<POI> pois = poiProvider.getPOIAlong(road.getRouteLow(), "fuel", 50, 2.0); //6. Wikipedia POIs with GeoNames /* GeoNamesPOIProvider poiProvider = new GeoNamesPOIProvider("mkergall"); //BoundingBox bb = map.getBoundingBox(); //ArrayList<POI> pois = poiProvider.getPOIInside(bb, 30); //=> not possible in onCreate, as map bounding box is not correct until a draw occurs (osmdroid issue). ArrayList<POI> pois = poiProvider.getPOICloseTo(startPoint, 30, 20.0); */ //8. Quick overview of the Flickr and Picasa POIs */ /* PicasaPOIProvider poiProvider = new PicasaPOIProvider(null); BoundingBox bb = BoundingBox.fromGeoPoints(waypoints); ArrayList<POI> pois = poiProvider.getPOIInside(bb, 20, null); */ //FolderOverlay poiMarkers = new FolderOverlay(this); //10. Marker Clustering RadiusMarkerClusterer poiMarkers = new RadiusMarkerClusterer(this); //end of 10. //11.1 Customizing the clusters design Drawable clusterIconD = ResourcesCompat.getDrawable(getResources(), R.drawable.marker_poi_cluster, null); Bitmap clusterIcon = ((BitmapDrawable) clusterIconD).getBitmap(); poiMarkers.setIcon(clusterIcon); poiMarkers.getTextPaint().setTextSize(12 * getResources().getDisplayMetrics().density); poiMarkers.mAnchorV = Marker.ANCHOR_BOTTOM; poiMarkers.mTextAnchorU = 0.70f; poiMarkers.mTextAnchorV = 0.27f; //end of 11.1 map.getOverlays().add(poiMarkers); Drawable poiIcon = ResourcesCompat.getDrawable(getResources(), R.drawable.marker_poi_default, null); if (pois != null) { for (POI poi : pois) { Marker poiMarker = new Marker(map); poiMarker.setTitle(poi.mType); poiMarker.setSnippet(poi.mDescription); poiMarker.setPosition(poi.mLocation); poiMarker.setIcon(poiIcon); if (poi.mThumbnail != null) { poiMarker.setImage(new BitmapDrawable(getResources(), poi.mThumbnail)); } // 7. poiMarker.setInfoWindow(new CustomInfoWindow(map)); poiMarker.setRelatedObject(poi); poiMarkers.add(poiMarker); } } //12. Loading KML content //String url = "http://mapsengine.google.com/map/kml?forcekml=1&mid=z6IJfj90QEd4.kUUY9FoHFRdE"; mKmlDocument = new KmlDocument(); //boolean ok = mKmlDocument.parseKMLUrl(url); //Get OpenStreetMap content as KML with Overpass API: OverpassAPIProvider overpassProvider = new OverpassAPIProvider(); BoundingBox oBB = new BoundingBox(startPoint.getLatitude() + 0.25, startPoint.getLongitude() + 0.25, startPoint.getLatitude() - 0.25, startPoint.getLongitude() - 0.25); String oUrl = overpassProvider.urlForTagSearchKml("highway=speed_camera", oBB, 500, 30); boolean ok = overpassProvider.addInKmlFolder(mKmlDocument.mKmlRoot, oUrl); //Variant - getting KML file from Assets: /* AssetManager assetManager = getAssets(); boolean ok; try { InputStream stream = assetManager.open("KML_Samples.kml"); ok = mKmlDocument.parseKMLStream(stream, null); stream.close(); }catch (Exception e) { e.printStackTrace(); ok = false; } */ if (ok) { //13.1 Simple styling Drawable defaultMarker = ResourcesCompat.getDrawable(getResources(), R.drawable.marker_kml_point, null); Bitmap defaultBitmap = ((BitmapDrawable) defaultMarker).getBitmap(); Style defaultStyle = new Style(defaultBitmap, 0x901010AA, 3.0f, 0x20AA1010); //13.2 Advanced styling with Styler KmlFeature.Styler styler = new MyKmlStyler(defaultStyle); FolderOverlay kmlOverlay = (FolderOverlay) mKmlDocument.mKmlRoot.buildOverlay(map, defaultStyle, styler, mKmlDocument); map.getOverlays().add(kmlOverlay); BoundingBox bb = mKmlDocument.mKmlRoot.getBoundingBox(); if (bb != null) { //map.zoomToBoundingBox(bb, false); //=> not working in onCreate - this is a well-known osmdroid issue. //Workaround: setInitialViewOn(bb); } } else Toast.makeText(this, "Error when loading KML", Toast.LENGTH_SHORT).show(); //14. Grab overlays in KML structure, save KML document locally if (mKmlDocument.mKmlRoot != null) { KmlFolder root = mKmlDocument.mKmlRoot; root.addOverlay(roadOverlay, mKmlDocument); root.addOverlay(roadMarkers, mKmlDocument); mKmlDocument.saveAsKML(mKmlDocument.getDefaultPathForAndroid("my_route.kml")); //15. Loading and saving of GeoJSON content mKmlDocument.saveAsGeoJSON(mKmlDocument.getDefaultPathForAndroid("my_route.json")); } //16. Handling Map events MapEventsOverlay mapEventsOverlay = new MapEventsOverlay(this); map.getOverlays().add(0, mapEventsOverlay); //inserted at the "bottom" of all overlays //Testing osmdroid issue #353 - turning HW acceleration on com.example.osmbonuspacktuto.Polyline pl = new com.example.osmbonuspacktuto.Polyline(); ArrayList<GeoPoint> l = new ArrayList(); l.add(new GeoPoint(48.5, 20.0)); l.add(new GeoPoint(48.5, -20.0)); pl.setPoints(l); map.getOverlays().add(pl); com.example.osmbonuspacktuto.Polygon p = new com.example.osmbonuspacktuto.Polygon(); p.setFillColor(0xAA00FF00); l = new ArrayList(); l.add(new GeoPoint(48.0, 20.0)); l.add(new GeoPoint(48.0, -20.0)); l.add(new GeoPoint(47.0, -20.0)); l.add(new GeoPoint(47.0, 20.0)); //l.add(new GeoPoint(48.0, 160.0)); l.add(new GeoPoint(48.0, -160.0)); //intersecting 180° line p.setPoints(l); map.getOverlays().add(p); } //--- Stuff for setting the mapview on a box at startup: BoundingBox mInitialBoundingBox = null; void setInitialViewOn(BoundingBox bb) { if (map.getScreenRect(null).height() == 0) { mInitialBoundingBox = bb; map.addOnFirstLayoutListener(this); } else map.zoomToBoundingBox(bb, false); } @Override public void onFirstLayout(View v, int left, int top, int right, int bottom) { if (mInitialBoundingBox != null) map.zoomToBoundingBox(mInitialBoundingBox, false); } //--- //0. Using the Marker and Polyline overlays - advanced options class OnMarkerDragListenerDrawer implements OnMarkerDragListener { ArrayList<GeoPoint> mTrace; Polyline mPolyline; OnMarkerDragListenerDrawer() { mTrace = new ArrayList<GeoPoint>(100); mPolyline = new Polyline(); mPolyline.setColor(0xAA0000FF); mPolyline.setWidth(2.0f); mPolyline.setGeodesic(true); map.getOverlays().add(mPolyline); } @Override public void onMarkerDrag(Marker marker) { //mTrace.add(marker.getPosition()); } @Override public void onMarkerDragEnd(Marker marker) { mTrace.add(marker.getPosition()); mPolyline.setPoints(mTrace); map.invalidate(); } @Override public void onMarkerDragStart(Marker marker) { //mTrace.add(marker.getPosition()); } } //7. Customizing the bubble behaviour class CustomInfoWindow extends MarkerInfoWindow { POI mSelectedPoi; public CustomInfoWindow(MapView mapView) { super(org.osmdroid.bonuspack.R.layout.bonuspack_bubble, mapView); Button btn = (Button) (mView.findViewById(org.osmdroid.bonuspack.R.id.bubble_moreinfo)); btn.setOnClickListener(new View.OnClickListener() { public void onClick(View view) { if (mSelectedPoi.mUrl != null) { Intent myIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(mSelectedPoi.mUrl)); view.getContext().startActivity(myIntent); } else { Toast.makeText(view.getContext(), "Button clicked", Toast.LENGTH_LONG).show(); } } }); } @Override public void onOpen(Object item) { super.onOpen(item); mView.findViewById(org.osmdroid.bonuspack.R.id.bubble_moreinfo).setVisibility(View.VISIBLE); Marker marker = (Marker) item; mSelectedPoi = (POI) marker.getRelatedObject(); //8. put thumbnail image in bubble, fetching the thumbnail in background: if (mSelectedPoi.mThumbnailPath != null) { ImageView imageView = (ImageView) mView.findViewById(org.osmdroid.bonuspack.R.id.bubble_image); mSelectedPoi.fetchThumbnailOnThread(imageView); } } } //11.2 Customizing the clusters design - and beyond class CirclesGridMarkerClusterer extends RadiusMarkerClusterer { public CirclesGridMarkerClusterer(Context ctx) { super(ctx); } @Override public Marker buildClusterMarker(StaticCluster cluster, MapView mapView) { Marker m = new Marker(mapView); m.setPosition(cluster.getPosition()); m.setInfoWindow(null); m.setAnchor(0.5f, 0.5f); int radius = (int) Math.sqrt(cluster.getSize() * 3); radius = Math.max(radius, 10); radius = Math.min(radius, 30); Bitmap finalIcon = Bitmap.createBitmap(radius * 2, radius * 2, mClusterIcon.getConfig()); Canvas iconCanvas = new Canvas(finalIcon); Paint circlePaint = new Paint(); if (cluster.getSize() < 20) circlePaint.setColor(Color.BLUE); else circlePaint.setColor(Color.RED); circlePaint.setAlpha(200); iconCanvas.drawCircle(radius, radius, radius, circlePaint); String text = "" + cluster.getSize(); int textHeight = (int) (mTextPaint.descent() + mTextPaint.ascent()); iconCanvas.drawText(text, mTextAnchorU * finalIcon.getWidth(), mTextAnchorV * finalIcon.getHeight() - textHeight / 2, mTextPaint); m.setIcon(new BitmapDrawable(mapView.getContext().getResources(), finalIcon)); return m; } } //13.2 Loading KML content - Advanced styling with Styler class MyKmlStyler implements KmlFeature.Styler { Style mDefaultStyle; MyKmlStyler(Style defaultStyle) { mDefaultStyle = defaultStyle; } @Override public void onLineString(Polyline polyline, KmlPlacemark kmlPlacemark, KmlLineString kmlLineString) { //Custom styling: polyline.setColor(Color.GREEN); polyline.setWidth(Math.max(kmlLineString.mCoordinates.size() / 200.0f, 3.0f)); } @Override public void onPolygon(Polygon polygon, KmlPlacemark kmlPlacemark, KmlPolygon kmlPolygon) { //Keeping default styling: kmlPolygon.applyDefaultStyling(polygon, mDefaultStyle, kmlPlacemark, mKmlDocument, map); } @Override public void onTrack(Polyline polyline, KmlPlacemark kmlPlacemark, KmlTrack kmlTrack) { //Keeping default styling: kmlTrack.applyDefaultStyling(polyline, mDefaultStyle, kmlPlacemark, mKmlDocument, map); } @Override public void onPoint(Marker marker, KmlPlacemark kmlPlacemark, KmlPoint kmlPoint) { //Styling based on ExtendedData properties: if (kmlPlacemark.getExtendedData("maxspeed") != null) kmlPlacemark.mStyle = "maxspeed"; kmlPoint.applyDefaultStyling(marker, mDefaultStyle, kmlPlacemark, mKmlDocument, map); } @Override public void onFeature(Overlay overlay, KmlFeature kmlFeature) { //If nothing to do, do nothing. } } //16. Handling Map events @Override public boolean singleTapConfirmedHelper(GeoPoint p) { Toast.makeText(this, "Tap on (" + p.getLatitude() + "," + p.getLongitude() + ")", Toast.LENGTH_SHORT).show(); InfoWindow.closeAllInfoWindowsOn(map); return true; } float mGroundOverlayBearing = 0.0f; @Override public boolean longPressHelper(GeoPoint p) { //Toast.makeText(this, "Long press", Toast.LENGTH_SHORT).show(); //17. Using Polygon, defined as a circle: Polygon circle = new Polygon(); circle.setPoints(Polygon.pointsAsCircle(p, 2000.0)); circle.setFillColor(0x12121212); circle.setStrokeColor(Color.RED); circle.setStrokeWidth(2); map.getOverlays().add(circle); circle.setInfoWindow(new BasicInfoWindow(org.osmdroid.bonuspack.R.layout.bonuspack_bubble, map)); circle.setTitle("Centered on " + p.getLatitude() + "," + p.getLongitude()); //18. Using GroundOverlay GroundOverlay myGroundOverlay = new GroundOverlay(); myGroundOverlay.setPosition(p); Drawable d = ResourcesCompat.getDrawable(getResources(), R.drawable.ic_launcher, null); myGroundOverlay.setImage(d.mutate()); myGroundOverlay.setDimensions(2000.0f); //myGroundOverlay.setTransparency(0.25f); myGroundOverlay.setBearing(mGroundOverlayBearing); mGroundOverlayBearing += 20.0f; map.getOverlays().add(myGroundOverlay); map.invalidate(); return true; } }