package com.echo5bravo.govre.UI; import java.util.ArrayList; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.graphics.Color; import android.graphics.drawable.AnimationDrawable; import android.location.Location; import android.os.Bundle; import android.os.Handler; import android.os.SystemClock; import android.preference.PreferenceManager; import android.support.v4.app.FragmentActivity; import android.text.SpannableString; import android.text.style.ForegroundColorSpan; import android.util.Log; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.animation.BounceInterpolator; import android.view.animation.Interpolator; import android.widget.ImageView; import android.widget.TextView; import com.echo5bravo.govre.R; import com.echo5bravo.govre.BLL.BusinessRoute; import com.echo5bravo.govre.BLL.BusinessSchedule; import com.echo5bravo.govre.BLL.BusinessStation; import com.echo5bravo.govre.BLL.BusinessUpdate; import com.echo5bravo.govre.BLL.BusinessVehicle; import com.echo5bravo.govre.DAL.BusinessBaseCalDates; import com.echo5bravo.govre.INFO.CalDates; import com.echo5bravo.govre.INFO.Device; import com.echo5bravo.govre.INFO.Route; import com.echo5bravo.govre.INFO.Station; import com.echo5bravo.govre.INFO.Update; import com.echo5bravo.govre.INFO.Vehicle; import com.echo5bravo.govre.INFO.VehicleBubble; import com.echo5bravo.govre.UTILS.Common; import com.google.android.apps.analytics.GoogleAnalyticsTracker; import com.google.android.gms.common.ConnectionResult; import com.google.android.gms.common.GooglePlayServicesClient.ConnectionCallbacks; import com.google.android.gms.common.GooglePlayServicesClient.OnConnectionFailedListener; import com.google.android.gms.location.LocationClient; import com.google.android.gms.location.LocationListener; import com.google.android.gms.location.LocationRequest; import com.google.android.gms.maps.CameraUpdateFactory; import com.google.android.gms.maps.GoogleMap; import com.google.android.gms.maps.SupportMapFragment; import com.google.android.gms.maps.GoogleMap.InfoWindowAdapter; import com.google.android.gms.maps.GoogleMap.OnMarkerClickListener; import com.google.android.gms.maps.model.BitmapDescriptorFactory; import com.google.android.gms.maps.model.LatLng; import com.google.android.gms.maps.model.Marker; import com.google.android.gms.maps.model.MarkerOptions; import com.google.android.gms.maps.model.PolylineOptions; import static com.google.android.gms.maps.GoogleMap.MAP_TYPE_HYBRID; import static com.google.android.gms.maps.GoogleMap.MAP_TYPE_NORMAL; import static com.google.android.gms.maps.GoogleMap.MAP_TYPE_SATELLITE; import static com.google.android.gms.maps.GoogleMap.MAP_TYPE_TERRAIN; public class ActivityGoogleMapV2 extends FragmentActivity implements OnMarkerClickListener,ConnectionCallbacks, OnConnectionFailedListener, LocationListener { /** * Note that this may be null if the Google Play services APK is not available. */ private static final String TAG = ActivityGoogleMapV2.class.getSimpleName(); private GoogleAnalyticsTracker googleTracker; private static final String PREFS_NAME = "OldPreferences"; private static final String PREFS_TIME_FORMAT_KEY = "OldTimeFormatKEY"; private static final String PREFS_STATION_MARKER_KEY = "OldStationMarkerKEY"; private static final String PREFS_SATELLITE_KEY = "OldSatelliteKEY"; private static final String PREFS_TRAFFIC_KEY = "OldTrafficKEY"; private String mOldTimeFormatValue; private String mOldStationMarkerValue; private boolean mOldSatelliteValue; private boolean mOldTrafficValue; private GoogleMap mMap; private LocationClient mLocationClient; private Context context; private ImageView imgTwitter, imgAlerts, imgSched; private ImageView spinner; private TextView txtRefresh; private TextView txtArrivals; private AnimationDrawable spinnerAnim; private boolean spinnerOn; private ImageView imgNoSignal; private boolean noSignalOn; private boolean blnGTFSDataLoaded; private boolean blnLocalDataLoaded; private Marker mStation; private Marker mVehicle; private String stationMarker; private String vehicleMarker; String TodaysScheduleType; private ExecutorService TaskExecutorMap; private ScheduledExecutorService scheduleTaskExecutorVehicles; private ScheduledExecutorService scheduleTaskExecutorUiUpdates; ArrayList<Route> myFBGRoutes; ArrayList<Route> myMSSRoutes; ArrayList<Station> myStations; ArrayList<Vehicle> myVehicles; ArrayList<Update> myUpdates; ArrayList<CalDates> myCalDates; ArrayList<Marker> mapStations; //Stores Station Markers objects after they are committed to the Map ArrayList<Marker> mapVehicles; //Stores Vehicle Markers objects after they are committed to the Map LatLng srcLatLng; LatLng destLatLng; int LoopCounter = 0; String lblMsg = ""; // These settings are the same as the settings for the map. They will in fact give you updates // at the maximal rates currently possible. private static final LocationRequest REQUEST = LocationRequest.create() .setInterval(5000) // 5 seconds .setFastestInterval(16) // 16ms = 60fps .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); /* LIFECYCLE EVENTS ----------------------- onCreate() -------------------------------------------------*/ @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setTheme(R.style.Theme_BlueMoon); setContentView(R.layout.googlemap_v2_layout); //Start Google Analytics Tracker //------------------------------------------------------------------------------------------------- googleTracker = GoogleAnalyticsTracker.getInstance(); googleTracker.setDebug(Boolean.parseBoolean(this.getString(R.bool.ga_debug))); googleTracker.setDryRun(Boolean.parseBoolean(this.getString(R.bool.ga_dryrun))); googleTracker.startNewSession(this.getString(R.string.ga_api_key), 60, this); int CV_SLOT_1 = 1; //Slot 1 Tracks Device Orientation //int CV_SLOT_2 = 2; //Slot 2 Unassigned //int CV_SLOT_3 = 3; //Slot 3 Unassigned //int CV_SLOT_4 = 4; //Slot 4 Unassigned //int CV_SLOT_5 = 5; //Slot 5 Unassigned //Track Device's Current Orientation googleTracker.setCustomVar(CV_SLOT_1, //SLOT (Can only track up to 5) "Device Orientation", //NAME Device.getDeviceOrientation(this.getApplicationContext()), //VALUE 1); //SCOPE /*------------------------------------------------------------------------------------------------- NOTE: Add to Activity Handlers: onResume(): googleTracker.trackPageView("/" + TAG); onDestroy(): googleTracker.stopSession(); -------------------------------------------------------------------------------------------------*/ context = this; spinner = (ImageView) findViewById(R.id.splashSpinner); txtRefresh = (TextView) findViewById(R.id.txtrefresh); txtArrivals = (TextView) findViewById(R.id.txtarrivals); spinnerAnim = (AnimationDrawable) spinner.getBackground(); imgNoSignal = (ImageView) findViewById(R.id.imgNoSignal); addListenerOnTwitterImage(); addListenerOnAlert(); addListenerOnSched(); setUpMapIfNeeded(); } /* LIFECYCLE EVENTS ----------------------- onResume() -------------------------------------------------*/ @Override protected void onResume() { super.onResume(); //Track current Activity googleTracker.trackPageView("/" + TAG); /* Variables to check if user preferences have changed */ SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0); mOldTimeFormatValue = settings.getString(PREFS_TIME_FORMAT_KEY, ""); mOldStationMarkerValue = settings.getString(PREFS_STATION_MARKER_KEY, ""); mOldSatelliteValue = settings.getBoolean(PREFS_SATELLITE_KEY, false); mOldTrafficValue = settings.getBoolean(PREFS_TRAFFIC_KEY, false); setUpMapIfNeeded(); setUpLocationClientIfNeeded(); //Location Management mLocationClient.connect(); } /* LIFECYCLE EVENTS ----------------------- onPause() -------------------------------------------------*/ @Override protected void onPause(){ super.onPause(); //Stop Progress Spinner spinnerAnim.stop(); spinner.setVisibility(View.INVISIBLE); //Disable location manager if (mLocationClient != null) { mLocationClient.disconnect(); } } /* LIFECYCLE EVENTS ----------------------- onStop() -------------------------------------------------*/ @Override protected void onStop(){ super.onStop(); SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0); SharedPreferences.Editor editor = settings.edit(); editor.putString(PREFS_TIME_FORMAT_KEY, mOldTimeFormatValue); editor.putString(PREFS_STATION_MARKER_KEY, mOldStationMarkerValue); editor.putBoolean(PREFS_SATELLITE_KEY, mOldSatelliteValue); editor.putBoolean(PREFS_TRAFFIC_KEY, mOldTrafficValue); // Commit the edits! editor.commit(); //Close down Threads; TaskExecutorMap.shutdown(); scheduleTaskExecutorVehicles.shutdown(); scheduleTaskExecutorUiUpdates.shutdown(); } /* LIFECYCLE EVENTS ----------------------- onStart() -------------------------------------------------*/ @Override protected void onStart(){ super.onStart(); TaskExecutorMap = Executors.newSingleThreadExecutor(); TaskExecutorMap.execute(new Runnable() { public void run() { Log.w(TAG, "LOCAL ARRAYS LOADING...."); //Load Singleton ArrayLists LoadCalDates(); TodaysScheduleType = Common.TodaysScheduleType(context, myCalDates, true); LoadFBGRoute(); LoadMSSRoute(); LoadStationStop(); Log.w(TAG, "LOCAL ARRAYS LOADED."); // Update the UI Thread runOnUiThread(new Runnable() { public void run() { //Ensure local values are loaded before committing to blnLocalDataLoaded=true if (myFBGRoutes != null && myMSSRoutes != null && myStations != null){ Log.w(TAG, "DRAWING RAIL LINES AND STATIONS."); //Pull user's preferred Map Settings SharedPreferences getPrefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext()); String prefLine = getPrefs.getString("listTrainLine", "FBG,ALL"); stationMarker = getPrefs.getString("listStationMarker", "abbv"); //Draw user lines by preference. This will insure the preferred line //overlays correctly for when the lines Merger in Alexandria if (prefLine.equals("MSS,ALL")){ DrawFBGRoute(srcLatLng, destLatLng); DrawMSSRoute(srcLatLng, destLatLng); } else{ DrawMSSRoute(srcLatLng, destLatLng); DrawFBGRoute(srcLatLng, destLatLng); } if (mOldStationMarkerValue.equals(stationMarker) || mOldStationMarkerValue.length() == 0){ mOldStationMarkerValue = stationMarker; DrawStationStopOverlay(); } Log.w(TAG, "DRAWING RAIL LINES AND STATIONS... COMPLETE"); blnLocalDataLoaded = true; Log.w(TAG, "CHECKING MAPVIEW SETTINGS FOR CHANGES."); //Pull user's preferred Map Settings boolean trafficOn = getPrefs.getBoolean("chkTraffic", false); String sMapType = getPrefs.getString("listMapType", "MAP_TYPE_NORMAL"); if (sMapType.equals("MAP_TYPE_NORMAL")) { mMap.setMapType(MAP_TYPE_NORMAL); } else if (sMapType.equals("MAP_TYPE_HYBRID")) { mMap.setMapType(MAP_TYPE_HYBRID); } else if (sMapType.equals("MAP_TYPE_SATELLITE")) { mMap.setMapType(MAP_TYPE_SATELLITE); } else if (sMapType.equals("MAP_TYPE_TERRAIN")) { mMap.setMapType(MAP_TYPE_TERRAIN); } mMap.setTrafficEnabled(trafficOn); Log.w(TAG, "CHECK COMPLETE"); } else{ blnLocalDataLoaded = false; } } }); } }); scheduleTaskExecutorVehicles = Executors.newSingleThreadScheduledExecutor(); // This schedule a task to run every X Seconds: scheduleTaskExecutorVehicles.scheduleAtFixedRate(new Runnable() { public void run() { try{ if (Device.isDeviceOnline(context.getApplicationContext())) noSignalOn = false; else noSignalOn = true; spinnerOn = true; //Get GTFS data on separate thread (Requires Network) if (noSignalOn==false && blnGTFSDataLoaded == false && blnLocalDataLoaded == true){ Log.w(TAG, "CALLING VRE GTFS INTERFACE..."); doRefreshGTFSFeeds(); Log.w(TAG, "CALL COMPELTE."); Log.w(TAG, "GTFS ARRAYS LOADING...."); LoadVehicleStop(); LoadUpdates(); Log.w(TAG, "GTFS ARRAYS LOADED."); //Ensure local values are loaded before committing to blnLocalDataLoaded=true if (myVehicles != null && myUpdates != null) blnGTFSDataLoaded = true; else blnGTFSDataLoaded = false; } spinnerOn = false; } catch(Exception ex) { spinnerOn = false; Log.w(TAG, "run(): " + ex.toString()); } if (LoopCounter == 0){ LoopCounter = 59; blnGTFSDataLoaded = false; } else { LoopCounter--; } // Update the UI Thread runOnUiThread(new Runnable() { public void run() { try{ /*********************************************************************************** * Since there are 1,000s of GeoPoints for the Rail Lines and the Stations * are static locations, to redraw these every time a vehicle update is posted * causes the map to crash. * * The logic below keeps the FBG, MSS Lines and the Stations on the map * and only re-draws the Vehicles. * * -Check the mapView for our itemizedOverlay, both Station and Train use them * but the overlayVehicles ArrayList collection will contain the old objects we * want to clear before adding the new Vehicle locations to the map. **********************************************************************************/ if (!spinnerOn){ //Check if Station marker icon preference has changed, if so, redraw with new Icon if (!(mOldStationMarkerValue.equals(stationMarker))){ if (mapStations == null || myStations.size() == 0){ DrawStationStopOverlay(); mOldStationMarkerValue = stationMarker; } //Always Destroy and re-draw vehicles if (mapStations != null){ for(Marker m : mapStations) { for(Station each : myStations){ String rawTitle = m.getTitle(); //Contains both the Station Name and ID String delims = "[|]"; String[] title = rawTitle.split(delims); if(title[1].equals(each.STATION_ID())){ Log.w(TAG, "-----------------------------------------------------------------------------------------------------"); Log.w(TAG, "UPDATE STATION: " + title[1] + " ID: " + each.STATION_ID()); Log.w(TAG, "LAT: " + each.STATION_LATITUDE() + " LONG: " + each.STATION_LONGITUDE()); Log.w(TAG, "-----------------------------------------------------------------------------------------------------"); UpdateStationStopMarker(m, each); } } } } } if (mapVehicles == null || mapVehicles.size() == 0){ DrawVehicleOverlay(); } //Always Destroy and re-draw vehicles if (mapVehicles != null){ for(Marker v : mapVehicles) { for(Vehicle each : myVehicles){ if(v.getTitle().equals(each.VEHICLE_ID())){ Log.w(TAG, "-----------------------------------------------------------------------------------------------------"); Log.w(TAG, "MOVED VEHICLE: " + v.getTitle() + " ID: " + each.VEHICLE_ID()); Log.w(TAG, "LAT: " + each.VEHICLE_LATITUDE() + " LONG: " + each.VEHCILE_LONGITUDE()); Log.w(TAG, "-----------------------------------------------------------------------------------------------------"); //LatLng GP = new LatLng(Double.parseDouble(each.VEHICLE_LATITUDE()), Double.parseDouble(each.VEHCILE_LONGITUDE())); //v.setPosition(GP); UpdateVehicleMarker(v, each); //v.remove(); } } } } } spinnerOn = false; } catch(Exception e) { Log.w(TAG, "runOnUiThread: " + e.toString()); } if (LoopCounter == 0) txtRefresh.setText("Loading..."); else txtRefresh.setText(" Refreshing: " + Integer.toString(LoopCounter) + " "); txtArrivals.setText(lblMsg); } }); } }, 0, 1, TimeUnit.SECONDS); scheduleTaskExecutorUiUpdates = Executors.newScheduledThreadPool(4); // This schedule a task to run every x minutes: scheduleTaskExecutorUiUpdates.scheduleAtFixedRate(new Runnable() { public void run() { // Update the UI Thread runOnUiThread(new Runnable() { public void run() { if (spinnerOn){ spinnerAnim.start(); spinner.setVisibility(View.VISIBLE); } else { spinnerAnim.stop(); spinner.setVisibility(View.INVISIBLE); } if (noSignalOn){ imgNoSignal.setVisibility(View.VISIBLE); } else { imgNoSignal.setVisibility(View.INVISIBLE); } } }); } }, 0, 1, TimeUnit.SECONDS); //}, 0, 500, TimeUnit.MILLISECONDS); } private void setUpLocationClientIfNeeded() { if (mLocationClient == null) { mLocationClient = new LocationClient( getApplicationContext(), this, // ConnectionCallbacks this); // OnConnectionFailedListener } } /** * Sets up the map if it is possible to do so (i.e., the Google Play services APK is correctly * installed) and the map has not already been instantiated.. This will ensure that we only ever * call {@link #setUpMap()} once when {@link #mMap} is not null. * <p> * If it isn't installed {@link SupportMapFragment} (and * {@link com.google.android.gms.maps.MapView MapView}) will show a prompt for the user to * install/update the Google Play services APK on their device. * <p> * A user can return to this FragmentActivity after following the prompt and correctly * installing/updating/enabling the Google Play services. Since the FragmentActivity may not have been * completely destroyed during this process (it is likely that it would only be stopped or * paused), {@link #onCreate(Bundle)} may not be called again so we should call this method in * {@link #onResume()} to guarantee that it will be called. */ private void setUpMapIfNeeded() { // Do a null check to confirm that we have not already instantiated the map. if (mMap == null) { // Try to obtain the map from the SupportMapFragment. mMap = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map)) .getMap(); // Check if we were successful in obtaining the map. if (mMap != null) { setUpMap(); } } } /** * This is where we can add markers or lines, add listeners or move the camera. In this case, we * just add a marker near Africa. * <p> * This should only be called once and when we are sure that {@link #mMap} is not null. */ private void setUpMap() { //Pull user's preferred Map Settings SharedPreferences getPrefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext()); String prefLine = getPrefs.getString("listTrainLine", "FBG,ALL"); stationMarker = getPrefs.getString("listStationMarker", "abbv"); //Pull user's preferred Map Settings boolean satelliteOn = getPrefs.getBoolean("chkSatellite", false); boolean trafficOn = getPrefs.getBoolean("chkTraffic", false); if (!satelliteOn){ mMap.setMapType(MAP_TYPE_TERRAIN); } else { mMap.setMapType(MAP_TYPE_HYBRID); } mMap.setTrafficEnabled(trafficOn); // Setting an info window adapter allows us to change the both the contents and look of the // info window. mMap.setInfoWindowAdapter(new CustomInfoWindowAdapter()); //Move to Thread /////////////////// USED TO SET STARTING POINT ////////////////// double src_lat = 0.0; double src_long = 0.0; //Orient the Map Center Point based on the user's device orientation if (Device.getDeviceOrientation(this.getApplicationContext()).equals("portrait")){ //Location: Rippon src_lat = 38.613158999999996; src_long = -77.254272; } else { //Location: Lorton src_lat = 38.71252799999999; src_long = -77.217865; } //Location: Union Station double dest_lat = 38.897346; double dest_long = -77.007337; //Set GeoPoints as defaults until the TrainLines are drawn srcLatLng = new LatLng(src_lat, src_long); destLatLng = new LatLng(dest_lat, dest_long); /////////////////// END USED TO SET STARTING POINT ////////////////// // Set listeners for marker events. See the bottom of this class for their behavior. mMap.setOnMarkerClickListener(this); // Move the map so that it is centered on the polyline. mMap.moveCamera(CameraUpdateFactory.newLatLng(srcLatLng)); mMap.moveCamera(CameraUpdateFactory.zoomTo(9)); mMap.setMyLocationEnabled(true); } /* LOAD EVENTS -------------------------------------------------------------------------*/ private void doRefreshGTFSFeeds() { /* Verify the Device is Connected before invoking a method requiring INTERNET*/ //if (Device.isDeviceOnline(context.getApplicationContext())){ //Pull Vehicles from VRE GTFS and Load them to SQL BusinessVehicle.LoadVehiclesFromGTFS(this); //Pull Trip Updates from VRE GTFS and Load them to SQL BusinessUpdate.LoadUpdatesFromGTFS(this); //} } private void LoadFBGRoute(){ //Get Route Based on route_id myFBGRoutes = BusinessRoute.getAllRoutes(context, 2); //FBG (RED) } private void LoadMSSRoute(){ //Get Route Based on route_id myMSSRoutes = BusinessRoute.getAllRoutes(context, 4); //MSS (BLUE) } private void LoadStationStop(){ //Get Stations myStations = BusinessStation.getAllStations(context); } private void LoadVehicleStop(){ //Get Vehicles myVehicles = BusinessVehicle.getAllVehicles(context); } private void LoadCalDates(){ //Current CalDates Collection myCalDates = BusinessBaseCalDates.getAllCalDates(this); } private void LoadUpdates(){ //Current Station Collection myUpdates = BusinessUpdate.getAllUpdates(context); } /* MAP LOAD EVENTS -------------------------------------------------------------------------*/ private void DrawFBGRoute(LatLng src, LatLng dest){ DrawRoute(src, dest, myFBGRoutes, Color.RED); } private void DrawMSSRoute(LatLng src, LatLng dest){ DrawRoute(src, dest, myMSSRoutes, Color.BLUE); } private void DrawRoute(LatLng src, LatLng dest, ArrayList<Route> route, int DefaultColor){ Integer counter = 0; LatLng startGP = null; LatLng gp1 = null; LatLng gp2 = null; ArrayList<LatLng> routePoints = new ArrayList<LatLng>(); for (Route each : route) { if (counter == 0){ startGP = new LatLng(Double.parseDouble(each.ROUTE_LATITUDE()), Double.parseDouble(each.ROUTE_LONGITUDE())); routePoints.add(startGP); gp2 = startGP; counter++; } else { gp1 = gp2; gp2 = new LatLng(Double.parseDouble(each.ROUTE_LATITUDE()), Double.parseDouble(each.ROUTE_LONGITUDE())); routePoints.add(gp2); } } routePoints.add(dest); mMap.addPolyline((new PolylineOptions()) .addAll(routePoints) .width(5) .color(DefaultColor) .geodesic(true)); } private void DrawStationStopOverlay(){ LatLng stationLatLng = null; String stationIconString, stationTitle, stationSnippet; int stationIcon; mapStations = new ArrayList<Marker>(); try{ for (Station each : myStations) { //Set local variables for each object in collection //Station Location (Lat Long) stationLatLng = new LatLng(Double.parseDouble(each.STATION_LATITUDE()), Double.parseDouble(each.STATION_LONGITUDE())); //Station Marker Icon if (stationMarker.equals("abbv")) stationIconString = "drawable/station_" + each.STATION_ID().toLowerCase(); else stationIconString = "drawable/stop_marker"; stationIcon = (int)(getResources().getIdentifier(stationIconString, null, getPackageName())); //Station Marker Title (HACK ALERT!!!: Since maps.model Marker does not have an ID property, //concatenate Station Name and ID and parse out ID later.) stationTitle = each.STATION_STOP_NAME() + "|" + each.STATION_ID(); //Station Snippet stationSnippet = each.ZONE() + "\n"; stationSnippet += each.ADDRESS() + "\n"; stationSnippet += each.CITY() + ", " + each.STATE() + " " + each.ZIP() + "\n"; // Uses a custom icon with the info window popping out of the center of the icon. mStation = mMap.addMarker(new MarkerOptions() .position(stationLatLng) .title(stationTitle) .snippet(stationSnippet) .icon(BitmapDescriptorFactory.fromResource(stationIcon)) .infoWindowAnchor(0.5f, 0.5f)); //Build Stations list collection once they are commited to the Map mapStations.add(mStation); } } catch(Exception e) { Log.w(TAG, "DrawStationStopOverlay ERROR: " + e.toString()); } } private void UpdateStationStopMarker(Marker marker, Station myStation){ LatLng stationLatLng = null; String stationIconString, stationTitle, stationSnippet; int stationIcon; try{ //Set local variables for each object in collection //Station Location (Lat Long) stationLatLng = new LatLng(Double.parseDouble(myStation.STATION_LATITUDE()), Double.parseDouble(myStation.STATION_LONGITUDE())); //Station Marker Icon if (stationMarker.equals("abbv")) stationIconString = "drawable/station_" + myStation.STATION_ID().toLowerCase(); else stationIconString = "drawable/stop_marker"; stationIcon = (int)(getResources().getIdentifier(stationIconString, null, getPackageName())); //Station Marker Title (HACK ALERT!!!: Since maps.model Marker does not have an ID property, //concatenate Station Name and ID and parse out ID later.) stationTitle = myStation.STATION_STOP_NAME() + "|" + myStation.STATION_ID(); //Station Snippet stationSnippet = myStation.ZONE() + "\n"; stationSnippet += myStation.ADDRESS() + "\n"; stationSnippet += myStation.CITY() + ", " + myStation.STATE() + " " + myStation.ZIP() + "\n"; // Uses a custom icon with the info window popping out of the center of the icon. //mStation = mMap.addMarker(new MarkerOptions() // .position(stationLatLng) // .title(stationTitle) // .snippet(stationSnippet) // .icon(B;tmapDescriptorFactory.fromResource(stationIcon)) // .infoWindowAnchor(0.5f, 0.5f)); marker.setIcon(BitmapDescriptorFactory.fromResource(stationIcon)); } catch(Exception e) { Log.w(TAG, "DrawStationStopOverlay ERROR: " + e.toString()); } } /* * DrawVehicleOverlay * * Requires Special Logic: Since it is too expensive to re-draw the mapView everytime a Vehicle * change occurs, load the vehicles into a collection and clear their old location and draw the * new location on the background thread. */ @SuppressWarnings("unused") private void DrawVehicleOverlay(){ mapVehicles = new ArrayList<Marker>(); boolean VehicleAtStation = false; LatLng vehicleLatLng = null; String vehicleIconString, vehicleTitle, vehicleIconName, vehicleSnippet; int vehicleIcon; String StationLat = ""; String StationLong = ""; String iconColor = ""; //Default is Green lblMsg = ""; //Clear VehicleBubble myVehicleBubble = null; //IDEA! Convert to Collection refresh collection only when Spinner recycles if (!(myVehicles == null)){ try{ for (Vehicle eachVehicle : myVehicles) { //Station Location (Lat Long) vehicleLatLng = new LatLng(Double.parseDouble(eachVehicle.VEHICLE_LATITUDE()), Double.parseDouble(eachVehicle.VEHCILE_LONGITUDE())); ////vehicleLat = Double.parseDouble(eachVehicle.VEHICLE_LATITUDE()); ////vehicleLong = Double.parseDouble(eachVehicle.VEHCILE_LONGITUDE()); // Pull user's preferred default train line // SharedPreferences getPrefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext()); String timeformat = getPrefs.getString("listTimeFormat", "12"); if (myStations != null && myUpdates != null && TodaysScheduleType != null) myVehicleBubble = BusinessSchedule.fetchVehicleBubble(this, eachVehicle, myUpdates, myStations, TodaysScheduleType, timeformat); if (myVehicleBubble != null){ if (myVehicleBubble.AT_STATION()) { if (lblMsg.length() == 0) lblMsg = (" " + myVehicleBubble.VEHICLE_ID() + "@" + myVehicleBubble.CURRENT_STOP() + " "); else lblMsg = (lblMsg + "\n " + myVehicleBubble.VEHICLE_ID() + "@" + myVehicleBubble.CURRENT_STOP() + " "); } //Train Station Icon vehicleIconString = "drawable/train"; vehicleIcon = (int)(getResources().getIdentifier(vehicleIconString, null, getPackageName())); //Vehicle Title vehicleTitle = myVehicleBubble.VEHICLE_ID(); //vehicleInfo = myVehicleBubble.VEHICLE_LABLE() + " \n"; vehicleSnippet = myVehicleBubble.STATUS() + " \n"; vehicleSnippet += myVehicleBubble.NEXT_STOP_AND_TIME() + " \n"; vehicleSnippet += "To: " + myVehicleBubble.HEADING() + " \n"; vehicleSnippet += myVehicleBubble.STOPS_REMAINING(); //Determine which color icon to display iconColor = "green"; //Default: green if (myVehicleBubble.DELAYED()) //Delayed turns orange iconColor = "orange"; if (myVehicleBubble.LOST_COMM()) //Lost Comms overrides Default and Delay turns gray iconColor = "gray"; int imageResource; //Train Station Map Icon if (myVehicleBubble.AT_STATION()){ if (LoopCounter%2==0) vehicleIconName = "drawable/map_train_" + iconColor + "_" + eachVehicle.VEHICLE_ID().toLowerCase(); else vehicleIconName = "drawable/map_train_" + iconColor + "_arrive"; } else { vehicleIconName = "drawable/map_train_" + iconColor + "_" + eachVehicle.VEHICLE_ID().toLowerCase(); } try{ imageResource = getResources().getIdentifier(vehicleIconName, null, getPackageName()); } catch(Exception e) { //In case a new Train is added and there is no graphic for it, Use this catch-all vehicleIconName = "drawable/map_train_green"; imageResource = getResources().getIdentifier(vehicleIconName, null, getPackageName()); } // Uses a custom icon with the info window popping out of the center of the icon. mVehicle = mMap.addMarker(new MarkerOptions() .position(vehicleLatLng) .title(vehicleTitle) .snippet(vehicleSnippet) .icon(BitmapDescriptorFactory.fromResource(imageResource)) .infoWindowAnchor(0.5f, 0.5f)); //Build Stations list collection once they are committed to the Map mapVehicles.add(mVehicle); } } } catch(Exception e) { Log.w(TAG, "DrawVehicleOverlay: " + e.toString()); } } } /* * DrawVehicleOverlay * * Requires Special Logic: Since it is too expensive to re-draw the mapView everytime a Vehicle * change occurs, load the vehicles into a collection and clear their old location and draw the * new location on the background thread. */ @SuppressWarnings("unused") private void UpdateVehicleMarker(Marker vMarker, Vehicle myVehicle){ boolean VehicleAtStation = false; LatLng vehicleLatLng = null; String vehicleIconString, vehicleTitle, vehicleIconName, vehicleSnippet; int vehicleIcon; String StationLat = ""; String StationLong = ""; String iconColor = ""; //Default is Green lblMsg = ""; //Clear VehicleBubble myVehicleBubble = null; //IDEA! Convert to Collection refresh collection only when Spinner recycles if (!(vMarker == null)){ try{ //for (Vehicle eachVehicle : myVehicles) { //Station Location (Lat Long) vehicleLatLng = new LatLng(Double.parseDouble(myVehicle.VEHICLE_LATITUDE()), Double.parseDouble(myVehicle.VEHCILE_LONGITUDE())); ////vehicleLat = Double.parseDouble(eachVehicle.VEHICLE_LATITUDE()); ////vehicleLong = Double.parseDouble(eachVehicle.VEHCILE_LONGITUDE()); // Pull user's preferred default train line // SharedPreferences getPrefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext()); String timeformat = getPrefs.getString("listTimeFormat", "12"); if (myStations != null && myUpdates != null && TodaysScheduleType != null) myVehicleBubble = BusinessSchedule.fetchVehicleBubble(this, myVehicle, myUpdates, myStations, TodaysScheduleType, timeformat); if (myVehicleBubble != null){ if (myVehicleBubble.AT_STATION()) { if (lblMsg.length() == 0) lblMsg = (" " + myVehicleBubble.VEHICLE_ID() + "@" + myVehicleBubble.CURRENT_STOP() + " "); else lblMsg = (lblMsg + "\n " + myVehicleBubble.VEHICLE_ID() + "@" + myVehicleBubble.CURRENT_STOP() + " "); } //Train Station Icon vehicleIconString = "drawable/train"; vehicleIcon = (int)(getResources().getIdentifier(vehicleIconString, null, getPackageName())); //Vehicle Title vehicleTitle = myVehicleBubble.VEHICLE_ID(); //vehicleInfo = myVehicleBubble.VEHICLE_LABLE() + " \n"; vehicleSnippet = myVehicleBubble.STATUS() + " \n"; vehicleSnippet += myVehicleBubble.NEXT_STOP_AND_TIME() + " \n"; vehicleSnippet += "To: " + myVehicleBubble.HEADING() + " \n"; vehicleSnippet += myVehicleBubble.STOPS_REMAINING(); //Determine which color icon to display iconColor = "green"; //Default: green if (myVehicleBubble.DELAYED()) //Delayed turns orange iconColor = "orange"; if (myVehicleBubble.LOST_COMM()) //Lost Comms overrides Default and Delay turns gray iconColor = "gray"; int imageResource; //Train Station Map Icon if (myVehicleBubble.AT_STATION()){ if (LoopCounter%2==0) vehicleIconName = "drawable/map_train_" + iconColor + "_" + myVehicle.VEHICLE_ID().toLowerCase(); else vehicleIconName = "drawable/map_train_" + iconColor + "_arrive"; } else { vehicleIconName = "drawable/map_train_" + iconColor + "_" + myVehicle.VEHICLE_ID().toLowerCase(); } try{ imageResource = getResources().getIdentifier(vehicleIconName, null, getPackageName()); } catch(Exception e) { //In case a new Train is added and there is no graphic for it, Use this catch-all vehicleIconName = "drawable/map_train_green"; imageResource = getResources().getIdentifier(vehicleIconName, null, getPackageName()); } vMarker.setPosition(vehicleLatLng); vMarker.setSnippet(vehicleSnippet); //TODO://Commented showInfoWindow method, causing issues because last marker to render always displayed InfoWindow //if (VehicleAtStation){ vMarker.setIcon(BitmapDescriptorFactory.fromResource(imageResource)); //vMarker.showInfoWindow(); // } } //} } catch(Exception e) { Log.w(TAG, "DrawVehicleOverlay: " + e.toString()); } } } /** Demonstrates customizing the info window and/or its contents. */ class CustomInfoWindowAdapter implements InfoWindowAdapter { // These a both viewgroups containing an ImageView with id "badge" and two TextViews with id // "title" and "snippet". private final View mWindow; private final View mContents; CustomInfoWindowAdapter() { mWindow = getLayoutInflater().inflate(R.layout.custom_info_window, null); mContents = getLayoutInflater().inflate(R.layout.custom_info_contents, null); } @Override public View getInfoWindow(Marker marker) { render(marker, mWindow); return mWindow; } @Override public View getInfoContents(Marker marker) { // This means that the default info contents will be used. return null; } private void render(Marker marker, View view) { //int badge = 0; String stationIconString = null, sTitle = null; int stationIcon = 0; if (mapStations != null){ for(Marker m : mapStations) { if (marker.equals(m)) { //HACK ALERT!!! ;-) //My HACK to get the Station Name and Station ID together from the Marker.Title property //tokens[0] = Station Name (exp: Union Station) //tokens[1] = Station ID (exp: 00000000000000000000000000000001) String rawTitle = marker.getTitle(); //Contains both the Station Name and ID String delims = "[|]"; String[] tokens = rawTitle.split(delims); //Station Marker Icon stationIconString = "drawable/station_icon_" + tokens[1].toLowerCase(); stationIcon = (int)(getResources().getIdentifier(stationIconString, null, getPackageName())); sTitle = tokens[0]; } } } if (mapVehicles != null){ for(Marker v : mapVehicles) { if (marker.equals(v)) { sTitle = marker.getTitle(); //Contains both the Station Name and ID //Station Marker Icon stationIconString = "drawable/train"; stationIcon = (int)(getResources().getIdentifier(stationIconString, null, getPackageName())); } } } Log.w(TAG, "OOOOOOO TITLE: " + sTitle); Log.w(TAG, "OOOOOOO StationIconString: " + stationIconString); Log.w(TAG, "OOOOOOO StationIcon: " + stationIcon); ((ImageView) view.findViewById(R.id.badge)).setImageResource(stationIcon); String title = sTitle; TextView titleUi = ((TextView) view.findViewById(R.id.title)); if (title != null) { // Spannable string allows us to edit the formatting of the text. SpannableString titleText = new SpannableString(title); titleText.setSpan(new ForegroundColorSpan(Color.BLACK), 0, titleText.length(), 0); titleUi.setText(titleText); } else { titleUi.setText(""); } String snippet = marker.getSnippet(); TextView snippetUi = ((TextView) view.findViewById(R.id.snippet)); if (snippet != null) { SpannableString snippetText = new SpannableString(snippet); //snippetText.setSpan(new ForegroundColorSpan(Color.MAGENTA), 0, 10, 0); //snippetText.setSpan(new ForegroundColorSpan(Color.BLUE), 12, snippet.length(), 0); snippetText.setSpan(new ForegroundColorSpan(Color.DKGRAY), 0, snippet.length(), 0); snippetUi.setText(snippetText); } else { snippetUi.setText(""); } } } @Override public boolean onMarkerClick(final Marker marker) { //if (marker.equals(mStation)) { // This causes the marker at Stations to bounce into position when it is clicked. final Handler handler = new Handler(); final long start = SystemClock.uptimeMillis(); final long duration = 1500; final Interpolator interpolator = new BounceInterpolator(); handler.post(new Runnable() { @Override public void run() { long elapsed = SystemClock.uptimeMillis() - start; float t = Math.max(1 - interpolator .getInterpolation((float) elapsed / duration), 0); marker.setAnchor(0.5f, 1.0f + 2 * t); if (t > 0.0) { // Post again 16ms later. handler.postDelayed(this, 16); } } }); //} // We return false to indicate that we have not consumed the event and that we wish // for the default behavior to occur (which is for the camera to move such that the // marker is centered and for the marker's info window to open, if it has one). return false; } /* MENU AND NAVIGATION ------------------------------------------------------------------------*/ @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.mapmenu, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { if (item.getItemId() == R.id.about) { //Track GoogleAnalytics Event googleTracker.trackEvent("ui_interaction", //category "from_menu", //action "about", //label 0); //value Intent a = new Intent(ActivityGoogleMapV2.this, ActivityAbout.class); a.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP); startActivity(a); } else if (item.getItemId() == R.id.options) { //Track GoogleAnalytics Event googleTracker.trackEvent("ui_interaction", //category "from_menu", //action "options", //label 0); //value Intent p = new Intent(ActivityGoogleMapV2.this, ActivityPreferences.class); p.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP); startActivity(p); } else if (item.getItemId() == R.id.oldmap) { //Track GoogleAnalytics Event googleTracker.trackEvent("ui_interaction", //category "from_menu", //action "oldmap", //label 0); //value Intent o = new Intent(ActivityGoogleMapV2.this, ActivityOldMap.class); o.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP); startActivity(o); } else if (item.getItemId() == R.id.alerts) { //Track GoogleAnalytics Event googleTracker.trackEvent("ui_interaction", //category "from_menu", //action "alerts", //label 0); //value Intent x = new Intent(ActivityGoogleMapV2.this, ActivityAlerts.class); x.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP); startActivity(x); } else if (item.getItemId() == R.id.schedules) { //Track GoogleAnalytics Event googleTracker.trackEvent("ui_interaction", //category "from_menu", //action "schedules", //label 0); //value Intent e = new Intent(ActivityGoogleMapV2.this, ActivityStationSchedule.class); e.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP); startActivity(e); } return true; } private void addListenerOnAlert() { imgAlerts = (ImageView) findViewById(R.id.imgAlerts); imgAlerts.setOnClickListener(new View.OnClickListener() { public void onClick(View arg0) { //Track GoogleAnalytics Event googleTracker.trackEvent("ui_interaction", //category "from_icon", //action "alerts", //label 0); //value //Do Something Intent myIntent = new Intent(ActivityGoogleMapV2.this, ActivityAlerts.class); myIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP); startActivity(myIntent); } }); } private void addListenerOnSched() { imgSched = (ImageView) findViewById(R.id.imgSched); imgSched.setOnClickListener(new View.OnClickListener() { public void onClick(View arg0) { //Track GoogleAnalytics Event googleTracker.trackEvent("ui_interaction", //category "from_icon", //action "schedule", //label 0); //value //Do Something Intent myIntent = new Intent(ActivityGoogleMapV2.this, ActivityStationSchedule.class); myIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP); startActivity(myIntent); } }); } private void addListenerOnTwitterImage() { imgTwitter = (ImageView) findViewById(R.id.imgTwitter); imgTwitter.setOnClickListener(new View.OnClickListener() { public void onClick(View arg0) { //Track GoogleAnalytics Event googleTracker.trackEvent("ui_interaction", //category "from_icon", //action "twitter", //label 0); //value //Do Something Intent myIntent = new Intent(ActivityGoogleMapV2.this, ActivityTwitterFeed.class); myIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP); startActivity(myIntent); } }); } /* END ---- MENU AND NAVIGATION ------------------------------------------------------------------------*/ @Override protected void onDestroy() { super.onDestroy(); // Stop the tracker when it is no longer needed. googleTracker.stopSession(); } @Override public void onConnectionFailed(ConnectionResult arg0) { // TODO Auto-generated method stub } @Override public void onConnected(Bundle connectionHint) { mLocationClient.requestLocationUpdates( REQUEST, this); // LocationListener } @Override public void onDisconnected() { // TODO Auto-generated method stub } @Override public void onLocationChanged(Location arg0) { // TODO Auto-generated method stub } }