package net.osmand.plus.activities; import android.content.DialogInterface; import android.graphics.drawable.Drawable; import android.support.v7.app.AlertDialog; import android.view.View; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.ListView; import android.widget.Toast; import net.osmand.CallbackWithObject; import net.osmand.ResultMatcher; import net.osmand.StateChangedListener; import net.osmand.map.ITileSource; import net.osmand.map.TileSourceManager.TileSourceTemplate; import net.osmand.plus.ContextMenuAdapter; import net.osmand.plus.ContextMenuItem; import net.osmand.plus.GPXUtilities.GPXFile; import net.osmand.plus.GPXUtilities.WptPt; import net.osmand.plus.OsmandApplication; import net.osmand.plus.OsmandPlugin; import net.osmand.plus.OsmandSettings; import net.osmand.plus.OsmandSettings.CommonPreference; import net.osmand.plus.R; import net.osmand.plus.SQLiteTileSource; import net.osmand.plus.activities.MapActivity.ShowQuickSearchMode; import net.osmand.plus.helpers.GpxUiHelper; import net.osmand.plus.poi.PoiFiltersHelper; import net.osmand.plus.poi.PoiUIFilter; import net.osmand.plus.quickaction.QuickActionRegistry; import net.osmand.plus.rastermaps.OsmandRasterMapsPlugin; import net.osmand.plus.render.MapVectorLayer; import net.osmand.plus.render.RenderingIcons; import net.osmand.plus.routing.RoutingHelper; import net.osmand.plus.views.ContextMenuLayer; import net.osmand.plus.views.DownloadedRegionsLayer; import net.osmand.plus.views.FavouritesLayer; import net.osmand.plus.views.GPXLayer; import net.osmand.plus.views.ImpassableRoadsLayer; import net.osmand.plus.views.MapControlsLayer; import net.osmand.plus.views.MapInfoLayer; import net.osmand.plus.views.MapMarkersLayer; import net.osmand.plus.views.MapQuickActionLayer; import net.osmand.plus.views.MapTextLayer; import net.osmand.plus.views.MapTileLayer; import net.osmand.plus.views.OsmandMapTileView; import net.osmand.plus.views.POIMapLayer; import net.osmand.plus.views.PointLocationLayer; import net.osmand.plus.views.PointNavigationLayer; import net.osmand.plus.views.RouteLayer; import net.osmand.plus.views.TransportStopsLayer; import net.osmand.plus.views.mapwidgets.MapWidgetRegistry; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map.Entry; /** * Object is responsible to maintain layers using by map activity */ public class MapActivityLayers { private final MapActivity activity; // the order of layer should be preserved ! when you are inserting new layer private MapTileLayer mapTileLayer; private MapVectorLayer mapVectorLayer; private GPXLayer gpxLayer; private RouteLayer routeLayer; private POIMapLayer poiMapLayer; private FavouritesLayer mFavouritesLayer; private TransportStopsLayer transportStopsLayer; private PointLocationLayer locationLayer; private PointNavigationLayer navigationLayer; private MapMarkersLayer mapMarkersLayer; private ImpassableRoadsLayer impassableRoadsLayer; private MapInfoLayer mapInfoLayer; private MapTextLayer mapTextLayer; private ContextMenuLayer contextMenuLayer; private MapControlsLayer mapControlsLayer; private MapQuickActionLayer mapQuickActionLayer; private DownloadedRegionsLayer downloadedRegionsLayer; private MapWidgetRegistry mapWidgetRegistry; private QuickActionRegistry quickActionRegistry; private StateChangedListener<Integer> transparencyListener; public MapActivityLayers(MapActivity activity) { this.activity = activity; this.mapWidgetRegistry = new MapWidgetRegistry(activity.getMyApplication().getSettings()); this.quickActionRegistry = new QuickActionRegistry(activity.getMyApplication().getSettings()); } public QuickActionRegistry getQuickActionRegistry() { return quickActionRegistry; } public MapWidgetRegistry getMapWidgetRegistry() { return mapWidgetRegistry; } public OsmandApplication getApplication() { return (OsmandApplication) activity.getApplication(); } public void createLayers(final OsmandMapTileView mapView) { OsmandApplication app = getApplication(); RoutingHelper routingHelper = app.getRoutingHelper(); // first create to make accessible mapTextLayer = new MapTextLayer(); // 5.95 all labels mapView.addLayer(mapTextLayer, 5.95f); // 8. context menu layer contextMenuLayer = new ContextMenuLayer(activity); mapView.addLayer(contextMenuLayer, 8); // mapView.addLayer(underlayLayer, -0.5f); mapTileLayer = new MapTileLayer(true); mapView.addLayer(mapTileLayer, 0.0f); mapView.setMainLayer(mapTileLayer); // 0.5 layer mapVectorLayer = new MapVectorLayer(mapTileLayer, false); mapView.addLayer(mapVectorLayer, 0.5f); downloadedRegionsLayer = new DownloadedRegionsLayer(); mapView.addLayer(downloadedRegionsLayer, 0.5f); // 0.9 gpx layer gpxLayer = new GPXLayer(); mapView.addLayer(gpxLayer, 0.9f); // 1. route layer routeLayer = new RouteLayer(routingHelper); mapView.addLayer(routeLayer, 1); // 2. osm bugs layer // 3. poi layer poiMapLayer = new POIMapLayer(activity); mapView.addLayer(poiMapLayer, 3); // 4. favorites layer mFavouritesLayer = new FavouritesLayer(); mapView.addLayer(mFavouritesLayer, 4); // 5. transport layer transportStopsLayer = new TransportStopsLayer(activity); mapView.addLayer(transportStopsLayer, 5); // 5.95 all text labels // 6. point location layer locationLayer = new PointLocationLayer(activity.getMapViewTrackingUtilities()); mapView.addLayer(locationLayer, 6); // 7. point navigation layer navigationLayer = new PointNavigationLayer(activity); mapView.addLayer(navigationLayer, 7); // 7.3 map markers layer mapMarkersLayer = new MapMarkersLayer(activity); mapView.addLayer(mapMarkersLayer, 7.3f); // 7.5 Impassible roads impassableRoadsLayer = new ImpassableRoadsLayer(activity); mapView.addLayer(impassableRoadsLayer, 7.5f); // 8. context menu layer // 9. map info layer mapInfoLayer = new MapInfoLayer(activity, routeLayer); mapView.addLayer(mapInfoLayer, 9); // 11. route info layer mapControlsLayer = new MapControlsLayer(activity); mapView.addLayer(mapControlsLayer, 11); // 12. quick actions layer mapQuickActionLayer = new MapQuickActionLayer(activity, contextMenuLayer); mapView.addLayer(mapQuickActionLayer, 12); contextMenuLayer.setMapQuickActionLayer(mapQuickActionLayer); mapControlsLayer.setMapQuickActionLayer(mapQuickActionLayer); transparencyListener = new StateChangedListener<Integer>() { @Override public void stateChanged(Integer change) { mapTileLayer.setAlpha(change); mapVectorLayer.setAlpha(change); mapView.refreshMap(); } }; app.getSettings().MAP_TRANSPARENCY.addListener(transparencyListener); OsmandPlugin.createLayers(mapView, activity); app.getAppCustomization().createLayers(mapView, activity); app.getAidlApi().registerMapLayers(activity); } public void updateLayers(OsmandMapTileView mapView) { OsmandSettings settings = getApplication().getSettings(); updateMapSource(mapView, settings.MAP_TILE_SOURCES); boolean showStops = settings.getCustomRenderBooleanProperty(OsmandSettings.TRANSPORT_STOPS_OVER_MAP).get(); transportStopsLayer.setShowTransportStops(showStops); OsmandPlugin.refreshLayers(mapView, activity); } public void updateMapSource(OsmandMapTileView mapView, CommonPreference<String> settingsToWarnAboutMap) { OsmandSettings settings = getApplication().getSettings(); // update transparency int mapTransparency = settings.MAP_UNDERLAY.get() == null ? 255 : settings.MAP_TRANSPARENCY.get(); mapTileLayer.setAlpha(mapTransparency); mapVectorLayer.setAlpha(mapTransparency); ITileSource newSource = settings.getMapTileSource(settings.MAP_TILE_SOURCES == settingsToWarnAboutMap); ITileSource oldMap = mapTileLayer.getMap(); if (newSource != oldMap) { if (oldMap instanceof SQLiteTileSource) { ((SQLiteTileSource) oldMap).closeDB(); } mapTileLayer.setMap(newSource); } boolean vectorData = !settings.MAP_ONLINE_DATA.get(); mapTileLayer.setVisible(!vectorData); mapVectorLayer.setVisible(vectorData); if (vectorData) { mapView.setMainLayer(mapVectorLayer); } else { mapView.setMainLayer(mapTileLayer); } } public AlertDialog showGPXFileLayer(List<String> files, final OsmandMapTileView mapView) { final OsmandSettings settings = getApplication().getSettings(); CallbackWithObject<GPXFile[]> callbackWithObject = new CallbackWithObject<GPXFile[]>() { @Override public boolean processResult(GPXFile[] result) { WptPt locToShow = null; for (GPXFile g : result) { if (g.showCurrentTrack) { if (!settings.SAVE_TRACK_TO_GPX.get() && ! settings.SAVE_GLOBAL_TRACK_TO_GPX.get()) { Toast.makeText(activity, R.string.gpx_monitoring_disabled_warn, Toast.LENGTH_LONG).show(); } break; } else { locToShow = g.findPointToShow(); } } getApplication().getSelectedGpxHelper().setGpxFileToDisplay(result); if (locToShow != null) { mapView.getAnimatedDraggingThread().startMoving(locToShow.lat, locToShow.lon, mapView.getZoom(), true); } mapView.refreshMap(); activity.getDashboard().refreshContent(true); return true; } }; return GpxUiHelper.selectGPXFiles(files, activity, callbackWithObject); } public void showMultichoicePoiFilterDialog(final OsmandMapTileView mapView, final DismissListener listener) { final OsmandApplication app = getApplication(); final PoiFiltersHelper poiFilters = app.getPoiFilters(); final ContextMenuAdapter adapter = new ContextMenuAdapter(); final List<PoiUIFilter> list = new ArrayList<>(); for (PoiUIFilter f : poiFilters.getTopDefinedPoiFilters()) { addFilterToList(adapter, list, f, true); } for (PoiUIFilter f : poiFilters.getSearchPoiFilters()) { addFilterToList(adapter, list, f, true); } list.add(poiFilters.getCustomPOIFilter()); final ArrayAdapter<ContextMenuItem> listAdapter = adapter.createListAdapter(activity, app.getSettings().isLightContent()); AlertDialog.Builder builder = new AlertDialog.Builder(activity); final ListView listView = new ListView(activity); listView.setDivider(null); listView.setClickable(true); listView.setAdapter(listAdapter); listView.setOnItemClickListener(new ListView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { ContextMenuItem item = listAdapter.getItem(position); item.setSelected(!item.getSelected()); item.getItemClickListener().onContextMenuClick(listAdapter, position, position, item.getSelected()); listAdapter.notifyDataSetChanged(); } }); builder.setView(listView) .setTitle(R.string.show_poi_over_map) .setPositiveButton(R.string.shared_string_ok, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { for (int i = 0; i < listAdapter.getCount(); i++) { ContextMenuItem item = listAdapter.getItem(i); PoiUIFilter filter = list.get(i); if (item.getSelected()) { getApplication().getPoiFilters().addSelectedPoiFilter(filter); } else { getApplication().getPoiFilters().removeSelectedPoiFilter(filter); } } mapView.refreshMap(); } }) .setNegativeButton(R.string.shared_string_cancel, null) // TODO go to single choice dialog .setNeutralButton(" ", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { showSingleChoicePoiFilterDialog(mapView, listener); } }); final AlertDialog alertDialog = builder.create(); alertDialog.setOnShowListener(new DialogInterface.OnShowListener() { @Override public void onShow(DialogInterface dialog) { Button neutralButton = alertDialog.getButton(DialogInterface.BUTTON_NEUTRAL); Drawable drawable = app.getIconsCache().getThemedIcon(R.drawable.ic_action_singleselect); neutralButton.setCompoundDrawablesWithIntrinsicBounds(drawable, null, null, null); neutralButton.setContentDescription(app.getString(R.string.shared_string_filters)); } }); alertDialog.setOnDismissListener(new DialogInterface.OnDismissListener() { @Override public void onDismiss(DialogInterface dialog) { listener.dismiss(); } }); alertDialog.show(); } public void showSingleChoicePoiFilterDialog(final OsmandMapTileView mapView, final DismissListener listener) { final OsmandApplication app = getApplication(); final PoiFiltersHelper poiFilters = app.getPoiFilters(); final ContextMenuAdapter adapter = new ContextMenuAdapter(); adapter.addItem(new ContextMenuItem.ItemBuilder() .setTitleId(R.string.shared_string_search, app) .setIcon(R.drawable.ic_action_search_dark).createItem()); final List<PoiUIFilter> list = new ArrayList<>(); list.add(poiFilters.getCustomPOIFilter()); for (PoiUIFilter f : poiFilters.getTopDefinedPoiFilters()) { addFilterToList(adapter, list, f, false); } for (PoiUIFilter f : poiFilters.getSearchPoiFilters()) { addFilterToList(adapter, list, f, false); } final ArrayAdapter<ContextMenuItem> listAdapter = adapter.createListAdapter(activity, app.getSettings().isLightContent()); AlertDialog.Builder builder = new AlertDialog.Builder(activity); builder.setAdapter(listAdapter, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { PoiUIFilter pf = list.get(which); String filterId = pf.getFilterId(); if (filterId.equals(PoiUIFilter.CUSTOM_FILTER_ID)) { if (activity.getDashboard().isVisible()) { activity.getDashboard().hideDashboard(); } activity.showQuickSearch(ShowQuickSearchMode.NEW, true); } else { getApplication().getPoiFilters().clearSelectedPoiFilters(); getApplication().getPoiFilters().addSelectedPoiFilter(pf); mapView.refreshMap(); } } }); builder.setTitle(R.string.show_poi_over_map); builder.setNegativeButton(R.string.shared_string_dismiss, null); builder.setNeutralButton(" ", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { showMultichoicePoiFilterDialog(mapView, listener); } }); final AlertDialog alertDialog = builder.create(); alertDialog.setOnShowListener(new DialogInterface.OnShowListener() { @Override public void onShow(DialogInterface dialog) { Button neutralButton = alertDialog.getButton(DialogInterface.BUTTON_NEUTRAL); Drawable drawable = app.getIconsCache().getThemedIcon(R.drawable.ic_action_multiselect); neutralButton.setCompoundDrawablesWithIntrinsicBounds(drawable, null, null, null); neutralButton.setContentDescription(app.getString(R.string.apply_filters)); } }); alertDialog.setOnDismissListener(new DialogInterface.OnDismissListener() { @Override public void onDismiss(DialogInterface dialog) { listener.dismiss(); } }); alertDialog.show(); } private void addFilterToList(final ContextMenuAdapter adapter, final List<PoiUIFilter> list, final PoiUIFilter f, boolean multichoice) { list.add(f); ContextMenuItem.ItemBuilder builder = new ContextMenuItem.ItemBuilder(); if (multichoice) { builder.setSelected(getApplication().getPoiFilters().isPoiFilterSelected(f)); builder.setListener(new ContextMenuAdapter.ItemClickListener() { @Override public boolean onContextMenuClick(ArrayAdapter<ContextMenuItem> adapter, int itemId, int position, boolean isChecked) { ContextMenuItem item = adapter.getItem(position); item.setSelected(isChecked); return false; } }); } builder.setTitle(f.getName()); if (RenderingIcons.containsBigIcon(f.getIconId())) { builder.setIcon(RenderingIcons.getBigIconResourceId(f.getIconId())); } else { builder.setIcon(R.drawable.mx_user_defined); } builder.setColor(ContextMenuItem.INVALID_ID); builder.setSkipPaintingWithoutColor(true); adapter.addItem(builder.createItem()); } public void selectMapLayer(final OsmandMapTileView mapView, final ContextMenuItem it, final ArrayAdapter<ContextMenuItem> adapter) { if (OsmandPlugin.getEnabledPlugin(OsmandRasterMapsPlugin.class) == null) { Toast.makeText(activity, R.string.map_online_plugin_is_not_installed, Toast.LENGTH_LONG).show(); return; } final OsmandSettings settings = getApplication().getSettings(); final LinkedHashMap<String, String> entriesMap = new LinkedHashMap<>(); final String layerOsmVector = "LAYER_OSM_VECTOR"; final String layerInstallMore = "LAYER_INSTALL_MORE"; final String layerEditInstall = "LAYER_EDIT"; entriesMap.put(layerOsmVector, getString(R.string.vector_data)); entriesMap.putAll(settings.getTileSourceEntries()); entriesMap.put(layerInstallMore, getString(R.string.install_more)); entriesMap.put(layerEditInstall, getString(R.string.maps_define_edit)); final List<Entry<String, String>> entriesMapList = new ArrayList<>(entriesMap.entrySet()); AlertDialog.Builder builder = new AlertDialog.Builder(activity); String selectedTileSourceKey = settings.MAP_TILE_SOURCES.get(); int selectedItem = -1; if (!settings.MAP_ONLINE_DATA.get()) { selectedItem = 0; } else { Entry<String, String> selectedEntry = null; for (Entry<String, String> entry : entriesMap.entrySet()) { if (entry.getKey().equals(selectedTileSourceKey)) { selectedEntry = entry; break; } } if (selectedEntry != null) { selectedItem = 0; entriesMapList.remove(selectedEntry); entriesMapList.add(0, selectedEntry); } } final String[] items = new String[entriesMapList.size()]; int i = 0; for (Entry<String, String> entry : entriesMapList) { items[i++] = entry.getValue(); } builder.setSingleChoiceItems(items, selectedItem, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { String layerKey = entriesMapList.get(which).getKey(); switch (layerKey) { case layerOsmVector: settings.MAP_ONLINE_DATA.set(false); updateMapSource(mapView, null); it.setDescription(null); adapter.notifyDataSetChanged(); break; case layerEditInstall: OsmandRasterMapsPlugin.defineNewEditLayer(activity, new ResultMatcher<TileSourceTemplate>() { @Override public boolean publish(TileSourceTemplate object) { settings.MAP_TILE_SOURCES.set(object.getName()); settings.MAP_ONLINE_DATA.set(true); if(it != null) { it.setDescription(object.getName()); } updateMapSource(mapView, settings.MAP_TILE_SOURCES); return true; } @Override public boolean isCancelled() { return false; } }); break; case layerInstallMore: OsmandRasterMapsPlugin.installMapLayers(activity, new ResultMatcher<TileSourceTemplate>() { TileSourceTemplate template = null; int count = 0; @Override public boolean publish(TileSourceTemplate object) { if (object == null) { if (count == 1) { settings.MAP_TILE_SOURCES.set(template.getName()); settings.MAP_ONLINE_DATA.set(true); it.setDescription(template.getName()); adapter.notifyDataSetChanged(); updateMapSource(mapView, settings.MAP_TILE_SOURCES); } else { selectMapLayer(mapView, it, adapter); } } else { count++; template = object; } return false; } @Override public boolean isCancelled() { return false; } }); break; default: settings.MAP_TILE_SOURCES.set(layerKey); settings.MAP_ONLINE_DATA.set(true); it.setDescription(layerKey); adapter.notifyDataSetChanged(); updateMapSource(mapView, settings.MAP_TILE_SOURCES); break; } dialog.dismiss(); } }); builder.setNegativeButton(R.string.shared_string_dismiss, null); builder.show(); } private String getString(int resId) { return activity.getString(resId); } public PointNavigationLayer getNavigationLayer() { return navigationLayer; } public ImpassableRoadsLayer getImpassableRoadsLayer() { return impassableRoadsLayer; } public GPXLayer getGpxLayer() { return gpxLayer; } public ContextMenuLayer getContextMenuLayer() { return contextMenuLayer; } public FavouritesLayer getFavouritesLayer() { return mFavouritesLayer; } public MapTextLayer getMapTextLayer() { return mapTextLayer; } public PointLocationLayer getLocationLayer() { return locationLayer; } public MapInfoLayer getMapInfoLayer() { return mapInfoLayer; } public MapControlsLayer getMapControlsLayer() { return mapControlsLayer; } public MapQuickActionLayer getMapQuickActionLayer() { return mapQuickActionLayer; } public MapMarkersLayer getMapMarkersLayer() { return mapMarkersLayer; } public MapTileLayer getMapTileLayer() { return mapTileLayer; } public MapVectorLayer getMapVectorLayer() { return mapVectorLayer; } public POIMapLayer getPoiMapLayer() { return poiMapLayer; } public TransportStopsLayer getTransportStopsLayer() { return transportStopsLayer; } public DownloadedRegionsLayer getDownloadedRegionsLayer() { return downloadedRegionsLayer; } public interface DismissListener { void dismiss(); } }