/* * Copyright (C) 2012 - 2013 Niall 'Rivernile' Scott * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors or contributors be held liable for * any damages arising from the use of this software. * * The aforementioned copyright holder(s) hereby grant you a * non-transferrable right to use this software for any purpose (including * commercial applications), and to modify it and redistribute it, subject to * the following conditions: * * 1. This notice may not be removed or altered from any file it appears in. * * 2. Any modifications made to this software, except those defined in * clause 3 of this agreement, must be released under this license, and * the source code of any modifications must be made available on a * publically accessible (and locateable) website, or sent to the * original author of this software. * * 3. Software modifications that do not alter the functionality of the * software but are simply adaptations to a specific environment are * exempt from clause 2. */ package uk.org.rivernile.edinburghbustracker.android.maps; import android.content.Context; import android.database.Cursor; import com.google.android.gms.maps.model.BitmapDescriptorFactory; import com.google.android.gms.maps.model.LatLng; import com.google.android.gms.maps.model.MarkerOptions; import java.util.HashMap; import uk.org.rivernile.android.utils.SimpleResultLoader; import uk.org.rivernile.edinburghbustracker.android.BusStopDatabase; import uk.org.rivernile.edinburghbustracker.android.R; /** * This Loader retrieves the bus stops for a given area from the bus stop * database and outputs the bus stops as a HashMap of MarkerOptions objects. * * Optionally, a service filter can be specified where only services that are * contained in the filter are returned. * * @author Niall Scott */ public class BusStopMarkerLoader extends SimpleResultLoader<HashMap<String, MarkerOptions>> { private static final int MIN_ZOOM_LEVEL = 14; private final BusStopDatabase bsd; private final double minX; private final double minY; private final double maxX; private final double maxY; private final float zoom; private String[] filteredServices; /** * Create a new BusStopMarkerLoader. * * @param context A Context instance. * @param minX The minimum X coordinate. * @param minY The minimum Y coordinate. * @param maxX The maximum X coordinate. * @param maxY The maximum Y coordinate. * @param zoom The zoom level from Google Maps. */ public BusStopMarkerLoader(final Context context, final double minX, final double minY, final double maxX, final double maxY, final float zoom) { super(context); bsd = BusStopDatabase.getInstance(context.getApplicationContext()); this.minX = minX; this.minY = minY; this.maxX = maxX; this.maxY = maxY; this.zoom = zoom; } /** * Create a new BusStopMarkerLoader. * * @param context A Context instance. * @param minX The minimum X coordinate. * @param minY The minimum Y coordinate. * @param maxX The maximum X coordinate. * @param maxY The maximum Y coordinate. * @param zoom The zoom level from Google Maps. * @param filteredServices A String array of the only services to show. */ public BusStopMarkerLoader(final Context context, final double minX, final double minY, final double maxX, final double maxY, final float zoom, final String[] filteredServices) { this(context, minX, minY, maxX, maxY, zoom); this.filteredServices = filteredServices; } /** * {@inheritDoc} */ @Override public HashMap<String, MarkerOptions> loadInBackground() { final HashMap<String, MarkerOptions> result = new HashMap<String, MarkerOptions>(); // Does the zoom level satisfy the mininum zoom requirement? if(zoom < MIN_ZOOM_LEVEL) return result; // When dealing with the Cursor externally to BusStopDatabase, then the // BusStopDatabase instance needs to be synchronized. This is so that // the database cannot be updated while it is being used. synchronized(bsd) { Cursor c; // What query to execute depends on whether filtering has been // enabled or not. if(filteredServices != null && filteredServices.length > 0) { c = bsd.getFilteredStopsByCoords(minX, minY, maxX, maxY, filteredServices); } else { c = bsd.getBusStopsByCoords(minX, minY, maxX, maxY); } if(c != null) { MarkerOptions mo; int orientation; String locality, stopCode, title; // Loop through all rows in the Cursor. while(c.moveToNext()) { // Create a new MarkerOptions... mo = new MarkerOptions(); // ...and set its options. mo.draggable(false); mo.anchor(0.5f, 1.f); // Get the stopCode. stopCode = c.getString(0); // Set the latitude and longitude. mo.position(new LatLng(c.getDouble(2), c.getDouble(3))); locality = c.getString(5); if(locality != null) { title = getContext().getString( R.string.busstop_locality, c.getString(1), locality, stopCode); } else { title = getContext().getString( R.string.busstop, c.getString(1), stopCode); } mo.title(title); orientation = c.getInt(4); // The icon to use depends on the orientation. switch(orientation) { case 0: mo.icon(BitmapDescriptorFactory.fromResource( R.drawable.mapmarker_n)); break; case 1: mo.icon(BitmapDescriptorFactory.fromResource( R.drawable.mapmarker_ne)); break; case 2: mo.icon(BitmapDescriptorFactory.fromResource( R.drawable.mapmarker_e)); break; case 3: mo.icon(BitmapDescriptorFactory.fromResource( R.drawable.mapmarker_se)); break; case 4: mo.icon(BitmapDescriptorFactory.fromResource( R.drawable.mapmarker_s)); break; case 5: mo.icon(BitmapDescriptorFactory.fromResource( R.drawable.mapmarker_sw)); break; case 6: mo.icon(BitmapDescriptorFactory.fromResource( R.drawable.mapmarker_w)); break; case 7: mo.icon(BitmapDescriptorFactory.fromResource( R.drawable.mapmarker_nw)); break; default: mo.icon(BitmapDescriptorFactory.fromResource( R.drawable.mapmarker)); break; } // Add the marker to the result HashMap. result.put(stopCode, mo); } // Remember to close the Cursor object. c.close(); } } return result; } }