package net.osmand.plus.mapcontextmenu; import android.graphics.drawable.Drawable; import android.support.annotation.NonNull; import android.view.View; import android.view.View.OnClickListener; import android.widget.LinearLayout; import net.osmand.IndexConstants; import net.osmand.NativeLibrary.RenderedObject; import net.osmand.aidl.maplayer.point.AMapPoint; import net.osmand.binary.BinaryMapDataObject; import net.osmand.binary.BinaryMapIndexReader.TagValuePair; import net.osmand.binary.RouteDataObject; import net.osmand.data.Amenity; import net.osmand.data.FavouritePoint; import net.osmand.data.LatLon; import net.osmand.data.PointDescription; import net.osmand.data.TransportStop; import net.osmand.map.OsmandRegions; import net.osmand.map.WorldRegion; import net.osmand.plus.GPXUtilities.WptPt; import net.osmand.plus.GpxSelectionHelper.GpxDisplayItem; import net.osmand.plus.MapMarkersHelper.MapMarker; import net.osmand.plus.OsmandApplication; import net.osmand.plus.OsmandPlugin; import net.osmand.plus.OsmandSettings; import net.osmand.plus.R; import net.osmand.plus.TargetPointsHelper.TargetPoint; import net.osmand.plus.activities.MapActivity; import net.osmand.plus.audionotes.AudioVideoNoteMenuController; import net.osmand.plus.audionotes.AudioVideoNotesPlugin.Recording; import net.osmand.plus.download.DownloadActivityType; import net.osmand.plus.download.DownloadIndexesThread; import net.osmand.plus.download.DownloadValidationManager; import net.osmand.plus.download.IndexItem; import net.osmand.plus.helpers.SearchHistoryHelper; import net.osmand.plus.mapcontextmenu.controllers.AMapPointMenuController; import net.osmand.plus.mapcontextmenu.controllers.AmenityMenuController; import net.osmand.plus.mapcontextmenu.controllers.FavouritePointMenuController; import net.osmand.plus.mapcontextmenu.controllers.GpxItemMenuController; import net.osmand.plus.mapcontextmenu.controllers.HistoryMenuController; import net.osmand.plus.mapcontextmenu.controllers.ImpassibleRoadsMenuController; import net.osmand.plus.mapcontextmenu.controllers.MapDataMenuController; import net.osmand.plus.mapcontextmenu.controllers.MapMarkerMenuController; import net.osmand.plus.mapcontextmenu.controllers.MyLocationMenuController; import net.osmand.plus.mapcontextmenu.controllers.PointDescriptionMenuController; import net.osmand.plus.mapcontextmenu.controllers.RenderedObjectMenuController; import net.osmand.plus.mapcontextmenu.controllers.TargetPointMenuController; import net.osmand.plus.mapcontextmenu.controllers.TransportRouteController; import net.osmand.plus.mapcontextmenu.controllers.TransportStopController; import net.osmand.plus.mapcontextmenu.controllers.TransportStopController.TransportStopRoute; import net.osmand.plus.mapcontextmenu.controllers.WptPtMenuController; import net.osmand.plus.mapcontextmenu.other.ShareMenu; import net.osmand.plus.osmedit.EditPOIMenuController; import net.osmand.plus.osmedit.OsmBugMenuController; import net.osmand.plus.osmedit.OsmBugsLayer.OpenStreetNote; import net.osmand.plus.osmedit.OsmPoint; import net.osmand.plus.osmo.OsMoGroupsStorage.OsMoDevice; import net.osmand.plus.osmo.OsMoMenuController; import net.osmand.plus.parkingpoint.ParkingPositionMenuController; import net.osmand.plus.resources.ResourceManager; import net.osmand.plus.views.DownloadedRegionsLayer.DownloadMapObject; import net.osmand.plus.views.mapwidgets.MapInfoWidgetsFactory.TopToolbarController; import net.osmand.plus.views.mapwidgets.MapInfoWidgetsFactory.TopToolbarControllerType; import net.osmand.util.Algorithms; import net.osmand.util.MapUtils; import java.io.IOException; import java.util.Iterator; import java.util.LinkedList; import java.util.List; public abstract class MenuController extends BaseMenuController { public static class MenuState { public static final int HEADER_ONLY = 1; public static final int HALF_SCREEN = 2; public static final int FULL_SCREEN = 4; } public enum MenuType { STANDARD, MULTI_LINE } protected MenuBuilder builder; private int currentMenuState; private MenuType menuType = MenuType.STANDARD; private PointDescription pointDescription; private LatLon latLon; private boolean active; protected TitleButtonController leftTitleButtonController; protected TitleButtonController rightTitleButtonController; protected TitleButtonController topRightTitleButtonController; protected TitleButtonController leftDownloadButtonController; protected TitleButtonController rightDownloadButtonController; protected TitleProgressController titleProgressController; protected TopToolbarController toolbarController; protected IndexItem indexItem; protected boolean downloaded; private BinaryMapDataObject downloadMapDataObject; private WorldRegion downloadRegion; private DownloadIndexesThread downloadThread; public MenuController(MenuBuilder builder, PointDescription pointDescription, MapActivity mapActivity) { super(mapActivity); this.pointDescription = pointDescription; this.builder = builder; this.currentMenuState = getInitialMenuState(); this.builder.setLight(isLight()); } public void build(View rootView) { for (OsmandPlugin plugin : OsmandPlugin.getEnabledPlugins()) { if (plugin.isMenuControllerSupported(this.getClass())) { builder.addMenuPlugin(plugin); } } builder.build(rootView); } public static MenuController getMenuController(MapActivity mapActivity, LatLon latLon, PointDescription pointDescription, Object object, MenuType menuType) { OsmandApplication app = mapActivity.getMyApplication(); MenuController menuController = null; if (object != null) { if (object instanceof Amenity) { menuController = new AmenityMenuController(mapActivity, pointDescription, (Amenity) object); } else if (object instanceof FavouritePoint) { menuController = new FavouritePointMenuController(mapActivity, pointDescription, (FavouritePoint) object); } else if (object instanceof SearchHistoryHelper.HistoryEntry) { menuController = new HistoryMenuController(mapActivity, pointDescription, (SearchHistoryHelper.HistoryEntry) object); } else if (object instanceof TargetPoint) { menuController = new TargetPointMenuController(mapActivity, pointDescription, (TargetPoint) object); } else if (object instanceof OsMoDevice) { menuController = new OsMoMenuController(mapActivity, pointDescription, (OsMoDevice) object); } else if (object instanceof Recording) { menuController = new AudioVideoNoteMenuController(mapActivity, pointDescription, (Recording) object); } else if (object instanceof OsmPoint) { menuController = new EditPOIMenuController(mapActivity, pointDescription, (OsmPoint) object); } else if (object instanceof WptPt) { menuController = new WptPtMenuController(mapActivity, pointDescription, (WptPt) object); } else if (object instanceof DownloadMapObject) { menuController = new MapDataMenuController(mapActivity, pointDescription, (DownloadMapObject) object); } else if (object instanceof OpenStreetNote) { menuController = new OsmBugMenuController(mapActivity, pointDescription, (OpenStreetNote) object); } else if (object instanceof GpxDisplayItem) { menuController = new GpxItemMenuController(mapActivity, pointDescription, (GpxDisplayItem) object); } else if (object instanceof MapMarker) { menuController = new MapMarkerMenuController(mapActivity, pointDescription, (MapMarker) object); } else if (object instanceof TransportStopRoute) { menuController = new TransportRouteController(mapActivity, pointDescription, (TransportStopRoute) object); } else if (object instanceof TransportStop) { menuController = new TransportStopController(mapActivity, pointDescription, (TransportStop) object); } else if (object instanceof AMapPoint) { menuController = new AMapPointMenuController(mapActivity, pointDescription, (AMapPoint) object); } else if (object instanceof LatLon) { if (pointDescription.isParking()) { menuController = new ParkingPositionMenuController(mapActivity, pointDescription); } else if (pointDescription.isMyLocation()) { menuController = new MyLocationMenuController(mapActivity, pointDescription); } } else if (object instanceof RouteDataObject) { menuController = new ImpassibleRoadsMenuController(mapActivity, pointDescription, (RouteDataObject) object); } else if (object instanceof RenderedObject) { menuController = new RenderedObjectMenuController(mapActivity, pointDescription, (RenderedObject) object); } } if (menuController == null) { menuController = new PointDescriptionMenuController(mapActivity, pointDescription); } menuController.menuType = menuType; menuController.setLatLon(latLon); return menuController; } public void update(PointDescription pointDescription, Object object) { setPointDescription(pointDescription); setObject(object); } protected void setPointDescription(PointDescription pointDescription) { this.pointDescription = pointDescription; } protected abstract void setObject(Object object); protected abstract Object getObject(); public boolean isActive() { return active; } public void setActive(boolean active) { this.active = active; } public void addPlainMenuItem(int iconId, String text, boolean needLinks, boolean isUrl, OnClickListener onClickListener) { builder.addPlainMenuItem(iconId, text, needLinks, isUrl, onClickListener); } public void clearPlainMenuItems() { builder.clearPlainMenuItems(); } public void addPlainMenuItems(String typeStr, PointDescription pointDescription, LatLon latLon) { addMyLocationToPlainItems(latLon); } protected void addMyLocationToPlainItems(LatLon latLon) { OsmandSettings st = ((OsmandApplication) getMapActivity().getApplicationContext()).getSettings(); addPlainMenuItem(R.drawable.ic_action_get_my_location, PointDescription.getLocationName(getMapActivity(), latLon.getLatitude(), latLon.getLongitude(), true).replaceAll("\n", " "), false, false, null); if (st.COORDINATES_FORMAT.get() != PointDescription.OLC_FORMAT) addPlainMenuItem(R.drawable.ic_action_get_my_location, PointDescription.getLocationOlcName( latLon.getLatitude(), latLon.getLongitude()).replaceAll("\n", " "), false, false, null); } public PointDescription getPointDescription() { return pointDescription; } public int getInitialMenuState() { if (isLandscapeLayout()) { return MenuState.FULL_SCREEN; } else { return getInitialMenuStatePortrait(); } } public int getSupportedMenuStates() { if (isLandscapeLayout()) { return MenuState.FULL_SCREEN; } else { return getSupportedMenuStatesPortrait(); } } protected int getInitialMenuStatePortrait() { return MenuState.HEADER_ONLY; } protected int getSupportedMenuStatesPortrait() { return MenuState.HEADER_ONLY | MenuState.HALF_SCREEN | MenuState.FULL_SCREEN; } public int getCurrentMenuState() { return currentMenuState; } public MenuType getMenuType() { return menuType; } public boolean slideUp() { int v = currentMenuState; for (int i = 0; i < 2; i++) { v = v << 1; if ((v & getSupportedMenuStates()) != 0) { currentMenuState = v; return true; } } return false; } public boolean slideDown() { int v = currentMenuState; for (int i = 0; i < 2; i++) { v = v >> 1; if ((v & getSupportedMenuStates()) != 0) { currentMenuState = v; return true; } } return false; } public void setCurrentMenuState(int currentMenuState) { this.currentMenuState = currentMenuState; } public TitleButtonController getLeftTitleButtonController() { return leftTitleButtonController; } public TitleButtonController getRightTitleButtonController() { return rightTitleButtonController; } public TitleButtonController getTopRightTitleButtonController() { return topRightTitleButtonController; } public TitleButtonController getLeftDownloadButtonController() { return leftDownloadButtonController; } public TitleButtonController getRightDownloadButtonController() { return rightDownloadButtonController; } public TitleProgressController getTitleProgressController() { return titleProgressController; } public TopToolbarController getToolbarController() { return toolbarController; } public boolean hasBackAction() { return toolbarController != null; } public LatLon getLatLon() { return latLon; } public boolean supportZoomIn() { return true; } public boolean fabVisible() { return true; } public boolean buttonsVisible() { return true; } public boolean handleSingleTapOnMap() { return false; } public boolean needStreetName() { return !displayDistanceDirection(); } public boolean needTypeStr() { return true; } public boolean displayStreetNameInTitle() { return false; } public boolean displayDistanceDirection() { return false; } public int getLeftIconId() { return 0; } public Drawable getLeftIcon() { return null; } public Drawable getSecondLineTypeIcon() { return null; } public int getFavActionIconId() { return R.drawable.map_action_fav_dark; } public int getFavActionStringId() { return R.string.shared_string_add_to_favorites; } public String getTypeStr() { return ""; } public String getCommonTypeStr() { return ""; } public String getNameStr() { return pointDescription.getName(); } public void share(LatLon latLon, String title, String address) { ShareMenu.show(latLon, title, address, getMapActivity()); } public void updateData() { if (downloadMapDataObject != null) { if (indexItem == null) { List<IndexItem> indexItems = new LinkedList<>(downloadThread.getIndexes().getIndexItems(downloadRegion)); for (IndexItem item : indexItems) { if (item.getType() == DownloadActivityType.NORMAL_FILE) { indexItem = item; break; } } } if (indexItem != null) { downloaded = indexItem.isDownloaded(); } leftDownloadButtonController.visible = !downloaded; leftDownloadButtonController.leftIconId = R.drawable.ic_action_import; boolean downloadIndexes = getMapActivity().getMyApplication().getSettings().isInternetConnectionAvailable() && !downloadThread.getIndexes().isDownloadedFromInternet && !downloadThread.getIndexes().downloadFromInternetFailed; boolean isDownloading = indexItem != null && downloadThread.isDownloading(indexItem); if (isDownloading) { titleProgressController.setMapDownloadMode(); if (downloadThread.getCurrentDownloadingItem() == indexItem) { titleProgressController.indeterminate = false; titleProgressController.progress = downloadThread.getCurrentDownloadingItemProgress(); } else { titleProgressController.indeterminate = true; titleProgressController.progress = 0; } double mb = indexItem.getArchiveSizeMB(); String v; if (titleProgressController.progress != -1) { v = getMapActivity().getString(R.string.value_downloaded_of_max, mb * titleProgressController.progress / 100, mb); } else { v = getMapActivity().getString(R.string.file_size_in_mb, mb); } if (indexItem.getType() == DownloadActivityType.ROADS_FILE) { titleProgressController.caption = indexItem.getType().getString(getMapActivity()) + " • " + v; } else { titleProgressController.caption = v; } titleProgressController.visible = true; } else if (downloadIndexes) { titleProgressController.setIndexesDownloadMode(); titleProgressController.visible = true; } else { titleProgressController.visible = false; } } } public boolean hasCustomAddressLine() { return builder.hasCustomAddressLine(); } public void buildCustomAddressLine(LinearLayout ll) { builder.buildCustomAddressLine(ll); } public abstract class TitleButtonController { public String caption = ""; public int leftIconId = 0; public boolean needRightText = false; public String rightTextCaption = ""; public boolean visible = true; public Drawable getLeftIcon() { if (leftIconId != 0) { return getIcon(leftIconId, isLight() ? R.color.map_widget_blue : R.color.osmand_orange); } else { return null; } } public abstract void buttonPressed(); } public abstract class TitleProgressController { public String caption = ""; public int progress = 0; public boolean indeterminate; public boolean visible; public boolean buttonVisible; public void setIndexesDownloadMode() { caption = getMapActivity().getString(R.string.downloading_list_indexes); indeterminate = true; buttonVisible = false; } public void setMapDownloadMode() { indeterminate = false; buttonVisible = true; } public abstract void buttonPressed(); } public void onShow() { if (toolbarController != null) { getMapActivity().showTopToolbar(toolbarController); } } public void onHide() { if (builder != null) { builder.onHide(); } } public void onClose() { if (builder != null) { builder.onClose(); } if (toolbarController != null) { getMapActivity().hideTopToolbar(toolbarController); } } public void onAcquireNewController(PointDescription pointDescription, Object object) { } public boolean isMapDownloaded() { return downloaded; } public void setLatLon(@NonNull LatLon latLon) { this.latLon = latLon; if (builder != null) { builder.setLatLon(latLon); } } public void buildMapDownloadButton(LatLon latLon) { int point31x = MapUtils.get31TileNumberX(latLon.getLongitude()); int point31y = MapUtils.get31TileNumberY(latLon.getLatitude()); ResourceManager rm = getMapActivity().getMyApplication().getResourceManager(); OsmandRegions osmandRegions = rm.getOsmandRegions(); List<BinaryMapDataObject> mapDataObjects = null; try { mapDataObjects = osmandRegions.queryBbox(point31x, point31x, point31y, point31y); } catch (IOException e) { e.printStackTrace(); } if (mapDataObjects != null) { Iterator<BinaryMapDataObject> it = mapDataObjects.iterator(); while (it.hasNext()) { BinaryMapDataObject o = it.next(); if (o.getTypes() != null) { boolean isRegion = true; for (int i = 0; i < o.getTypes().length; i++) { TagValuePair tp = o.getMapIndex().decodeType(o.getTypes()[i]); if ("boundary".equals(tp.value)) { isRegion = false; break; } } if (!isRegion || !osmandRegions.contain(o, point31x, point31y)) { it.remove(); } } } String selectedFullName = ""; double smallestArea = -1; downloadMapDataObject = null; for (BinaryMapDataObject o : mapDataObjects) { String downloadName = osmandRegions.getDownloadName(o); if (!Algorithms.isEmpty(downloadName)) { boolean downloaded = checkIfObjectDownloaded(rm, downloadName); if (downloaded) { downloadMapDataObject = null; break; } else { String fullName = osmandRegions.getFullName(o); WorldRegion region = osmandRegions.getRegionData(fullName); if (region != null && region.isRegionMapDownload()) { double area = OsmandRegions.getArea(o); if (smallestArea == -1) { smallestArea = area; selectedFullName = fullName; downloadMapDataObject = o; } else if (area < smallestArea) { smallestArea = area; selectedFullName = fullName; downloadMapDataObject = o; } } } } } downloaded = downloadMapDataObject == null; if (!downloaded) { downloadThread = getMapActivity().getMyApplication().getDownloadThread(); downloadRegion = osmandRegions.getRegionData(selectedFullName); if (downloadRegion != null && downloadRegion.isRegionMapDownload()) { List<IndexItem> indexItems = downloadThread.getIndexes().getIndexItems(downloadRegion); for (IndexItem item : indexItems) { if (item.getType() == DownloadActivityType.NORMAL_FILE && (item.isDownloaded() || downloadThread.isDownloading(item))) { indexItem = item; } } } leftDownloadButtonController = new TitleButtonController() { @Override public void buttonPressed() { if (indexItem != null) { if (indexItem.getType() == DownloadActivityType.NORMAL_FILE) { new DownloadValidationManager(getMapActivity().getMyApplication()) .startDownload(getMapActivity(), indexItem); } } } }; leftDownloadButtonController.caption = downloadRegion != null ? downloadRegion.getLocaleName() : getMapActivity().getString(R.string.shared_string_download); leftDownloadButtonController.leftIconId = R.drawable.ic_action_import; titleProgressController = new TitleProgressController() { @Override public void buttonPressed() { if (indexItem != null) { downloadThread.cancelDownload(indexItem); } } }; if (!downloadThread.getIndexes().isDownloadedFromInternet) { if (getMapActivity().getMyApplication().getSettings().isInternetConnectionAvailable()) { downloadThread.runReloadIndexFiles(); } } updateData(); } } } private boolean checkIfObjectDownloaded(ResourceManager rm, String downloadName) { final String regionName = Algorithms.capitalizeFirstLetterAndLowercase(downloadName) + IndexConstants.BINARY_MAP_INDEX_EXT; final String roadsRegionName = Algorithms.capitalizeFirstLetterAndLowercase(downloadName) + ".road" + IndexConstants.BINARY_MAP_INDEX_EXT; boolean downloaded = rm.getIndexFileNames().containsKey(regionName) || rm.getIndexFileNames().containsKey(roadsRegionName); if (!downloaded) { WorldRegion region = rm.getOsmandRegions().getRegionDataByDownloadName(downloadName); if (region != null && region.getSuperregion() != null && region.getSuperregion().isRegionMapDownload()) { return checkIfObjectDownloaded(rm, region.getSuperregion().getRegionDownloadName()); } } return downloaded; } public static class ContextMenuToolbarController extends TopToolbarController { private MenuController menuController; public ContextMenuToolbarController(MenuController menuController) { super(TopToolbarControllerType.CONTEXT_MENU); this.menuController = menuController; } public MenuController getMenuController() { return menuController; } } }