/* * Southampton University Map App * Copyright (C) 2011 Christopher Baines * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package net.cbaines.suma; import java.io.IOException; import java.io.InputStream; import java.sql.SQLException; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.List; import org.osmdroid.DefaultResourceProxyImpl; import org.osmdroid.ResourceProxy; import org.osmdroid.tileprovider.tilesource.TileSourceFactory; import org.osmdroid.util.GeoPoint; import org.osmdroid.views.MapController; import org.osmdroid.views.MapView; import org.osmdroid.views.overlay.MyLocationOverlay; import org.osmdroid.views.overlay.Overlay; import org.osmdroid.views.overlay.PathOverlay; import org.osmdroid.views.overlay.ScaleBarOverlay; import org.osmdroid.views.util.constants.MapViewConstants; import android.app.AlertDialog; import android.app.Dialog; import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; import android.content.SharedPreferences.OnSharedPreferenceChangeListener; import android.graphics.Color; import android.graphics.DashPathEffect; import android.graphics.Paint; import android.net.Uri; import android.os.Bundle; import android.preference.PreferenceManager; import android.util.Log; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.AdapterView.OnItemLongClickListener; import com.j256.ormlite.dao.Dao; /** * * @author Christopher Baines * */ public class MapActivity extends ToastHelperActivity implements MapViewConstants, Runnable, RouteColorConstants, OnItemClickListener, OnItemLongClickListener, OnSharedPreferenceChangeListener, Preferences { /** * Enable to use the database in the assets folder, if its not enabled, the database is built from the csv files in the assets * folder */ private boolean useBundledDatabase = true; private MapView mapView; private MapController mapController; private ResourceProxy mResourceProxy; private long startTime; static final int VIEW_DIALOG_ID = 0; static final int FAVOURITE_DIALOG_ID = 1; private POIDialog favDialog; private HashMap overlays = new HashMap(); private HashMap pastOverlays; // Overlays // -- Building Overlays static final String BUILDING_OVERLAYS = "buildingOverlays:"; // ---- Residential Building Overlay private static final String RESIDENTIAL_BUILDING_OVERLAY = "residentialBuildingOverlay"; private BuildingNumOverlay residentialBuildingOverlay; static final boolean RESIDENTIAL_BUILDING_OVERLAY_ENABLED_BY_DEFAULT = true; private static final int RESIDENTIAL_BUILDING_OVERLAY_RANK = 6; // ---- Non-Residential Building Overlay private static final String NON_RESIDENTIAL_BUILDING_OVERLAY = "nonResidentialBuildingOverlay"; private BuildingNumOverlay nonResidentialBuildingOverlay; static final boolean NON_RESIDENTIAL_BUILDING_OVERLAY_ENABLED_BY_DEFAULT = true; private static final int NON_RESIDENTIAL_BUILDING_OVERLAY_RANK = 5; static final String[] BUILDING_TYPES = { RESIDENTIAL_BUILDING_OVERLAY, NON_RESIDENTIAL_BUILDING_OVERLAY }; // -- Bus Stop Overlays static final String BUS_STOP_OVERLAYS = "busStopOverlays:"; // ---- Uni-Link Bus Stop Overlay private static final String UNI_LINK_BUS_STOP_OVERLAY = "uniLinkBusStopOverlay"; private BusStopOverlay uniLinkBusStopOverlay; static final boolean UNI_LINK_BUS_STOP_OVERLAY_ENABLED_BY_DEFAULT = true; private static final int UNI_LINK_BUS_STOP_OVERLAY_RANK = 3; // ---- Non Uni-Link Bus Stop Overlay private BusStopOverlay nonUniLinkBusStopOverlay; private static final int NON_UNI_LINK_BUS_STOP_OVERLAY_RANK = 4; // -- Site Overlays static final String[] SITE_NAMES = { "Highfield Campus", "Boldrewood Campus", "Avenue Campus", "Winchester School of Art", "The University of Southampton Science Park", "National Oceanography Centre Campus", "Boat House", "Southampton General Hospital", "Royal South Hants Hospital", "Belgrave Industrial Site", "Highfield Hall", "Glen Eyre Hall", "South Hill Hall", "Chamberlain Hall", "Hartley Grove", "Bencraft Hall", "Connaught Hall", "Montefiore Hall", "Stoneham Hall", "Erasmus Park" }; private static final String SITE_OVERLAYS = "siteOverlays:"; private HashMap siteOverlays = new HashMap(21); static final boolean SITE_OVERLAYS_ENABLED_BY_DEFAULT = false; private static final int SITE_OVERLAYS_RANK = 8; // -- Route Overlays private static final String BUS_ROUTE_OVERLAYS = "routeOverlays:"; private HashMap busRouteOverlays = new HashMap(5); static final boolean BUS_ROUTE_OVERLAYS_ENABLED_BY_DEFAULT = true; private static final int BUS_ROUTE_OVERLAYS_RANK = 7; // -- Other static final String OTHER_OVERLAYS = "otherOverlay:"; // ---- Scale Bar Overlay private static final String SCALE_BAR_OVERLAY = "scaleBarOverlay"; private ScaleBarOverlay scaleBarOverlay; static final boolean SCALE_BAR_OVERLAY_ENABLED_BY_DEFAULT = true; private static final int SCALE_BAR_OVERLAY_RANK = 1; // ---- My Location Overlay private static final String MY_LOCATION_OVERLAY = "myLocationOverlay"; private static final String MY_LOCATION_OVERLAY_COMPASS = "myLocationOverlayCompass"; private MyLocationOverlay myLocationOverlay; static final boolean MY_LOCATION_OVERLAY_ENABLED_BY_DEFAULT = true; static final boolean MY_LOCATION_OVERLAY_COMPASS_ENABLED_BY_DEFAULT = true; private static final int MY_LOCATION_OVERLAY_RANK = 2; static final String[] OTHER_OVERLAY_NAMES = { SCALE_BAR_OVERLAY, MY_LOCATION_OVERLAY_COMPASS, MY_LOCATION_OVERLAY }; // Other bits // Uni-Link routes static final String[] UNI_LINK_ROUTES = { "U1", "U1N", "U2", "U6", "U9" }; static final String[] PREFERENCES_GROUPS = { BUS_STOP_OVERLAYS, BUS_ROUTE_OVERLAYS, BUILDING_OVERLAYS, SITE_OVERLAYS, OTHER_OVERLAYS }; static final String[][] PREFERENCES_CHILDREN = { UNI_LINK_ROUTES, UNI_LINK_ROUTES, BUILDING_TYPES, SITE_NAMES, OTHER_OVERLAY_NAMES }; private MapActivity instance; private static final String TAG = "SUM"; @SuppressWarnings("unchecked") public void onCreate(Bundle savedInstanceState) { startTime = System.currentTimeMillis(); super.onCreate(savedInstanceState); instance = this; Thread databaseThread = new Thread(this); // Start the database thread databaseThread.start(); setContentView(R.layout.map_activity); Log.i(TAG, "Finished setting content view " + (System.currentTimeMillis() - startTime)); mapView = (MapView) this.findViewById(R.id.mapview); mapView.setTileSource(TileSourceFactory.MAPQUESTOSM); mapView.setBuiltInZoomControls(true); mapView.setMultiTouchControls(true); pastOverlays = (HashMap) getLastNonConfigurationInstance(); /* * SensorManager mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); This code in the following * constructor causes problems in some emulators, disable sensors to fix. */ Log.i(TAG, "Starting creating myLocationOverlay"); myLocationOverlay = new MyLocationOverlay(instance, mapView); myLocationOverlay.setEnabled(true); Log.i(TAG, "Finished creating myLocationOverlay"); while (databaseThread.isAlive()) { Thread.yield(); } new Thread(new Runnable() { public void run() { Thread.currentThread().setPriority(Thread.MAX_PRIORITY); try { showOverlays(); } catch (SQLException e) { e.printStackTrace(); } } }).start(); Log.i(TAG, "Started loading thread " + (System.currentTimeMillis() - startTime)); mapController = mapView.getController(); mResourceProxy = new DefaultResourceProxyImpl(getApplicationContext()); GeoPoint userLocation = null; Bundle extras = getIntent().getExtras(); if (getIntent().getDataString() != null) { Log.i(TAG, "getIntent().getDataString() " + getIntent().getDataString()); String str = getIntent().getDataString().substring(4, getIntent().getDataString().length()); String[] strParts = str.split(","); int lat = Util.doubleToIntE6(Double.valueOf(strParts[0])); int lng; if (strParts[1].contains("?")) { String zoom = strParts[1].substring(strParts[1].indexOf("?") + 3, strParts[1].length()); String strLng = strParts[1].substring(0, strParts[1].indexOf("?") - 1); lng = Util.doubleToIntE6(Double.valueOf(strLng)); mapController.setZoom(Integer.valueOf(zoom)); } else { lng = Util.doubleToIntE6(Double.valueOf(strParts[1])); mapController.setZoom(15); } userLocation = new GeoPoint(lat, lng); } else if (extras != null && extras.containsKey("poiPoint")) { String poiPoint = getIntent().getExtras().getString("poiPoint"); Log.i(TAG, "poiPoint " + poiPoint); String[] bits = poiPoint.split(","); userLocation = new GeoPoint(Double.valueOf(bits[0]), Double.valueOf(bits[1])); mapController.setZoom(20); } else { userLocation = myLocationOverlay.getMyLocation(); if (userLocation == null) { userLocation = new GeoPoint(50935551, -1393488); // ECS } mapController.setZoom(15); } mapController.setCenter(userLocation); Log.i(TAG, "Finished onCreate " + (System.currentTimeMillis() - startTime)); } public void onResume() { super.onResume(); Log.i(TAG, "OnResume"); if (myLocationOverlay != null) { final SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this); final SharedPreferences activityPrefs = getPreferences(0); if (activityPrefs.getBoolean(OTHER_OVERLAYS + MY_LOCATION_OVERLAY_COMPASS, MY_LOCATION_OVERLAY_COMPASS_ENABLED_BY_DEFAULT)) { myLocationOverlay.enableCompass(); } else { myLocationOverlay.disableCompass(); } if (activityPrefs.getBoolean(OTHER_OVERLAYS + MY_LOCATION_OVERLAY, MY_LOCATION_OVERLAY_ENABLED_BY_DEFAULT) && sharedPrefs.getBoolean(GPS_ENABLED, GPS_ENABLED_BY_DEFAULT)) { // The following can cause problems in some emulators, myLocationOverlay.enableMyLocation(); } else { myLocationOverlay.disableMyLocation(); } sharedPrefs.registerOnSharedPreferenceChangeListener(this); activityPrefs.registerOnSharedPreferenceChangeListener(this); } Log.i(TAG, "Finished OnResume"); } public void onPause() { super.onResume(); Log.i(TAG, "OnPause"); if (myLocationOverlay != null) { myLocationOverlay.disableMyLocation(); myLocationOverlay.disableCompass(); } } public void finish() { super.finish(); } @Override public Object onRetainNonConfigurationInstance() { return overlays; } public void run() { Log.i(TAG, "Begining loading database " + (System.currentTimeMillis() - startTime)); DatabaseHelper helper = getHelper(); Log.i(TAG, "Got the helper at " + (System.currentTimeMillis() - startTime)); boolean dbExist = helper.checkDataBase(); Log.i(TAG, "Finished checking the database at " + (System.currentTimeMillis() - startTime)); if (dbExist) { // do nothing - database already exist } else { if (useBundledDatabase) { try { // By calling this method and empty database will be created // into the default system path // of your application so we are gonna be able to overwrite // that database with our database. Log.i(TAG, "GetReadableDatabase"); helper.getWritableDatabase().close(); helper.copyDataBase(); Log.i(TAG, "Out of copy database"); } catch (IOException ioe) { throw new Error("Unable to create database"); } } else { Thread buildingThread = null; Thread busStopThread = null; Thread siteThread = null; Log.i(TAG, "Begining loading databases " + (System.currentTimeMillis() - startTime)); try { Dao buildingDao; buildingDao = helper.getBuildingDao(); long buildingCount = buildingDao.countOf(); Log.i(TAG, "Building count " + buildingCount); if (buildingCount < 260) { buildingThread = new Thread(new Runnable() { public void run() { try { DataManager.loadBuildings(instance); Log.i(TAG, "Loaded building database " + (System.currentTimeMillis() - startTime)); } catch (SQLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }); buildingThread.start(); } Dao busStopDao = helper.getBusStopDao(); Dao busRouteDao = helper.getBusRouteDao(); Dao routeStopsDao = helper.getRouteStopsDao(); long busStopCount = busStopDao.countOf(); long busRouteCount = busRouteDao.countOf(); long routeStopsCount = routeStopsDao.countOf(); Log.i(TAG, "BusStop count " + busStopCount); Log.i(TAG, "BusRoute count " + busRouteCount); Log.i(TAG, "RouteStops count " + routeStopsCount); if (busStopCount < 217 || busRouteCount < 5 || routeStopsCount < 327) { busStopThread = new Thread(new Runnable() { public void run() { try { DataManager.loadBusData(instance, true); Log.i(TAG, "Loaded bus stop database " + (System.currentTimeMillis() - startTime)); } catch (SQLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }); busStopThread.start(); } Dao siteDao = helper.getSiteDao(); long siteCount = siteDao.countOf(); Log.i(TAG, "Sites count " + siteCount); if (siteCount < 21) { siteThread = new Thread(new Runnable() { public void run() { try { DataManager.loadSiteData(instance); Log.i(TAG, "Loaded site database " + (System.currentTimeMillis() - startTime)); } catch (SQLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }); siteThread.start(); } while (true) { if ((buildingThread == null || !buildingThread.isAlive()) && (busStopThread == null || !busStopThread.isAlive()) && (siteThread == null || !siteThread.isAlive())) break; Thread.yield(); } Log.i(TAG, "Finished loading databases " + (System.currentTimeMillis() - startTime)); } catch (SQLException e1) { e1.printStackTrace(); } } } Log.i(TAG, "Begining setting up the static values " + (System.currentTimeMillis() - startTime)); Log.i(TAG, "Finished the database thread " + (System.currentTimeMillis() - startTime)); } private void showOverlays() throws SQLException { Log.i(TAG, "Began showing overlays at " + (System.currentTimeMillis() - startTime)); if (pastOverlays != null) { Log.i(TAG, "Able to recover some/all of the overlays from a previous activity"); } else { Log.i(TAG, "Unable to recover overlays"); } final SharedPreferences activityPrefs = getPreferences(0); showUtilityOverlays(); showUniLinkBusStopOverlay(); showNonUniLinkBusStopOverlay(); if (activityPrefs.getBoolean(BUILDING_OVERLAYS + RESIDENTIAL_BUILDING_OVERLAY, RESIDENTIAL_BUILDING_OVERLAY_ENABLED_BY_DEFAULT) || activityPrefs.getBoolean(BUILDING_OVERLAYS + NON_RESIDENTIAL_BUILDING_OVERLAY, NON_RESIDENTIAL_BUILDING_OVERLAY_ENABLED_BY_DEFAULT)) { showBuildingOverlays(); } Log.i(TAG, "Begining to show the route overlays at " + (System.currentTimeMillis() - startTime)); for (BusRoute busRoute : getHelper().getBusRouteDao()) { if (!busRoute.uniLink) { Log.v(TAG, "Bus route " + busRoute.code + "(" + busRoute.id + ") is not unilink"); continue; } Log.v(TAG, "Looking at showing " + busRoute.code + " route overlay"); if (activityPrefs.getBoolean(BUS_ROUTE_OVERLAYS + busRoute.code, BUS_ROUTE_OVERLAYS_ENABLED_BY_DEFAULT)) { showRouteOverlay(busRoute); } } Log.i(TAG, "Finished loading routes " + (System.currentTimeMillis() - startTime)); Log.i(TAG, "Begining to show the site overlays at " + (System.currentTimeMillis() - startTime)); try { for (Site site : getHelper().getSiteDao()) { Log.v(TAG, "Looking at showing " + site.name + " site overlay"); if (activityPrefs.getBoolean(SITE_OVERLAYS + site.name, SITE_OVERLAYS_ENABLED_BY_DEFAULT)) { showSiteOverlay(site); } } } catch (SQLException e) { e.printStackTrace(); } Log.i(TAG, "Finished showing the site overlays " + (System.currentTimeMillis() - startTime)); Log.i(TAG, "Finished showing all the overlays " + (System.currentTimeMillis() - startTime)); } private void showUtilityOverlays() { new Thread(new Runnable() { public void run() { Log.i(TAG, "Begining showing the utility overlays " + (System.currentTimeMillis() - startTime)); final SharedPreferences activityPrefs = getPreferences(0); final OverlayRankComparator comparator = new OverlayRankComparator(getPreferences(0)); if (scaleBarOverlay != null) { Log.v(TAG, "ScaleBarOverlay is already created"); } else { if (pastOverlays != null && (scaleBarOverlay = (ScaleBarOverlay) pastOverlays.get(SCALE_BAR_OVERLAY)) != null) { Log.i(TAG, "Finished restoring utility overlays " + (System.currentTimeMillis() - startTime)); } else { scaleBarOverlay = new ScaleBarOverlay(instance); } overlays.put(SCALE_BAR_OVERLAY, scaleBarOverlay); synchronized (mapView.getOverlays()) { mapView.getOverlays().add(scaleBarOverlay); mapView.getOverlays().add(myLocationOverlay); Collections.sort(mapView.getOverlays(), comparator); } } scaleBarOverlay.setEnabled(activityPrefs.getBoolean(OTHER_OVERLAYS + SCALE_BAR_OVERLAY, SCALE_BAR_OVERLAY_ENABLED_BY_DEFAULT)); mapView.postInvalidate(); Log.i(TAG, "Finished showing utility overlays " + (System.currentTimeMillis() - startTime)); } }).start(); } private void showRouteOverlay(final BusRoute route) { new Thread(new Runnable() { public void run() { Log.i(TAG, "Begining showing route " + route.code + " overlay at " + (System.currentTimeMillis() - startTime)); final SharedPreferences activityPrefs = getPreferences(0); final OverlayRankComparator comparator = new OverlayRankComparator(getPreferences(0)); PathOverlay routeOverlay; if ((routeOverlay = busRouteOverlays.get(route)) != null) { Log.v(TAG, route.code + " route overlay already existed"); } else { if (pastOverlays != null && (routeOverlay = (PathOverlay) pastOverlays.get(BUS_ROUTE_OVERLAYS + route.code)) != null) { Log.v(TAG, "Restored " + route.code + " route overlay"); if (route.code.equals("U1")) { PathOverlay routeOverlayU1E = (PathOverlay) pastOverlays.get(BUS_ROUTE_OVERLAYS + "U1E"); overlays.put(BUS_ROUTE_OVERLAYS + "U1E", routeOverlayU1E); } } else { InputStream resource = null; int colour = 0; if (route.code.equals("U1")) { resource = getResources().openRawResource(R.raw.u1); colour = U1; // TODO Is this a route like U1N or, something else, // this hack works somewhat for now? PathOverlay routeOverlayU1E = DataManager.getRoutePath(getResources().openRawResource(R.raw.u1e), colour, mResourceProxy); routeOverlayU1E.getPaint().setAntiAlias(true); routeOverlayU1E.getPaint().setAlpha(145); routeOverlayU1E.getPaint().setStrokeWidth(12); routeOverlayU1E.getPaint().setPathEffect(new DashPathEffect(new float[] { 20, 16 }, 0)); busRouteOverlays.put(new BusRoute(1000, "U1E", "U1E Route Label", true), routeOverlayU1E); overlays.put(BUS_ROUTE_OVERLAYS + "U1E", routeOverlayU1E); synchronized (mapView.getOverlays()) { mapView.getOverlays().add(routeOverlayU1E); } } else if (route.code.equals("U1N")) { resource = getResources().openRawResource(R.raw.u1n); colour = U1N; } else if (route.code.equals("U2")) { resource = getResources().openRawResource(R.raw.u2); colour = U2; } else if (route.code.equals("U6")) { resource = getResources().openRawResource(R.raw.u6); colour = U6; } else if (route.code.equals("U9")) { resource = getResources().openRawResource(R.raw.u9); colour = U9; } else { Log.w(TAG, "Wierd route " + route); } routeOverlay = DataManager.getRoutePath(resource, colour, mResourceProxy); Log.v(TAG, "Path overlay has " + routeOverlay.getNumberOfPoints() + " points"); routeOverlay.getPaint().setAntiAlias(true); routeOverlay.getPaint().setAlpha(145); routeOverlay.getPaint().setStrokeWidth(12); } busRouteOverlays.put(route, routeOverlay); overlays.put(BUS_ROUTE_OVERLAYS + route.code, routeOverlay); synchronized (mapView.getOverlays()) { mapView.getOverlays().add(routeOverlay); Collections.sort(mapView.getOverlays(), comparator); } } routeOverlay.setEnabled(activityPrefs.getBoolean(BUS_ROUTE_OVERLAYS + route.code, BUS_ROUTE_OVERLAYS_ENABLED_BY_DEFAULT)); if (route.code.equals("U1")) { overlays.get(BUS_ROUTE_OVERLAYS + "U1E").setEnabled( activityPrefs.getBoolean(BUS_ROUTE_OVERLAYS + "U1", BUS_ROUTE_OVERLAYS_ENABLED_BY_DEFAULT)); } mapView.postInvalidate(); Log.i(TAG, "Finished showing route " + route.code + " overlay at " + (System.currentTimeMillis() - startTime)); } }).start(); } private void showSiteOverlay(final Site site) { new Thread(new Runnable() { public void run() { Log.i(TAG, "Begining showing site " + site.name + " overlay at " + (System.currentTimeMillis() - startTime)); final SharedPreferences activityPrefs = getPreferences(0); final OverlayRankComparator comparator = new OverlayRankComparator(getPreferences(0)); PathOverlay siteOverlay; if ((siteOverlay = siteOverlays.get(site)) != null) { } else { if (pastOverlays != null && (siteOverlay = (PathOverlay) pastOverlays.get(SITE_OVERLAYS + site.name)) != null) { Log.i(TAG, "Restored " + site.name + " site overlay"); } else { siteOverlay = new PathOverlay(Color.BLUE, instance); Paint paint = siteOverlay.getPaint(); paint.setAntiAlias(true); paint.setStrokeWidth(1.5f); for (int i = 0; i < site.outline.points.length; i++) { siteOverlay.addPoint(site.outline.points[i]); } siteOverlay.addPoint(site.outline.points[0]); } siteOverlays.put(site, siteOverlay); overlays.put(SITE_OVERLAYS + site.name, siteOverlay); Log.v(TAG, "Applyed the site overlay, now sorting them"); synchronized (mapView.getOverlays()) { mapView.getOverlays().add(siteOverlay); Collections.sort(mapView.getOverlays(), comparator); } } siteOverlay.setEnabled(activityPrefs.getBoolean(SITE_OVERLAYS + site.name, SITE_OVERLAYS_ENABLED_BY_DEFAULT)); mapView.postInvalidate(); Log.i(TAG, "Finished showing site " + site.name + " overlay at " + (System.currentTimeMillis() - startTime)); } }).start(); } private void showBuildingOverlays() { new Thread(new Runnable() { public void run() { Log.i(TAG, "Begining showing building overlays at " + (System.currentTimeMillis() - startTime)); final SharedPreferences activityPrefs = getPreferences(0); final OverlayRankComparator comparator = new OverlayRankComparator(getPreferences(0)); if (residentialBuildingOverlay != null) { } else { if (pastOverlays != null && (residentialBuildingOverlay = (BuildingNumOverlay) pastOverlays.get(RESIDENTIAL_BUILDING_OVERLAY)) != null) { nonResidentialBuildingOverlay = (BuildingNumOverlay) pastOverlays.get(NON_RESIDENTIAL_BUILDING_OVERLAY); Log.i(TAG, "Restored building overlays"); } else { try { Log.v(TAG, "Begining the creation of the building overlays"); ArrayList residentialBuildings = new ArrayList(); ArrayList nonResidentialBuildings = new ArrayList(); Dao buildingDao; buildingDao = getHelper().getBuildingDao(); final SharedPreferences favouritesPrefs = getSharedPreferences(FAVOURITES_PREFERENCES, MODE_PRIVATE); for (Building building : buildingDao) { if (building.residential == true) { if (favouritesPrefs.getBoolean(building.id, false)) { residentialBuildings.add(building); } else { residentialBuildings.add(0, building); } } else { if (favouritesPrefs.getBoolean(building.id, false)) { nonResidentialBuildings.add(building); } else { nonResidentialBuildings.add(0, building); } } } residentialBuildingOverlay = new BuildingNumOverlay(instance, residentialBuildings); nonResidentialBuildingOverlay = new BuildingNumOverlay(instance, nonResidentialBuildings); Log.v(TAG, "Applyed the site overlay, now sorting them"); } catch (SQLException e) { e.printStackTrace(); } } overlays.put(RESIDENTIAL_BUILDING_OVERLAY, residentialBuildingOverlay); overlays.put(NON_RESIDENTIAL_BUILDING_OVERLAY, nonResidentialBuildingOverlay); synchronized (mapView.getOverlays()) { mapView.getOverlays().add(residentialBuildingOverlay); mapView.getOverlays().add(nonResidentialBuildingOverlay); Collections.sort(mapView.getOverlays(), comparator); } } residentialBuildingOverlay.setEnabled(activityPrefs.getBoolean(BUILDING_OVERLAYS + RESIDENTIAL_BUILDING_OVERLAY, RESIDENTIAL_BUILDING_OVERLAY_ENABLED_BY_DEFAULT)); nonResidentialBuildingOverlay.setEnabled(activityPrefs.getBoolean(BUILDING_OVERLAYS + NON_RESIDENTIAL_BUILDING_OVERLAY, NON_RESIDENTIAL_BUILDING_OVERLAY_ENABLED_BY_DEFAULT)); mapView.postInvalidate(); Log.i(TAG, "Finished showing building overlays at " + (System.currentTimeMillis() - startTime)); } }).start(); } private void showUniLinkBusStopOverlay() { new Thread(new Runnable() { public void run() { Log.i(TAG, "Begining showing bus stop overlays at " + (System.currentTimeMillis() - startTime)); final SharedPreferences activityPrefs = getPreferences(0); final OverlayRankComparator comparator = new OverlayRankComparator(getPreferences(0)); if (uniLinkBusStopOverlay != null) { if (!activityPrefs.getBoolean(BUS_STOP_OVERLAYS + "U1", UNI_LINK_BUS_STOP_OVERLAY_ENABLED_BY_DEFAULT) && !activityPrefs.getBoolean(BUS_STOP_OVERLAYS + "U1N", UNI_LINK_BUS_STOP_OVERLAY_ENABLED_BY_DEFAULT) && !activityPrefs.getBoolean(BUS_STOP_OVERLAYS + "U2", UNI_LINK_BUS_STOP_OVERLAY_ENABLED_BY_DEFAULT) && !activityPrefs.getBoolean(BUS_STOP_OVERLAYS + "U6", UNI_LINK_BUS_STOP_OVERLAY_ENABLED_BY_DEFAULT) && !activityPrefs.getBoolean(BUS_STOP_OVERLAYS + "U9", UNI_LINK_BUS_STOP_OVERLAY_ENABLED_BY_DEFAULT)) { Log.i(TAG, "Uni-Link bus stop overlay not needed"); overlays.remove(UNI_LINK_BUS_STOP_OVERLAY); synchronized (mapView.getOverlays()) { mapView.getOverlays().remove(uniLinkBusStopOverlay); Collections.sort(mapView.getOverlays(), comparator); } uniLinkBusStopOverlay = null; } else { uniLinkBusStopOverlay.setRoutes(0, activityPrefs.getBoolean(BUS_STOP_OVERLAYS + "U1", UNI_LINK_BUS_STOP_OVERLAY_ENABLED_BY_DEFAULT)); uniLinkBusStopOverlay.setRoutes(1, activityPrefs.getBoolean(BUS_STOP_OVERLAYS + "U1N", UNI_LINK_BUS_STOP_OVERLAY_ENABLED_BY_DEFAULT)); uniLinkBusStopOverlay.setRoutes(2, activityPrefs.getBoolean(BUS_STOP_OVERLAYS + "U2", UNI_LINK_BUS_STOP_OVERLAY_ENABLED_BY_DEFAULT)); uniLinkBusStopOverlay.setRoutes(3, activityPrefs.getBoolean(BUS_STOP_OVERLAYS + "U6", UNI_LINK_BUS_STOP_OVERLAY_ENABLED_BY_DEFAULT)); uniLinkBusStopOverlay.setRoutes(4, activityPrefs.getBoolean(BUS_STOP_OVERLAYS + "U9", UNI_LINK_BUS_STOP_OVERLAY_ENABLED_BY_DEFAULT)); } } else { if (activityPrefs.getBoolean(BUS_STOP_OVERLAYS + "U1", UNI_LINK_BUS_STOP_OVERLAY_ENABLED_BY_DEFAULT) || activityPrefs.getBoolean(BUS_STOP_OVERLAYS + "U1N", UNI_LINK_BUS_STOP_OVERLAY_ENABLED_BY_DEFAULT) || activityPrefs.getBoolean(BUS_STOP_OVERLAYS + "U2", UNI_LINK_BUS_STOP_OVERLAY_ENABLED_BY_DEFAULT) || activityPrefs.getBoolean(BUS_STOP_OVERLAYS + "U6", UNI_LINK_BUS_STOP_OVERLAY_ENABLED_BY_DEFAULT) || activityPrefs.getBoolean(BUS_STOP_OVERLAYS + "U9", UNI_LINK_BUS_STOP_OVERLAY_ENABLED_BY_DEFAULT)) { if (pastOverlays != null && (uniLinkBusStopOverlay = (BusStopOverlay) pastOverlays.get(UNI_LINK_BUS_STOP_OVERLAY)) != null) { Log.i(TAG, "Restored Uni-Link bus stop overlay"); } else { try { List busStops; Log.v(TAG, "Begin fetching BusStops at " + (System.currentTimeMillis() - startTime)); busStops = getHelper().getBusStopDao().queryForEq(BusStop.UNI_LINK_FIELD_NAME, true); Log.v(TAG, "Finished fetching BusStops at " + (System.currentTimeMillis() - startTime)); uniLinkBusStopOverlay = new BusStopOverlay(instance, busStops); } catch (SQLException e) { e.printStackTrace(); } } uniLinkBusStopOverlay.setRoutes(0, activityPrefs.getBoolean(BUS_STOP_OVERLAYS + "U1", UNI_LINK_BUS_STOP_OVERLAY_ENABLED_BY_DEFAULT)); uniLinkBusStopOverlay.setRoutes(1, activityPrefs.getBoolean(BUS_STOP_OVERLAYS + "U1N", UNI_LINK_BUS_STOP_OVERLAY_ENABLED_BY_DEFAULT)); uniLinkBusStopOverlay.setRoutes(2, activityPrefs.getBoolean(BUS_STOP_OVERLAYS + "U2", UNI_LINK_BUS_STOP_OVERLAY_ENABLED_BY_DEFAULT)); uniLinkBusStopOverlay.setRoutes(3, activityPrefs.getBoolean(BUS_STOP_OVERLAYS + "U6", UNI_LINK_BUS_STOP_OVERLAY_ENABLED_BY_DEFAULT)); uniLinkBusStopOverlay.setRoutes(4, activityPrefs.getBoolean(BUS_STOP_OVERLAYS + "U9", UNI_LINK_BUS_STOP_OVERLAY_ENABLED_BY_DEFAULT)); overlays.put(UNI_LINK_BUS_STOP_OVERLAY, uniLinkBusStopOverlay); Log.v(TAG, "Applyed the site overlay, now sorting them"); synchronized (mapView.getOverlays()) { mapView.getOverlays().add(uniLinkBusStopOverlay); Collections.sort(mapView.getOverlays(), comparator); } } } mapView.postInvalidate(); Log.i(TAG, "Finished showing bus stop overlays at " + (System.currentTimeMillis() - startTime)); } }).start(); } private void showNonUniLinkBusStopOverlay() { new Thread(new Runnable() { public void run() { Log.i(TAG, "Begining showing non uni link bus stop overlays at " + (System.currentTimeMillis() - startTime)); // final SharedPreferences activityPrefs = getPreferences(0); final SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(instance); final OverlayRankComparator comparator = new OverlayRankComparator(getPreferences(0)); if (nonUniLinkBusStopOverlay != null) { nonUniLinkBusStopOverlay.setEnabled(sharedPrefs.getBoolean(NON_UNI_LINK_BUS_STOPS_OVERLAY, NON_UNI_LINK_BUS_STOP_OVERLAY_ENABLED_BY_DEFAULT)); Log.i(TAG, "nonUniLinkBusStopOverlay enabled ? " + sharedPrefs.getBoolean(NON_UNI_LINK_BUS_STOPS_OVERLAY, NON_UNI_LINK_BUS_STOP_OVERLAY_ENABLED_BY_DEFAULT)); } else if (sharedPrefs.getBoolean(NON_UNI_LINK_BUS_STOPS_OVERLAY, NON_UNI_LINK_BUS_STOP_OVERLAY_ENABLED_BY_DEFAULT)) { if (pastOverlays != null && (nonUniLinkBusStopOverlay = (BusStopOverlay) pastOverlays.get(NON_UNI_LINK_BUS_STOPS_OVERLAY)) != null) { Log.i(TAG, "Restored non Uni-Link bus stop overlays"); } else { try { List busStops; Log.v(TAG, "Begin fetching non Uni-Link BusStops at " + (System.currentTimeMillis() - startTime)); busStops = getHelper().getBusStopDao().queryForEq(BusStop.UNI_LINK_FIELD_NAME, false); Log.v(TAG, "Finished fetching " + busStops.size() + " non Uni-Link BusStops at " + (System.currentTimeMillis() - startTime)); nonUniLinkBusStopOverlay = new BusStopOverlay(instance, busStops); } catch (SQLException e) { e.printStackTrace(); } } overlays.put(NON_UNI_LINK_BUS_STOPS_OVERLAY, nonUniLinkBusStopOverlay); Log.v(TAG, "Applyed the site overlay, now sorting them"); synchronized (mapView.getOverlays()) { mapView.getOverlays().add(nonUniLinkBusStopOverlay); Collections.sort(mapView.getOverlays(), comparator); } } if (nonUniLinkBusStopOverlay != null) { } mapView.postInvalidate(); Log.i(TAG, "Finished showing non Uni-Link bus stop overlays at " + (System.currentTimeMillis() - startTime)); } }).start(); } @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.map_menu, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle item selection switch (item.getItemId()) { case R.id.menu_find: Intent i = new Intent(MapActivity.this, FindActivity.class); startActivityForResult(i, 0); return true; case R.id.menu_preferences: Intent settingsActivity = new Intent(getBaseContext(), PreferencesActivity.class); startActivity(settingsActivity); return true; case R.id.menu_find_my_location: final SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this); final SharedPreferences activityPrefs = getPreferences(0); if (sharedPrefs.getBoolean(GPS_ENABLED, GPS_ENABLED_BY_DEFAULT)) { activityPrefs.edit().putBoolean(OTHER_OVERLAYS + MY_LOCATION_OVERLAY, true).commit(); myLocationOverlay.enableFollowLocation(); mapController.setZoom(18); } else { DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { switch (which) { case DialogInterface.BUTTON_POSITIVE: Editor editor = sharedPrefs.edit(); editor.putBoolean(GPS_ENABLED, true); editor.commit(); activityPrefs.edit().putBoolean(OTHER_OVERLAYS + MY_LOCATION_OVERLAY, true).commit(); myLocationOverlay.enableFollowLocation(); mapController.setZoom(18); case DialogInterface.BUTTON_NEGATIVE: // No button clicked break; } } }; AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setMessage("GPS is not enabled, do you wish to enable it?").setPositiveButton("Yes", dialogClickListener) .setNegativeButton("No", dialogClickListener).show(); } return true; case R.id.menu_view: Log.i(TAG, "Showing view dialog"); showDialog(VIEW_DIALOG_ID); return false; case R.id.menu_favourites: Log.i(TAG, "Showing favourite dialog"); showDialog(FAVOURITE_DIALOG_ID); if (favDialog == null) { Log.e(TAG, "Very wierd, just tried to launch the favourite's dialog, but its null?"); return false; } refreshFavouriteDialog(); return false; case R.id.menu_about: Intent aboutIntent = new Intent(MapActivity.this, AboutActivity.class); startActivityForResult(aboutIntent, 0); return true; default: Log.e(TAG, "No known menu option selected"); return super.onOptionsItemSelected(item); } } private void refreshFavouriteDialog() { ArrayList newFavouriteItems = new ArrayList(); try { Dao buildingDao = getHelper().getBuildingDao(); Dao busStopDao = getHelper().getBusStopDao(); final SharedPreferences favouritesPrefs = getSharedPreferences(FAVOURITES_PREFERENCES, MODE_PRIVATE); for (String id : favouritesPrefs.getAll().keySet()) { Building building; BusStop busStop; if ((building = buildingDao.queryForId(id)) != null) { newFavouriteItems.add(building); } else if ((busStop = busStopDao.queryForId(id)) != null) { newFavouriteItems.add(busStop); } else { Log.e(TAG, "Item in favourites " + id + " cannot be found"); } } } catch (SQLException e) { e.printStackTrace(); } Log.i(TAG, "There are " + newFavouriteItems.size() + " favourites"); if (newFavouriteItems.size() == 0) { Log.i(TAG, "Favourite dialog has no favourites, displaying message"); favDialog.setMessage(getResources().getString(R.string.favourites_dialog_message)); favDialog.setItems(null); } else { favDialog.setMessage(""); favDialog.setItems(newFavouriteItems); } } @Override public boolean onSearchRequested() { Intent i = new Intent(MapActivity.this, FindActivity.class); startActivityForResult(i, 0); return false; } protected void onActivityResult(int requestCode, int resultCode, Intent data) { Log.i(TAG, "Got activity result"); if (resultCode == RESULT_OK) { POI poi = null; Bundle bundle = data.getExtras(); if (bundle == null) { Log.i(TAG, "Bundle is null"); } else { String poiId = (String) bundle.get("poi"); if (poiId != null) { Log.i(TAG, "Got id " + poiId); try { poi = getHelper().getBuildingDao().queryForId(poiId); if (poi == null) { poi = getHelper().getBusStopDao().queryForId(poiId); } } catch (SQLException e) { e.printStackTrace(); } if (poi == null) { Log.e(TAG, "Could not find poi " + poiId + " in onActivityResult"); } else { if (myLocationOverlay != null) { // It could be null if it has not been enabled myLocationOverlay.disableFollowLocation(); } mapController.setZoom(20); mapController.setCenter(poi.point); } } else { Log.i(TAG, "Got null poi id"); } if (favDialog != null) { refreshFavouriteDialog(); } mapView.invalidate(); } } } protected Dialog onCreateDialog(int id) { switch (id) { case VIEW_DIALOG_ID: ViewDialog viewDialog = new ViewDialog(instance); return viewDialog; case FAVOURITE_DIALOG_ID: favDialog = new POIDialog(instance); favDialog.setOnItemClickListener(this); favDialog.setOnItemLongClickListener(this); favDialog.setTitle(R.string.favourites_dialog_title); return favDialog; } return null; } public void onItemClick(AdapterView parent, View view, int position, long id) { Log.i(TAG, "OnItemClick pos " + position + " id " + id); String poiId = favDialog.adapter.getItemStringId(position); Log.i(TAG, "POI " + poiId + " selected"); POI poi = null; if (poiId != null) { Log.i(TAG, "Got id " + poiId); try { poi = getHelper().getBuildingDao().queryForId(poiId); if (poi == null) { poi = getHelper().getBusStopDao().queryForId(poiId); } } catch (SQLException e) { e.printStackTrace(); } if (poi == null) { Log.e(TAG, "Could not find poi " + poiId + " in onActivityResult"); } else { if (myLocationOverlay != null) { myLocationOverlay.disableFollowLocation(); } mapController.setZoom(20); mapController.setCenter(poi.point); favDialog.dismiss(); } } else { Log.i(TAG, "Got null poi id"); // mapController.setZoom(15); // mapController.setCenter(new GeoPoint(50935551, -1393488)); } } /** * Long click on a item in the favourites menu */ public boolean onItemLongClick(AdapterView parent, View view, int position, long id) { Log.i(TAG, "OnItemClick pos " + position + " id " + id); String poiId = favDialog.adapter.getItemStringId(position); Log.i(TAG, "POI " + poiId + " selected"); POI poi = null; if (poiId != null) { Log.i(TAG, "Got id " + poiId); try { poi = getHelper().getBuildingDao().queryForId(poiId); if (poi == null) { poi = getHelper().getBusStopDao().queryForId(poiId); } } catch (SQLException e) { e.printStackTrace(); } if (poi == null) { Log.e(TAG, "Could not find poi " + poiId + " in onActivityResult"); } else { if (poi.type == POI.BUS_STOP) { BusStop busStop = (BusStop) poi; Log.i(TAG, "Pressed " + busStop.id); Uri uri = Uri.parse("http://id.southampton.ac.uk/bus-stop/" + busStop.id); Log.i(TAG, "Starting a activity for " + uri + " path " + uri.getPath()); Intent busStopIntent = new Intent(Intent.ACTION_VIEW, uri); startActivity(busStopIntent); return true; } else if (poi.type == POI.BUILDING) { Building building = (Building) poi; Log.i(TAG, "Pressed " + building.id); Uri uri = Uri.parse("http://id.southampton.ac.uk/building/" + building.id); Log.i(TAG, "Starting a activity for " + uri + " path " + uri.getPath()); Intent buildingIntent = new Intent(Intent.ACTION_VIEW, uri); startActivity(buildingIntent); return true; } else { myLocationOverlay.disableFollowLocation(); mapController.setZoom(20); mapController.setCenter(poi.point); favDialog.dismiss(); favDialog = null; } } } else { Log.i(TAG, "Got null poi id"); // mapController.setZoom(15); // mapController.setCenter(new GeoPoint(50935551, -1393488)); } return true; } private class OverlayRankComparator implements Comparator { // private final SharedPreferences prefs; OverlayRankComparator(SharedPreferences prefs) { // this.prefs = prefs; } public int compare(Overlay arg0, Overlay arg1) { return getRank(arg1) - getRank(arg0); } private final int getRank(Overlay overlay) { // TODO: Dont hardcode the // rank values if (overlay == scaleBarOverlay) { return SCALE_BAR_OVERLAY_RANK; } else if (overlay == myLocationOverlay) { return MY_LOCATION_OVERLAY_RANK; } else if (overlay == uniLinkBusStopOverlay) { return UNI_LINK_BUS_STOP_OVERLAY_RANK; } else if (overlay == nonUniLinkBusStopOverlay) { return NON_UNI_LINK_BUS_STOP_OVERLAY_RANK; } else if (overlay.equals(residentialBuildingOverlay)) { return RESIDENTIAL_BUILDING_OVERLAY_RANK; } else if (overlay.equals(nonResidentialBuildingOverlay)) { return NON_RESIDENTIAL_BUILDING_OVERLAY_RANK; } else if (siteOverlays != null && siteOverlays.values().contains(overlay)) { return SITE_OVERLAYS_RANK; } else if (busRouteOverlays != null && busRouteOverlays.values().contains(overlay)) { return BUS_ROUTE_OVERLAYS_RANK; } else { Log.e(TAG, "Trying to rank unknown overlay " + overlay); return -1; } } } /** * Handles all changes in preferences */ public void onSharedPreferenceChanged(SharedPreferences prefs, String key) { Log.v(TAG, "Got shared prefs changed event for key " + key); // Shared Preferences if (key.equals(GPS_ENABLED)) { final SharedPreferences activityPrefs = getPreferences(0); if (activityPrefs.getBoolean("Other:Compass", false) && prefs.getBoolean("GPSEnabled", false)) { myLocationOverlay.enableMyLocation(); } else { myLocationOverlay.disableMyLocation(); } } else if (key.equals(NON_UNI_LINK_BUS_TIMES)) { // Noting to do here atm } else if (key.equals(UNI_LINK_BUS_TIMES)) { // Noting to do here atm } else if (key.startsWith(BUS_STOP_OVERLAYS)) { showUniLinkBusStopOverlay(); } else if (key.equals(NON_UNI_LINK_BUS_STOPS_OVERLAY)) { showNonUniLinkBusStopOverlay(); } else if (key.startsWith(BUS_ROUTE_OVERLAYS)) { try { String routeName = key.substring(BUS_ROUTE_OVERLAYS.length(), key.length()); for (BusRoute route : getHelper().getBusRouteDao()) { Log.v(TAG, route.code + " " + routeName); if (route.code.equals(routeName)) { showRouteOverlay(route); } } } catch (SQLException e) { e.printStackTrace(); } } else if (key.startsWith(BUILDING_OVERLAYS)) { showBuildingOverlays(); } else if (key.startsWith(SITE_OVERLAYS)) { String siteName = key.substring(SITE_OVERLAYS.length(), key.length()); try { for (Site site : getHelper().getSiteDao()) { if (site.name.equals(siteName)) { showSiteOverlay(site); } } } catch (SQLException e) { e.printStackTrace(); } } else if (key.startsWith(OTHER_OVERLAYS)) { if (key.substring(OTHER_OVERLAYS.length(), key.length()).equals(SCALE_BAR_OVERLAY)) { showUtilityOverlays(); } else if (key.substring(OTHER_OVERLAYS.length(), key.length()).equals(MY_LOCATION_OVERLAY_COMPASS)) { if (prefs.getBoolean(key, MY_LOCATION_OVERLAY_COMPASS_ENABLED_BY_DEFAULT)) { myLocationOverlay.enableCompass(); } else { myLocationOverlay.disableCompass(); } mapView.invalidate(); } else if (key.substring(OTHER_OVERLAYS.length(), key.length()).equals(MY_LOCATION_OVERLAY)) { final SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this); if (prefs.getBoolean(key, MY_LOCATION_OVERLAY_ENABLED_BY_DEFAULT) && sharedPrefs.getBoolean(GPS_ENABLED, GPS_ENABLED_BY_DEFAULT)) { myLocationOverlay.enableMyLocation(); myLocationOverlay.setDrawAccuracyEnabled(true); } else { myLocationOverlay.disableMyLocation(); myLocationOverlay.setDrawAccuracyEnabled(false); } } else { Log.e(TAG, "Unhandled preference key " + key); } } else { Log.e(TAG, "Unhandled preference key " + key); } } }