package org.redcross.openmapkit; import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; import android.content.SharedPreferences; import android.widget.Toast; import com.mapbox.mapboxsdk.geometry.BoundingBox; import com.mapbox.mapboxsdk.tileprovider.tilesource.MBTilesLayer; import com.mapbox.mapboxsdk.tileprovider.tilesource.WebSourceTileLayer; import com.mapbox.mapboxsdk.views.MapView; import java.io.File; import java.util.ArrayList; import java.util.List; public class Basemap { public static final String ONLINE = "Online Humanitarian OpenStreetMap"; private static final String PREVIOUS_BASEMAP = "org.redcross.openmapkit.PREVIOUS_BASEMAP"; private MapActivity mapActivity; private MapView mapView; private Context context; private static String selectedBasemap; private static boolean needsBoundsChecking = false; /** * This is how you select a basemap from outside of the MapActivity. * We set a selected basemap static property, and when the MapActivity * starts, it it instantiates a Basemap instance. In the constructor, * it looks to see if we have a basemap that matches, and sets it * accordingly. * * @param basemap - Either Basemap.ONLINE or a file path to an MBTiles file */ public static void select(String basemap) { selectedBasemap = basemap; needsBoundsChecking = true; } public Basemap(MapActivity mapActivity) { this.mapActivity = mapActivity; this.mapView = mapActivity.getMapView(); this.context = mapActivity.getApplicationContext(); if (selectedBasemap == null) { final SharedPreferences sharedPreferences = mapActivity.getPreferences(Context.MODE_PRIVATE); selectedBasemap = sharedPreferences.getString(PREVIOUS_BASEMAP, null); } if (selectedBasemap != null) { // was online basemap if (selectedBasemap.equals(ONLINE)) { selectOnlineBasemap(); } else { selectMBTilesBasemap(selectedBasemap); } } else { presentBasemapsOptions(); } } public void presentBasemapsOptions() { //shared preferences private to mapActivity final SharedPreferences sharedPreferences = mapActivity.getPreferences(Context.MODE_PRIVATE); String previousBasemap = sharedPreferences.getString(PREVIOUS_BASEMAP, null); //create an array of all mbtile options final List<String> basemaps = new ArrayList<>(); //when device is connected, HOT OSM Basemap is the first option if(Connectivity.isConnected(context)) { basemaps.add(ONLINE); } //add mbtiles names from external storage File[] mbtiles = ExternalStorage.fetchMBTilesFiles(); if (mbtiles.length > 0) { for (File file : mbtiles) { String filePath = file.getAbsolutePath(); basemaps.add(filePath); } } if (basemaps.size() == 0) { Toast prompt = Toast.makeText(context, "No basemap downloaded yet. You may 1) download a deployment, 2) connect to the internet, or 3) add .mbtiles file to " + ExternalStorage.getMBTilesDir() + ".", Toast.LENGTH_LONG); prompt.show(); return; } //create dialog of mbtiles choices AlertDialog.Builder builder = new AlertDialog.Builder(mapActivity); builder.setTitle(mapActivity.getString(R.string.mbtilesChooserDialogTitle)); int len = basemaps.size(); String[] names = new String[len]; for (int i = 0; i < len; ++i) { String basemap = basemaps.get(i); if (basemap.equals(ONLINE)) { names[i] = basemap; } else { names[i] = new File(basemap).getName(); } } //default mbtiles option is based on previous selections (persisted in shared preferences) or connectivity state of device int defaultRadioButtonIndex = 0; if(previousBasemap == null) { //if user DID NOT previously choose an mbtiles option... if(Connectivity.isConnected(context)) { //the first radio button (for HOT OSM) will be selected by default defaultRadioButtonIndex = 0; //the default selected option is HOT OSM selectedBasemap = basemaps.get(0); //default choice } else { defaultRadioButtonIndex = -1; //no selected radio button by default } } else { //if user previously chose an mbtiles option ... for(int i = 0; i < basemaps.size(); ++i) { String filePath = basemaps.get(i); if(filePath.equals(previousBasemap)) { defaultRadioButtonIndex = i; selectedBasemap = filePath; } } if (selectedBasemap == null) { selectedBasemap = basemaps.get(0); } } //add choices to dialog builder.setSingleChoiceItems(names, defaultRadioButtonIndex, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { setSelectedBasemap(basemaps.get(which)); } }); //handle OK tap event of dialog builder.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int id) { //user clicked OK if(selectedBasemap.equals(ONLINE)) { selectOnlineBasemap(); } else { selectMBTilesBasemap(selectedBasemap); } } }); //handle cancel button tap event of dialog builder.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int id) { //user clicked cancel } }); //present dialog to user builder.show(); } private void selectOnlineBasemap() { //create OSM tile layer String defaultTilePID = mapActivity.getString(R.string.defaultTileLayerPID); String defaultTileURL = mapActivity.getString(R.string.defaultTileLayerURL); String defaultTileName = mapActivity.getString(R.string.defaultTileLayerName); String defaultTileAttribution = mapActivity.getString(R.string.defaultTileLayerAttribution); WebSourceTileLayer ws = new WebSourceTileLayer(defaultTilePID, defaultTileURL); ws.setName(defaultTileName).setAttribution(defaultTileAttribution); setSelectedBasemap(ONLINE); //add OSM tile layer to map mapView.setTileSource(ws); } private void selectMBTilesBasemap(String mbtilesPath) { File mbtilesFile = new File(mbtilesPath); if(!mbtilesFile.exists()) { AlertDialog.Builder builder = new AlertDialog.Builder(mapActivity); builder.setTitle("Offline Basemap Not Found"); builder.setMessage("Please check out a deployment or add MBTiles files to " + ExternalStorage.getMBTilesDir()); builder.setPositiveButton("Ok", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { //placeholder } }); AlertDialog dialog = builder.create(); dialog.show(); return; } //add mbtiles to map MBTilesLayer mbTilesLayer = new MBTilesLayer(mbtilesFile); mapView.setTileSource(mbTilesLayer); setSelectedBasemap(mbtilesPath); // if we set an MBTiles from a DeploymentDetails, the map may not start panned to the bounds if (needsBoundsChecking) { BoundingBox bbox = mbTilesLayer.getBoundingBox(); mapView.zoomToBoundingBox(bbox); needsBoundsChecking = false; } } private void setSelectedBasemap(String basemap) { selectedBasemap = basemap; SharedPreferences sharedPreferences = mapActivity.getPreferences(Context.MODE_PRIVATE); SharedPreferences.Editor editor = sharedPreferences.edit(); editor.putString(PREVIOUS_BASEMAP, selectedBasemap); editor.apply(); } }