package org.rudirect.android.fragment; import android.Manifest; import android.content.pm.PackageManager; import android.content.res.TypedArray; import android.os.AsyncTask; import android.os.Bundle; import android.os.Handler; import android.support.v4.app.ActivityCompat; import android.support.v4.content.ContextCompat; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import com.google.android.gms.analytics.HitBuilders; import com.google.android.gms.common.ConnectionResult; import com.google.android.gms.common.GoogleApiAvailability; import com.google.android.gms.maps.CameraUpdateFactory; import com.google.android.gms.maps.GoogleMap; import com.google.android.gms.maps.MapFragment; import com.google.android.gms.maps.OnMapReadyCallback; 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 org.rudirect.android.R; import org.rudirect.android.activity.RouteActivity; import org.rudirect.android.api.NextBusAPI; import org.rudirect.android.data.constants.RUDirectApplication; import org.rudirect.android.data.model.BusPathSegment; import org.rudirect.android.data.model.BusStop; import org.rudirect.android.data.model.BusVehicle; import java.util.ArrayList; public class BusMapFragment extends MapFragment implements OnMapReadyCallback { private static final int ACTIVE_BUS_REFRESH_INTERVAL = 10000; private RouteActivity routeActivity; private GoogleMap mMap; private Handler refreshHandler; private ArrayList<Marker> busStopMarkers; private ArrayList<Marker> activeBusMarkers; private BusPathSegment[] pathSegments; private boolean isVisible; private boolean connectedToPlayServices; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); routeActivity = (RouteActivity) getActivity(); setHasOptionsMenu(true); connectedToPlayServices = GoogleApiAvailability.getInstance() .isGooglePlayServicesAvailable(routeActivity) == ConnectionResult.SUCCESS; } @Override public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); activeBusMarkers = new ArrayList<>(); busStopMarkers = new ArrayList<>(); isVisible = false; if (connectedToPlayServices) { pathSegments = routeActivity.getRoute().getBusPathSegments(); getMapAsync(this); } } @Override public void onMapReady(final GoogleMap map) { if (connectedToPlayServices) { mMap = map; // Change map settings and set center location mMap.getUiSettings().setMapToolbarEnabled(false); BusStop stop = routeActivity.getRoute().getBusStops()[0]; mMap.animateCamera(CameraUpdateFactory.newLatLngZoom( getLatLng(stop.getLatitude(), stop.getLongitude()), 13.0f)); // Move Google logo up so that it's visible final TypedArray styledAttributes = RUDirectApplication.getContext().getTheme().obtainStyledAttributes( new int[] { android.R.attr.actionBarSize }); int actionBarHeight = (int) styledAttributes.getDimension(0, 0); styledAttributes.recycle(); mMap.setPadding(0, 0, 0, actionBarHeight); // Show current location on map if (ContextCompat.checkSelfPermission(routeActivity, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) { mMap.setMyLocationEnabled(true); } else { ActivityCompat.requestPermissions(routeActivity, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 0); } drawRoute(); } } @Override public void onResume() { super.onResume(); // Auto refreshes active bus locations refreshHandler = new Handler(); refreshHandler.postDelayed(new Runnable() { @Override public void run() { if (mMap != null && isVisible) new UpdateMarkers().execute(); refreshHandler.postDelayed(this, ACTIVE_BUS_REFRESH_INTERVAL); } }, ACTIVE_BUS_REFRESH_INTERVAL); } @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { super.onCreateOptionsMenu(menu, inflater); inflater.inflate(R.menu.menu_refresh, menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { int id = item.getItemId(); if (id == R.id.refresh) { if (connectedToPlayServices) new UpdateMarkers().execute(); return true; } return super.onOptionsItemSelected(item); } @Override public void setUserVisibleHint(boolean isVisibleToUser) { super.setUserVisibleHint(isVisibleToUser); isVisible = isVisibleToUser; if (isVisible && isAdded()) { RUDirectApplication.getTracker().send(new HitBuilders.EventBuilder() .setCategory(getString(R.string.route_map_category)) .setAction(getString(R.string.view_action)) .setLabel(routeActivity.getTitle().toString()) .build()); if (connectedToPlayServices) new UpdateMarkers().execute(); } } // Draws the bus route on the map private void drawRoute() { // Draws the active bus locations new UpdateMarkers().execute(); // Draws the bus route int polyLineColor = ContextCompat.getColor(RUDirectApplication.getContext(), R.color.polyline_color); for (BusPathSegment pathSegment : pathSegments) { PolylineOptions polylineOptions = new PolylineOptions(); polylineOptions.color(polyLineColor); double[] latitudes = pathSegment.getLatitudes(); double[] longitudes = pathSegment.getLongitudes(); int size = latitudes.length; for (int j = 0; j < size; j++) { polylineOptions.add(getLatLng(latitudes[j], longitudes[j])); } mMap.addPolyline(polylineOptions); } } private LatLng getLatLng(double latitude, double longitude) { return new LatLng(latitude, longitude); } public void setPathSegments(BusPathSegment[] pathSegments) { this.pathSegments = pathSegments; } // Update active bus locations private class UpdateMarkers extends AsyncTask<Void, Void, Void> { @Override protected Void doInBackground(Void... voids) { NextBusAPI.updateActiveRoutes(); return null; } @Override protected void onPostExecute(Void v) { // Update active bus locations ArrayList<BusVehicle> activeBuses = routeActivity.getRoute().getActiveBuses(); if (activeBuses != null) { // Clear map of active bus markers for (int i = 0; i < activeBusMarkers.size(); i++) { activeBusMarkers.get(i).remove(); } activeBusMarkers.clear(); // Add active bus markers for (int i = 0; i < activeBuses.size(); i++) { double[] location = activeBuses.get(i).getLocation(); MarkerOptions markerOptions = new MarkerOptions() .position(getLatLng(location[0], location[1])) .title("Vehicle ID: " + activeBuses.get(i).getVehicleId()) .icon(BitmapDescriptorFactory.fromResource(R.drawable.ic_bus)); activeBusMarkers.add(mMap.addMarker(markerOptions)); } } // Draw the bus stop markers BusStop[] busStops = routeActivity.getRoute().getBusStops(); if (busStops != null) { if (busStopMarkers.isEmpty()) { // Create the markers for (BusStop stop : busStops) { MarkerOptions markerOptions = new MarkerOptions() .position(getLatLng(stop.getLatitude(), stop.getLongitude())) .title(stop.getTitle()); if (!stop.isActive()) { markerOptions.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_AZURE)); } busStopMarkers.add(mMap.addMarker(markerOptions)); } } else { // Change the color if necessary for (int i = 0; i < busStops.length; i++) { if (!busStops[i].isActive()) { busStopMarkers.get(i).setIcon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_AZURE)); } else { busStopMarkers.get(i).setIcon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_RED)); } } } } } } }