package net.osmand.aidl; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.net.Uri; import android.os.ParcelFileDescriptor; import android.view.View; import net.osmand.IndexConstants; import net.osmand.aidl.gpx.ASelectedGpxFile; import net.osmand.aidl.maplayer.AMapLayer; import net.osmand.aidl.maplayer.point.AMapPoint; import net.osmand.aidl.mapmarker.AMapMarker; import net.osmand.aidl.mapwidget.AMapWidget; import net.osmand.data.LatLon; import net.osmand.data.PointDescription; import net.osmand.plus.GPXUtilities; import net.osmand.plus.GPXUtilities.GPXFile; import net.osmand.plus.GpxSelectionHelper.SelectedGpxFile; import net.osmand.plus.MapMarkersHelper; import net.osmand.plus.MapMarkersHelper.MapMarker; import net.osmand.plus.OsmandApplication; import net.osmand.plus.activities.MapActivity; import net.osmand.plus.views.AidlMapLayer; import net.osmand.plus.views.MapInfoLayer; import net.osmand.plus.views.OsmandMapLayer; import net.osmand.plus.views.OsmandMapLayer.DrawSettings; import net.osmand.plus.views.OsmandMapTileView; import net.osmand.plus.views.mapwidgets.MapWidgetRegistry.MapWidgetRegInfo; import net.osmand.plus.views.mapwidgets.TextInfoWidget; import net.osmand.util.Algorithms; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileDescriptor; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; public class OsmandAidlApi { private static final String AIDL_REFRESH_MAP = "aidl_refresh_map"; private static final String AIDL_SET_MAP_LOCATION = "aidl_set_map_location"; private static final String AIDL_LATITUDE = "aidl_latitude"; private static final String AIDL_LONGITUDE = "aidl_longitude"; private static final String AIDL_ZOOM = "aidl_zoom"; private static final String AIDL_ANIMATED = "aidl_animated"; private static final String AIDL_OBJECT_ID = "aidl_object_id"; private static final String AIDL_ADD_MAP_WIDGET = "aidl_add_map_widget"; private static final String AIDL_REMOVE_MAP_WIDGET = "aidl_remove_map_widget"; private static final String AIDL_ADD_MAP_LAYER = "aidl_add_map_layer"; private static final String AIDL_REMOVE_MAP_LAYER = "aidl_remove_map_layer"; private OsmandApplication app; private Map<String, AMapWidget> widgets = new ConcurrentHashMap<>(); private Map<String, TextInfoWidget> widgetControls = new ConcurrentHashMap<>(); private Map<String, AMapLayer> layers = new ConcurrentHashMap<>(); private Map<String, OsmandMapLayer> mapLayers = new ConcurrentHashMap<>(); private BroadcastReceiver refreshMapReceiver; private BroadcastReceiver setMapLocationReceiver; private BroadcastReceiver addMapWidgetReceiver; private BroadcastReceiver removeMapWidgetReceiver; private BroadcastReceiver addMapLayerReceiver; private BroadcastReceiver removeMapLayerReceiver; public OsmandAidlApi(OsmandApplication app) { this.app = app; } public void onCreateMapActivity(final MapActivity mapActivity) { registerRefreshMapReceiver(mapActivity); registerSetMapLocationReceiver(mapActivity); registerAddMapWidgetReceiver(mapActivity); registerRemoveMapWidgetReceiver(mapActivity); registerAddMapLayerReceiver(mapActivity); registerRemoveMapLayerReceiver(mapActivity); } public void onDestroyMapActivity(final MapActivity mapActivity) { if (refreshMapReceiver != null) { mapActivity.unregisterReceiver(refreshMapReceiver); } if (setMapLocationReceiver != null) { mapActivity.unregisterReceiver(setMapLocationReceiver); } if (addMapWidgetReceiver != null) { mapActivity.unregisterReceiver(addMapWidgetReceiver); } if (removeMapWidgetReceiver != null) { mapActivity.unregisterReceiver(removeMapWidgetReceiver); } widgetControls.clear(); if (addMapLayerReceiver != null) { mapActivity.unregisterReceiver(addMapLayerReceiver); } if (removeMapLayerReceiver != null) { mapActivity.unregisterReceiver(removeMapLayerReceiver); } } private void registerRefreshMapReceiver(final MapActivity mapActivity) { refreshMapReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { mapActivity.refreshMap(); } }; mapActivity.registerReceiver(refreshMapReceiver, new IntentFilter(AIDL_REFRESH_MAP)); } private void registerSetMapLocationReceiver(final MapActivity mapActivity) { setMapLocationReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { double lat = intent.getDoubleExtra(AIDL_LATITUDE, Double.NaN); double lon = intent.getDoubleExtra(AIDL_LONGITUDE, Double.NaN); int zoom = intent.getIntExtra(AIDL_ZOOM, 0); boolean animated = intent.getBooleanExtra(AIDL_ANIMATED, false); if (!Double.isNaN(lat) && !Double.isNaN(lon)) { OsmandMapTileView mapView = mapActivity.getMapView(); if (zoom == 0) { zoom = mapView.getZoom(); } else { zoom = zoom > mapView.getMaxZoom() ? mapView.getMaxZoom() : zoom; zoom = zoom < mapView.getMinZoom() ? mapView.getMinZoom() : zoom; } if (animated) { mapView.getAnimatedDraggingThread().startMoving(lat, lon, zoom, true); } else { mapView.setLatLon(lat, lon); mapView.setIntZoom(zoom); } } mapActivity.refreshMap(); } }; mapActivity.registerReceiver(setMapLocationReceiver, new IntentFilter(AIDL_SET_MAP_LOCATION)); } private int getDrawableId(String id) { if (Algorithms.isEmpty(id)) { return 0; } else { return app.getResources().getIdentifier(id, "drawable", app.getPackageName()); } } private void registerAddMapWidgetReceiver(final MapActivity mapActivity) { addMapWidgetReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String widgetId = intent.getStringExtra(AIDL_OBJECT_ID); if (widgetId != null) { AMapWidget widget = widgets.get(widgetId); if (widget != null) { MapInfoLayer layer = mapActivity.getMapLayers().getMapInfoLayer(); if (layer != null) { TextInfoWidget control = createWidgetControl(mapActivity, widgetId); widgetControls.put(widgetId, control); int menuIconId = getDrawableId(widget.getMenuIconName()); MapWidgetRegInfo widgetInfo = layer.registerSideWidget(control, menuIconId, widget.getMenuTitle(), "aidl_widget_" + widgetId, false, widget.getOrder()); if (!mapActivity.getMapLayers().getMapWidgetRegistry().isVisible(widgetInfo.key)) { mapActivity.getMapLayers().getMapWidgetRegistry().setVisibility(widgetInfo, true, false); } layer.recreateControls(); } } } } }; mapActivity.registerReceiver(addMapWidgetReceiver, new IntentFilter(AIDL_ADD_MAP_WIDGET)); } private void registerRemoveMapWidgetReceiver(final MapActivity mapActivity) { removeMapWidgetReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String widgetId = intent.getStringExtra(AIDL_OBJECT_ID); if (widgetId != null) { MapInfoLayer layer = mapActivity.getMapLayers().getMapInfoLayer(); TextInfoWidget widgetControl = widgetControls.get(widgetId); if (layer != null && widgetControl != null) { layer.removeSideWidget(widgetControl); widgetControls.remove(widgetId); layer.recreateControls(); } } } }; mapActivity.registerReceiver(removeMapWidgetReceiver, new IntentFilter(AIDL_REMOVE_MAP_WIDGET)); } public void registerWidgetControls(MapActivity mapActivity) { for (AMapWidget widget : widgets.values()) { MapInfoLayer layer = mapActivity.getMapLayers().getMapInfoLayer(); if (layer != null) { TextInfoWidget control = createWidgetControl(mapActivity, widget.getId()); widgetControls.put(widget.getId(), control); int menuIconId = getDrawableId(widget.getMenuIconName()); MapWidgetRegInfo widgetInfo = layer.registerSideWidget(control, menuIconId, widget.getMenuTitle(), "aidl_widget_" + widget.getId(), false, widget.getOrder()); if (!mapActivity.getMapLayers().getMapWidgetRegistry().isVisible(widgetInfo.key)) { mapActivity.getMapLayers().getMapWidgetRegistry().setVisibility(widgetInfo, true, false); } } } } private void registerAddMapLayerReceiver(final MapActivity mapActivity) { addMapLayerReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String layerId = intent.getStringExtra(AIDL_OBJECT_ID); if (layerId != null) { AMapLayer layer = layers.get(layerId); if (layer != null) { OsmandMapLayer mapLayer = mapLayers.get(layerId); if (mapLayer != null) { mapActivity.getMapView().removeLayer(mapLayer); } mapLayer = new AidlMapLayer(mapActivity, layer); mapActivity.getMapView().addLayer(mapLayer, layer.getZOrder()); mapLayers.put(layerId, mapLayer); } } } }; mapActivity.registerReceiver(addMapLayerReceiver, new IntentFilter(AIDL_ADD_MAP_LAYER)); } private void registerRemoveMapLayerReceiver(final MapActivity mapActivity) { removeMapLayerReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String layerId = intent.getStringExtra(AIDL_OBJECT_ID); if (layerId != null) { OsmandMapLayer mapLayer = mapLayers.remove(layerId); if (mapLayer != null) { mapActivity.getMapView().removeLayer(mapLayer); mapActivity.refreshMap(); } } } }; mapActivity.registerReceiver(removeMapLayerReceiver, new IntentFilter(AIDL_REMOVE_MAP_LAYER)); } public void registerMapLayers(MapActivity mapActivity) { for (AMapLayer layer : layers.values()) { OsmandMapLayer mapLayer = mapLayers.get(layer.getId()); if (mapLayer != null) { mapActivity.getMapView().removeLayer(mapLayer); } mapLayer = new AidlMapLayer(mapActivity, layer); mapActivity.getMapView().addLayer(mapLayer, layer.getZOrder()); mapLayers.put(layer.getId(), mapLayer); } } private void refreshMap() { Intent intent = new Intent(); intent.setAction(AIDL_REFRESH_MAP); app.sendBroadcast(intent); } private TextInfoWidget createWidgetControl(final MapActivity mapActivity, final String widgetId) { final TextInfoWidget control = new TextInfoWidget(mapActivity) { @Override public boolean updateInfo(DrawSettings drawSettings) { AMapWidget widget = widgets.get(widgetId); if (widget != null) { String txt = widget.getText(); String subtxt = widget.getDescription(); boolean night = drawSettings != null && drawSettings.isNightMode(); int icon = night ? getDrawableId(widget.getDarkIconName()) : getDrawableId(widget.getLightIconName()); setText(txt, subtxt); if (icon != 0) { setImageDrawable(icon); } else { setImageDrawable(null); } return true; } else { return false; } } }; control.updateInfo(null); control.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { AMapWidget widget = widgets.get(widgetId); if (widget != null && widget.getIntentOnClick() != null) { app.startActivity(widget.getIntentOnClick()); } } }); return control; } boolean addMapMarker(AMapMarker marker) { if (marker != null) { PointDescription pd = new PointDescription( PointDescription.POINT_TYPE_MAP_MARKER, marker.getName() != null ? marker.getName() : ""); MapMarkersHelper markersHelper = app.getMapMarkersHelper(); markersHelper.addMapMarker(new LatLon(marker.getLatLon().getLatitude(), marker.getLatLon().getLongitude()), pd); refreshMap(); return true; } else { return false; } } boolean removeMapMarker(AMapMarker marker) { if (marker != null) { LatLon latLon = new LatLon(marker.getLatLon().getLatitude(), marker.getLatLon().getLongitude()); MapMarkersHelper markersHelper = app.getMapMarkersHelper(); List<MapMarker> mapMarkers = markersHelper.getMapMarkers(); for (MapMarker m : mapMarkers) { if (m.getOnlyName().equals(marker.getName()) && latLon.equals(new LatLon(m.getLatitude(), m.getLongitude()))) { markersHelper.removeMapMarker(m); refreshMap(); return true; } } return false; } else { return false; } } boolean updateMapMarker(AMapMarker markerPrev, AMapMarker markerNew) { if (markerPrev != null && markerNew != null) { LatLon latLon = new LatLon(markerPrev.getLatLon().getLatitude(), markerPrev.getLatLon().getLongitude()); LatLon latLonNew = new LatLon(markerNew.getLatLon().getLatitude(), markerNew.getLatLon().getLongitude()); MapMarkersHelper markersHelper = app.getMapMarkersHelper(); List<MapMarker> mapMarkers = markersHelper.getMapMarkers(); for (MapMarker m : mapMarkers) { if (m.getOnlyName().equals(markerPrev.getName()) && latLon.equals(new LatLon(m.getLatitude(), m.getLongitude()))) { PointDescription pd = new PointDescription( PointDescription.POINT_TYPE_MAP_MARKER, markerNew.getName() != null ? markerNew.getName() : ""); MapMarker marker = new MapMarker(m.point, pd, m.colorIndex, m.selected, m.index); markersHelper.moveMapMarker(marker, latLonNew); refreshMap(); return true; } } return false; } else { return false; } } boolean addMapWidget(AMapWidget widget) { if (widget != null) { if (widgets.containsKey(widget.getId())) { updateMapWidget(widget); } else { widgets.put(widget.getId(), widget); Intent intent = new Intent(); intent.setAction(AIDL_ADD_MAP_WIDGET); intent.putExtra(AIDL_OBJECT_ID, widget.getId()); app.sendBroadcast(intent); } refreshMap(); return true; } else { return false; } } boolean removeMapWidget(String widgetId) { if (!Algorithms.isEmpty(widgetId) && widgets.containsKey(widgetId)) { widgets.remove(widgetId); Intent intent = new Intent(); intent.setAction(AIDL_REMOVE_MAP_WIDGET); intent.putExtra(AIDL_OBJECT_ID, widgetId); app.sendBroadcast(intent); return true; } else { return false; } } boolean updateMapWidget(AMapWidget widget) { if (widget != null && widgets.containsKey(widget.getId())) { widgets.put(widget.getId(), widget); refreshMap(); return true; } else { return false; } } boolean addMapLayer(AMapLayer layer) { if (layer != null) { if (layers.containsKey(layer.getId())) { updateMapLayer(layer); } else { layers.put(layer.getId(), layer); Intent intent = new Intent(); intent.setAction(AIDL_ADD_MAP_LAYER); intent.putExtra(AIDL_OBJECT_ID, layer.getId()); app.sendBroadcast(intent); } refreshMap(); return true; } else { return false; } } boolean removeMapLayer(String layerId) { if (!Algorithms.isEmpty(layerId) && layers.containsKey(layerId)) { layers.remove(layerId); Intent intent = new Intent(); intent.setAction(AIDL_REMOVE_MAP_LAYER); intent.putExtra(AIDL_OBJECT_ID, layerId); app.sendBroadcast(intent); return true; } else { return false; } } boolean updateMapLayer(AMapLayer layer) { if (layer != null && layers.containsKey(layer.getId())) { layers.put(layer.getId(), layer); refreshMap(); return true; } else { return false; } } boolean putMapPoint(String layerId, AMapPoint point) { if (point != null) { AMapLayer layer = layers.get(layerId); if (layer != null) { layer.putPoint(point); refreshMap(); return true; } } return false; } boolean removeMapPoint(String layerId, String pointId) { if (pointId != null) { AMapLayer layer = layers.get(layerId); if (layer != null) { layer.removePoint(pointId); refreshMap(); return true; } } return false; } boolean importGpxFromFile(File source, String destinationPath) { if (source != null && !Algorithms.isEmpty(destinationPath)) { if (source.exists() && source.canRead()) { File destination = app.getAppPath(IndexConstants.GPX_INDEX_DIR + destinationPath); if (destination.getParentFile().canWrite()) { try { Algorithms.fileCopy(source, destination); return true; } catch (IOException e) { e.printStackTrace(); } } } } return false; } boolean importGpxFromUri(Uri gpxUri, String destinationPath) { if (gpxUri != null && !Algorithms.isEmpty(destinationPath)) { File destination = app.getAppPath(IndexConstants.GPX_INDEX_DIR + destinationPath); ParcelFileDescriptor gpxParcelDescriptor = null; try { gpxParcelDescriptor = app.getContentResolver().openFileDescriptor(gpxUri, "r"); if (gpxParcelDescriptor != null) { FileDescriptor fileDescriptor = gpxParcelDescriptor.getFileDescriptor(); InputStream is = new FileInputStream(fileDescriptor); FileOutputStream fout = new FileOutputStream(destination); try { Algorithms.streamCopy(is, fout); } finally { try { is.close(); } catch (IOException e) { e.printStackTrace(); } try { fout.close(); } catch (IOException e) { e.printStackTrace(); } } return true; } } catch (IOException e) { e.printStackTrace(); } } return false; } boolean importGpxFromData(String sourceRawData, String destinationPath) { if (!Algorithms.isEmpty(sourceRawData) && !Algorithms.isEmpty(destinationPath)) { File destination = app.getAppPath(IndexConstants.GPX_INDEX_DIR + destinationPath); try { InputStream is = new ByteArrayInputStream(sourceRawData.getBytes()); FileOutputStream fout = new FileOutputStream(destination); try { Algorithms.streamCopy(is, fout); } finally { try { is.close(); } catch (IOException e) { e.printStackTrace(); } try { fout.close(); } catch (IOException e) { e.printStackTrace(); } } return true; } catch (IOException e) { e.printStackTrace(); } } return false; } boolean showGpx(String fileName) { if (!Algorithms.isEmpty(fileName)) { File f = app.getAppPath(IndexConstants.GPX_INDEX_DIR + fileName); if (f.exists()) { GPXFile gpx = GPXUtilities.loadGPXFile(app, f); app.getSelectedGpxHelper().selectGpxFile(gpx, true, false); refreshMap(); return true; } } return false; } boolean hideGpx(String fileName) { if (!Algorithms.isEmpty(fileName)) { SelectedGpxFile selectedGpxFile = app.getSelectedGpxHelper().getSelectedFileByName(fileName); if (selectedGpxFile != null) { app.getSelectedGpxHelper().selectGpxFile(selectedGpxFile.getGpxFile(), false, false); refreshMap(); } } return false; } boolean getActiveGpx(List<ASelectedGpxFile> files) { if (files != null) { List<SelectedGpxFile> selectedGpxFiles = app.getSelectedGpxHelper().getSelectedGPXFiles(); String gpxPath = app.getAppPath(IndexConstants.GPX_INDEX_DIR).getAbsolutePath(); for (SelectedGpxFile selectedGpxFile : selectedGpxFiles) { String path = selectedGpxFile.getGpxFile().path; if (!Algorithms.isEmpty(path)) { if (path.startsWith(gpxPath)) { path = path.substring(gpxPath.length() + 1); } files.add(new ASelectedGpxFile(path)); } } return true; } return false; } boolean setMapLocation(double latitude, double longitude, int zoom, boolean animated) { Intent intent = new Intent(); intent.setAction(AIDL_SET_MAP_LOCATION); intent.putExtra(AIDL_LATITUDE, latitude); intent.putExtra(AIDL_LONGITUDE, longitude); intent.putExtra(AIDL_ZOOM, zoom); intent.putExtra(AIDL_ANIMATED, animated); app.sendBroadcast(intent); return true; } }