/* * 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.sql.SQLException; import java.util.Collections; import java.util.List; import org.osmdroid.views.MapView; import org.osmdroid.views.MapView.Projection; import org.osmdroid.views.overlay.Overlay; import android.content.Intent; import android.content.SharedPreferences; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Paint.Style; import android.graphics.Point; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.net.Uri; import android.preference.PreferenceManager; import android.util.Log; import android.view.MotionEvent; import android.widget.Toast; public class BusStopOverlay extends Overlay implements RouteColorConstants, Preferences { List busStops; private final Point mCurScreenCoords = new Point(); private final Point mTouchScreenPoint = new Point(); private final Point mItemPoint = new Point(); private final Rect mRect = new Rect(); private final Drawable marker; private final Drawable favMarker; private final Paint paint; private static final String TAG = "BusStopOverlay"; private final MapActivity context; private float userScale = 1f; private boolean[] routes = new boolean[5]; private boolean showIdentifiers; public BusStopOverlay(MapActivity context, List busStops) throws SQLException { super(context); this.context = context; marker = context.getResources().getDrawable(R.drawable.busstop); favMarker = context.getResources().getDrawable(R.drawable.busstop_fav); showIdentifiers = PreferenceManager.getDefaultSharedPreferences(context).getBoolean(SHOW_IDENTIFIERS, SHOW_IDENTIFIERS_ENABLED_BY_DEFAULT); paint = new Paint(); paint.setStyle(Style.FILL); paint.setStrokeWidth(6); this.busStops = busStops; } void setRoutes(int route, boolean visible) { routes[route] = visible; } @Override public void draw(final Canvas canvas, final MapView mapView, final boolean shadow) { if (shadow) { return; } final float scale = mScale * userScale; final Projection pj = mapView.getProjection(); final int markerWidth = (int) (marker.getIntrinsicWidth() * userScale); final int markerHeight = (int) (marker.getIntrinsicHeight() * userScale); mRect.set(0, 0, 0 + markerWidth, 0 + markerHeight); mRect.offset(-markerWidth / 2, -markerHeight); marker.setBounds(mRect); favMarker.setBounds(mRect); final SharedPreferences favouritesPreferences = context.getSharedPreferences(FAVOURITES_PREFERENCES, 0); /* * Draw in backward cycle, so the items with the least index are on the * front. */ for (int stopNum = 0; stopNum < busStops.size(); stopNum++) { BusStop stop = busStops.get(stopNum); pj.toMapPixels(stop.point, mCurScreenCoords); if (!pj.getBoundingBox().increaseByScale(1.2f).contains(stop.point)) { continue; } byte routeNum = 0; final byte stopRoutes = stop.routes; boolean drawing = false; if (stop.uniLink) { for (int i = 0; i < 5; i++) { if ((stopRoutes & (1 << i)) != 0) { routeNum++; if (routes[i]) { drawing = true; } } } if (!drawing) continue; } if (favouritesPreferences.getBoolean(stop.id, false)) { Overlay.drawAt(canvas, favMarker, mCurScreenCoords.x, mCurScreenCoords.y, false); } else { Overlay.drawAt(canvas, marker, mCurScreenCoords.x, mCurScreenCoords.y, false); } if (stop.uniLink) { int makersPlaced = 0; final float rectLeft = mCurScreenCoords.x + (8.8f * scale); final float rectRight = rectLeft + (int) (8 * scale); int yOfsetPerMarker = (int) (10 * scale); int markerYSize = (int) (8 * scale); if (routeNum == 5) { markerYSize = (int) (5 * scale); yOfsetPerMarker = (int) (7 * scale); } else if (routeNum == 4) { markerYSize = (int) (6.5f * scale); yOfsetPerMarker = (int) (8 * scale); } for (int i = 0; i < 5; i++) { if ((stopRoutes & (1 << i)) != 0) { if (i == 0) { paint.setColor(U1); } else if (i == 1) { paint.setColor(U1N); } else if (i == 2) { paint.setColor(U2); } else if (i == 3) { paint.setColor(U6); } else if (i == 4) { paint.setColor(U9); } else { Log.e(TAG, "Unknown route code"); } canvas.drawRect(rectLeft, mCurScreenCoords.y + ((yOfsetPerMarker * makersPlaced) - (45 * scale)), rectRight, mCurScreenCoords.y + (yOfsetPerMarker * makersPlaced) - ((45 * scale) - markerYSize), paint); makersPlaced++; } } } } } @Override public boolean onSingleTapConfirmed(final MotionEvent event, final MapView mapView) { BusStop busStop = getSelectedItem(event, mapView); if (busStop == null) { // Log.v(TAG, "No busStop pressed"); return false; } else { Log.i(TAG, "busStop Pressed " + busStop.id); String str = busStop.description; if (showIdentifiers) { str += " (" + busStop.id + ")"; } str += "\n" + context.getResources().getString(R.string.map_activity_toast_help_message); context.makeToast(str, Toast.LENGTH_SHORT); return true; } } public boolean onDoubleTap(final MotionEvent event, final MapView mapView) { BusStop busStop = getSelectedItem(event, mapView); if (busStop == null) { // Log.v(TAG, "No busStop pressed"); return false; } else { 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); context.startActivity(busStopIntent); return true; } } @Override public boolean onLongPress(final MotionEvent event, final MapView mapView) { BusStop busStop = getSelectedItem(event, mapView); if (busStop == null) { // Log.v(TAG, "No busStop pressed"); return false; } else { Log.i(TAG, "Pressed " + busStop.id); SharedPreferences favouritesPreferences = context.getSharedPreferences(FAVOURITES_PREFERENCES, 0); if (favouritesPreferences.getBoolean(busStop.id, false)) { favouritesPreferences.edit().remove(busStop.id).commit(); context.makeToast(busStop.id + " removed from favourites", Toast.LENGTH_SHORT); } else { context.makeToast(busStop.id + " made a favourite", Toast.LENGTH_SHORT); favouritesPreferences.edit().putBoolean(busStop.id, true).commit(); } Collections.sort(busStops, new POIFavouriteComparator(context.getSharedPreferences(FAVOURITES_PREFERENCES, 0))); mapView.invalidate(); return true; } } private BusStop getSelectedItem(final MotionEvent event, final MapView mapView) { Log.i(TAG, "Getting selected item"); final Projection pj = mapView.getProjection(); final int eventX = (int) event.getX(); final int eventY = (int) event.getY(); /* These objects are created to avoid construct new ones every cycle. */ pj.fromMapPixels(eventX, eventY, mTouchScreenPoint); for (int i = busStops.size() - 1; i >= 0; i--) { BusStop busStop = busStops.get(i); pj.toPixels(busStop.point, mItemPoint); if (marker.getBounds().contains(mTouchScreenPoint.x - mItemPoint.x, mTouchScreenPoint.y - mItemPoint.y)) { if (busStop.uniLink) { boolean drawing = false; for (int route = 0; route < 5; route++) { if ((busStop.routes & (1 << route)) != 0) { if (routes[route]) { drawing = true; break; } } } if (!drawing) continue; } return busStop; } } return null; } public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { Log.i(TAG, "Got a favourites change in the BuildingNumOverlay for key " + key); Collections.sort(busStops, new POIFavouriteComparator(context.getSharedPreferences(FAVOURITES_PREFERENCES, 0))); } }