package net.bonysoft.mapsmuzei; import android.content.Context; import android.content.res.XmlResourceParser; import android.util.Log; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; import java.util.ArrayList; /** * Class defining a style for the map, as described in * https://developers.google.com/maps/documentation/staticmaps/#StyledMaps * * Created by Daniele Bonaldo on 2/26/14. */ public class MapTheme { private static final String TAG = MapTheme.class.getSimpleName(); public static final int MODE_MAP = 0; public static final int MODE_SATELLITE = 1; public static final int MODE_TERRAIN = 2; public static final int MODE_HYBRID = 3; public static final int MODE_CUSTOM = -1; public static final String[] MODES = {"roadmap", "satellite", "terrain", "hybrid"}; public static final String XML_TAG_STYLE = "MapStyle"; public static final String XML_TAG_THEME = "MapTheme"; public static final String XML_ATTRIBUTE_NAME = "name"; public static final String XML_ATTRIBUTE_MAP_TYPE = "mapType"; private static final String MODE_PREFIX = "&maptype="; private static final String STYLE_PREFIX = "&style="; private static final String STYLE_INVERT_LIGHTNESS = "invert_lightness:true"; private boolean isInverted = false; int mode = MODE_MAP; private ArrayList<String> styles = new ArrayList<String>(); public void setMapMode(int mode) { this.mode = mode; } public void setInverted(boolean isInverted) { this.isInverted = isInverted; } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append(MODE_PREFIX).append(MODES[mode]); for(String style : styles) { sb.append(STYLE_PREFIX).append(style); } if (isInverted) { sb.append(STYLE_PREFIX).append(STYLE_INVERT_LIGHTNESS); } return sb.toString(); } /** * Check id the selected map theme is one of the standard ones (roadmap, satellite, terrain, hybrid) * @param mapMode the index of the selected map type * @return true if the theme is between roadmap, satellite, terrain or hybrid; false otherwise */ public static boolean isStandardTheme(int mapMode) { return mapMode == MODE_MAP || mapMode == MODE_SATELLITE || mapMode == MODE_TERRAIN || mapMode == MODE_HYBRID; } /** * Load the selected theme from the themes XML file, starting from the index of the theme in the all-themes list * @param context the context from which access the resources for the themes XML file * @param themeId the id of the theme to load * @return the loaded theme or a default theme (roadmap) if there was any problem during the loading */ public static MapTheme loadCustomTheme(Context context, int themeId) { String[] themesNames = context.getResources().getStringArray(R.array.map_types_titles); if (themesNames.length > themeId) { return loadFromXml(context, themesNames[themeId]); } return new MapTheme(); } /** * Creates a new Theme loading it from the themes XML file * @param context the context from which access the resources for the themes XML file * @param themeName the name of the theme to load * @return the loaded theme or a default theme (roadmap) if a theme with the given name does not exist */ private static MapTheme loadFromXml(Context context, String themeName) { MapTheme newTheme = new MapTheme(); XmlResourceParser xrp = context.getResources().getXml(R.xml.map_themes); try { assert xrp != null; if (findThemeFromXml(themeName, xrp)) { readMapType(newTheme, xrp); // Load all the styles associated to the theme readThemeStyles(newTheme, xrp); } } catch (Exception e) { Log.e(TAG, "Unable to load theme \"" + themeName + "\" from XML resources", e); } return newTheme; } private static void readMapType(MapTheme newTheme, XmlResourceParser xrp) { String mapType = xrp.getAttributeValue(null, XML_ATTRIBUTE_MAP_TYPE); if (mapType != null) { newTheme.setMapMode(getMapTypeIdFromString(mapType)); } } private static int getMapTypeIdFromString(String mapTypeName) { int i=0; for (String s : MODES) { if (s.equals(mapTypeName)) { return i; } i++; } return MODE_MAP; } /** * Find the node associated to the selected theme in the loaded XML * * @param themeName the name of the theme to look for * @param xrp the XmlResourceParser used to load the themes XML file * @return true if atheme with the given name has been found, false otherwise * @throws XmlPullParserException * @throws IOException */ private static boolean findThemeFromXml(String themeName, XmlResourceParser xrp) throws XmlPullParserException, IOException { int eventType = xrp.next(); while (eventType != XmlPullParser.END_DOCUMENT) { if (eventType == XmlPullParser.START_TAG && xrp.getName().equalsIgnoreCase(XML_TAG_THEME) && themeName.equals(xrp.getAttributeValue(null, XML_ATTRIBUTE_NAME))) { break; } eventType = xrp.next(); } return eventType != XmlPullParser.END_DOCUMENT; } /** * Read all the styles contained in the node of the current theme * @param newTheme the target style in which the loaded styles will be saved * @param xrp the XmlResourceParser used to load the themes XML file * @throws XmlPullParserException * @throws IOException */ private static void readThemeStyles(MapTheme newTheme, XmlResourceParser xrp) throws XmlPullParserException, IOException { int eventType = xrp.next(); while (!(eventType == XmlPullParser.END_TAG && xrp.getName().equalsIgnoreCase(XML_TAG_THEME))) { if (eventType == XmlPullParser.START_TAG && xrp.getName().equalsIgnoreCase(XML_TAG_STYLE)) { eventType = xrp.next(); if (eventType == XmlPullParser.TEXT) { String style = xrp.getText(); newTheme.styles.add(style); } } eventType = xrp.next(); } } }