0

I am now working on a application related to plotting buses and bus stops on the map. One task is to get the user's current location and stop updating when the app pauses and continue updating when the app resumes. Also, location update occurs at most once every 10 seconds or with a change in position of at least 25 meters. I need to plot user's current location on the map.

Here's the code for MapDisplayFragment. OverlayItems are added here (including the OverlayItem representing user's location), and it seems that I need to create new classes to implement these functionality instead of writing code in this class like what I did. I am thinking of building two classes: MyLocationListener which extends LocationListener and MyLocationFragment which extends Fragment, but now I don't know how to get started: more specifically, I don't know what relationship between these classes I should build. Any idea?

import java.util.ArrayList;
import java.util.List;

import org.osmdroid.DefaultResourceProxyImpl;
import org.osmdroid.ResourceProxy;
import org.osmdroid.api.IMapController;
import org.osmdroid.tileprovider.tilesource.TileSourceFactory;
import org.osmdroid.util.GeoPoint;
import org.osmdroid.views.MapView;
import org.osmdroid.views.overlay.ItemizedIconOverlay;
import org.osmdroid.views.overlay.ItemizedIconOverlay.OnItemGestureListener;
import org.osmdroid.views.overlay.OverlayItem;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.res.Resources;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationManager;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import ca.ubc.cpsc210.exception.TranslinkException;
import ca.ubc.cpsc210.nextbus.model.Bus;
import ca.ubc.cpsc210.nextbus.model.BusStop;
import ca.ubc.cpsc210.nextbus.translink.ITranslinkService;
import ca.ubc.cpsc210.nextbus.translink.TranslinkService;
import ca.ubc.cpsc210.nextbus.util.LatLon;
import ca.ubc.cpsc210.nextbus.util.TextOverlay;

/**
 * Fragment holding the map in the UI.
 */
public class MapDisplayFragment extends Fragment {

    /**
     * Log tag for LogCat messages
     */
    private final static String LOG_TAG = "MapDisplayFragment";

    /**
     * Location of Nelson & Granville, downtown Vancouver
     */
    private final static GeoPoint NELSON_GRANVILLE 
    = new GeoPoint(49.279285, -123.123007);

    /**
     * Overlay for bus markers.
     */
    private ItemizedIconOverlay<OverlayItem> busLocnOverlay;

    /**
     * Overlay for bus stop location
     */
    private ItemizedIconOverlay<OverlayItem> busStopLocationOverlay;

    /**
     * Overlay for legend
     */
    private TextOverlay legendOverlay;


    /**
     * View that shows the map
     */
    private MapView mapView;

    /**
     * Selected bus stop
     */
    private BusStop selectedStop;

    /**
     * Wraps Translink web service
     */
    private ITranslinkService tlService;

    /**
     * Map controller for zooming in/out, centering
     */
    private IMapController mapController;

    /**
     * True if and only if map should zoom to fit displayed route.
     */
    private boolean zoomToFit;

    /**
     * Bus selected by user
     */
    private OverlayItem selectedBus;

    /**
     * User's location icon.
     */
    private OverlayItem userLocnIcon;

    /**
     * Overlay for user current location.
     */
    private ItemizedIconOverlay<OverlayItem> userLocnOverlay;

    /**
     * User's location.
     */
    private GeoPoint location;

    /**
     * Set up Translink service
     */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        Log.d(LOG_TAG, "onActivityCreated");

        setHasOptionsMenu(true);

        tlService = new TranslinkService(getActivity());

        Log.d(LOG_TAG, "Stop number for mapping: " + (selectedStop == null ? "not set" : selectedStop.getStopNum()));
    }

    /**
     * Set up map view with overlays for buses and selected bus stop.
     */
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        Log.d(LOG_TAG, "onCreateView");

        if (mapView == null) {
            mapView = new MapView(getActivity(), null);

            mapView.setTileSource(TileSourceFactory.MAPNIK);
            mapView.setClickable(true);
            mapView.setBuiltInZoomControls(true);

            // set default view for map (this seems to be important even when
            // it gets overwritten by plotBuses)
            mapController = mapView.getController();
            mapController.setZoom(mapView.getMaxZoomLevel() - 4);
            mapController.setCenter(NELSON_GRANVILLE);


            busLocnOverlay = createBusLocnOverlay();
            busStopLocationOverlay = createBusStopLocnOverlay();
            legendOverlay = createTextOverlay();
            userLocnOverlay = createUserLocnOverlay();

            // Order matters: overlays added later are displayed on top of
            // overlays added earlier.
            mapView.getOverlays().add(busStopLocationOverlay);
            mapView.getOverlays().add(busLocnOverlay);
            mapView.getOverlays().add(userLocnOverlay);
            mapView.getOverlays().add(legendOverlay);


        }

        return mapView;
    }


    @Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        super.onCreateOptionsMenu(menu, inflater);
        inflater.inflate(R.menu.fragment_map_refresh, menu);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        if (item.getItemId() == R.id.map_refresh) {
            update(false);
            return true;
        }

        return super.onOptionsItemSelected(item);
    }

    /**
     * When view is destroyed, remove map view from its parent so that it can be
     * added again when view is re-created.
     */
    @Override
    public void onDestroyView() {
        Log.d(LOG_TAG, "onDestroyView");

        ((ViewGroup) mapView.getParent()).removeView(mapView);

        super.onDestroyView();
    }

    @Override
    public void onDestroy() {
        Log.d(LOG_TAG, "onDestroy");

        super.onDestroy();
    }

    /**
     * Update bus locations.
     */
    @Override
    public void onResume() {
        Log.d(LOG_TAG, "onResume");

        update(true);

        super.onResume();
    }

    /**
     * Set selected bus stop
     * @param selectedStop  the selected stop
     */
    public void setBusStop(BusStop selectedStop) {
        this.selectedStop = selectedStop;
    }

    /**
     * Update bus location info for selected stop,
     * zoomToFit status and repaint.
     * 
     * @Param zoomToFit  true if map must be zoomed to fit (when new bus stop has been selected)
     */
    void update(boolean zoomToFit) {
        Log.d(LOG_TAG, "update - zoomToFit: " + zoomToFit);

        this.zoomToFit = zoomToFit;

        if(selectedStop != null) {
            new GetBusInfo().execute(selectedStop);
            selectedBus = null;
        }

        mapView.invalidate();

    }

    /**
     * Create the overlay for bus markers.
     */
    private ItemizedIconOverlay<OverlayItem> createBusLocnOverlay() {
        ResourceProxy rp = new DefaultResourceProxyImpl(getActivity());

        OnItemGestureListener<OverlayItem> gestureListener = new OnItemGestureListener<OverlayItem>() {
            /**
             * Display bus information in dialog box when user taps
             * bus.
             * 
             * @param index  index of item tapped
             * @param oi the OverlayItem that was tapped
             * @return true to indicate that tap event has been handled
             */
            @Override
            public boolean onItemSingleTapUp(int index, OverlayItem oi) {
                AlertDialog dlg = createSimpleDialog(oi.getTitle(), oi.getSnippet());
                dlg.show();
                if(selectedBus != null){
                    selectedBus.setMarker(getResources().getDrawable(R.drawable.bus));
                }
                selectedBus = oi;
                selectedBus.setMarker(getResources().getDrawable(R.drawable.selected_bus));
                mapView.postInvalidate();
                return true;
            }

            @Override
            public boolean onItemLongPress(int index, OverlayItem oi) {
                // do nothing
                return false;
            }
        };

        return new ItemizedIconOverlay<OverlayItem>(
                new ArrayList<OverlayItem>(), 
                getResources().getDrawable(R.drawable.bus), 
                gestureListener, rp);
    }



    /**
     * Create the overlay for bus stop marker.
     */
    private ItemizedIconOverlay<OverlayItem> createBusStopLocnOverlay() {
        ResourceProxy rp = new DefaultResourceProxyImpl(getActivity());

        OnItemGestureListener<OverlayItem> gestureListener = new OnItemGestureListener<OverlayItem>() {
            /**
             * Display bus stop description in dialog box when user taps
             * stop.
             * 
             * @param index  index of item tapped
             * @param oi the OverlayItem that was tapped
             * @return true to indicate that tap event has been handled
             */
            @Override
            public boolean onItemSingleTapUp(int index, OverlayItem oi) {
                AlertDialog dlg = createSimpleDialog(oi.getTitle(), oi.getSnippet());
                dlg.show();

                return true;
            }

            @Override
            public boolean onItemLongPress(int index, OverlayItem oi) {
                // do nothing
                return false;
            }
        };

        return new ItemizedIconOverlay<OverlayItem>(
                new ArrayList<OverlayItem>(), 
                getResources().getDrawable(R.drawable.stop), 
                gestureListener, rp);
    }

    private TextOverlay createTextOverlay() {
        ResourceProxy rp = new DefaultResourceProxyImpl(getActivity());
        Resources res = getResources();
        String legend = res.getString(R.string.legend);

        return new TextOverlay(rp, legend);
    }

    /**
     * Create the overlay for user location markers.
     */
    private ItemizedIconOverlay<OverlayItem> createUserLocnOverlay() {
        ResourceProxy rp = new DefaultResourceProxyImpl(getActivity());

        OnItemGestureListener<OverlayItem> gestureListener = new OnItemGestureListener<OverlayItem>() {
            /**
             * Display user location.
             * 
             * @param index  index of item tapped
             * @param oi the OverlayItem that was tapped
             * @return true to indicate that tap event has been handled
             */
            @Override
            public boolean onItemSingleTapUp(int index, OverlayItem oi) {
                // Don't do anything.
                return false;
            }

            @Override
            public boolean onItemLongPress(int index, OverlayItem oi) {
                // do nothing
                return false;
            }
        };

        return new ItemizedIconOverlay<OverlayItem>(
                new ArrayList<OverlayItem>(), 
                getResources().getDrawable(R.drawable.map_pin_blue), 
                gestureListener, rp);
    }

    /**
     * Plot bus stop
     */
    private void plotBusStop() {
        LatLon latlon = selectedStop.getLatLon();
        GeoPoint point = new GeoPoint(latlon.getLatitude(),
                latlon.getLongitude());
        OverlayItem overlayItem = new OverlayItem(Integer.valueOf(selectedStop.getStopNum()).toString(), 
                selectedStop.getLocationDesc(), point);
        busStopLocationOverlay.removeAllItems(); // make sure not adding
        // bus stop more than once
        busStopLocationOverlay.addItem(overlayItem);
    }

    /**
     * Plot buses onto bus location overlay
     * 
     * @param zoomToFit  determines if map should be zoomed to bounds of plotted buses
     */
    private void plotBuses(boolean zoomToFit) {
        List<Bus> buses = selectedStop.getBuses();
        Double maxlatSpan = 0.0;
        Double maxlonSpan = 0.0;


        busLocnOverlay.removeAllItems();
        for(Bus b : buses){
            Double latDifference = Math.abs(b.getLatLon().getLatitude()-NELSON_GRANVILLE.getLatitude() );
            if(latDifference > maxlatSpan && (latDifference < 2.0)){
                maxlatSpan = latDifference;
            }
            Double lonDifference = Math.abs(b.getLatLon().getLongitude()-NELSON_GRANVILLE .getLongitude());
            if(lonDifference > maxlonSpan && (lonDifference < 2.0)){
                maxlonSpan = lonDifference;
            }
            String routeNo = b.getRoute().getName();
            String desc = b.getDescription();
            LatLon latlon = b.getLatLon();
            GeoPoint point = new GeoPoint(latlon.getLatitude(), latlon.getLongitude());
            OverlayItem overlayItem = new OverlayItem(routeNo, desc, point);
            busLocnOverlay.addItem(overlayItem);
        }

        if(zoomToFit){
            mapController.zoomToSpan((int)Math.abs(maxlatSpan*2E6), (int) Math.abs(maxlonSpan*2E6));
        }


    }


    /**
     * Helper to create simple alert dialog to display message
     * @param title  the title to be displayed at top of dialog
     * @param msg  message to display in dialog
     * @return  the alert dialog
     */
    private AlertDialog createSimpleDialog(String title, String msg) {
        AlertDialog.Builder dialogBldr = new AlertDialog.Builder(getActivity());
        dialogBldr.setTitle(title);
        dialogBldr.setMessage(msg);
        dialogBldr.setNeutralButton(R.string.ok, null);

        return dialogBldr.create();
    }

    public void getUserLocation() {
        Criteria criteria = new Criteria();
        Context cont = new Activity();


        LocationManager locationManager = (LocationManager) getActivity().getSystemService(Context.LOCATION_SERVICE);
        String bestProvider = locationManager.getBestProvider(criteria, true);

        Location userLocation = locationManager.getLastKnownLocation(bestProvider); 
        location = new GeoPoint(userLocation.getLatitude() * 1E6, userLocation.getLongitude() * 1E6);




    }

    private void plotUserLocation() {
        getUserLocation();
        userLocnIcon = new OverlayItem("UserLocn", "User location", location);

        userLocnOverlay.addItem(userLocnIcon);

    }

    /** 
     * Asynchronous task to get bus location estimates from Translink service.
     * Displays progress dialog while running in background.  
     */
    private class GetBusInfo extends
    AsyncTask<BusStop, Void, Void> {
        private ProgressDialog dialog = new ProgressDialog(getActivity());
        private boolean success = true;

        @Override
        protected void onPreExecute() {
            dialog.setMessage("Retrieving bus info...");
            dialog.show();
        }

        @Override
        protected Void doInBackground(BusStop... selectedStops) {
            BusStop selectedStop = selectedStops[0];

            try {
                tlService.addBusLocationsForStop(selectedStop);
            } catch (TranslinkException e) {
                e.printStackTrace();
                success = false;
            }

            return null;
        }

        @Override
        protected void onPostExecute(Void dummy) {
            dialog.dismiss();

            if (success) {
                plotBuses(zoomToFit);
                plotBusStop();
                plotUserLocation();
                mapView.invalidate();
            } else {
                AlertDialog dialog = createSimpleDialog("Error", "Unable to retrieve bus location info...");
                dialog.show();
            }
        }
    }
}

Any help is appreciated.

988lmh988
  • 1
  • 1

1 Answers1

0

I had the same problem but after doing search on google i get to know that mapview is deprecated now. So you must use the map fragment and extend fragmentActivity instead of mapactivity

user3853169
  • 209
  • 3
  • 14