package nz.co.android.cowseye.gps; import java.io.IOException; import java.util.List; import java.util.Locale; import nz.co.android.cowseye.R; import nz.co.android.cowseye.activity.RecordLocationActivity; import nz.co.android.cowseye.service.ReverseGeoCodeCoordinatesService; import nz.co.android.cowseye.utility.AlertBuilder; import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; import android.location.Address; import android.location.Criteria; import android.location.Geocoder; import android.location.Location; import android.location.LocationListener; import android.location.LocationManager; import android.os.Bundle; import android.util.Log; import android.view.Window; import android.view.WindowManager.BadTokenException; import android.widget.Toast; import com.google.android.maps.GeoPoint; /** Managers the GPS updates and location of client * * @author Mitchell Lane */ public class GPSManager implements LocationListener{ AlertDialog alert; private static final String USER_LOCATION_LATITUDE_KEY = "LAT_KEY"; private static final String USER_LOCATION_LONGITUDE_KEY = "LON_KEY"; private GeoPoint userLocationGeoPoint; private Location lastKnownLocation; private static MapManager mapHelper; private static Context context; private static RecordLocationActivity locationActivity; private LocationManager locationManager; private Geocoder geocoder; /* Singleton*/ private static GPSManager gpsManager; public static GPSManager getInstance(){ return gpsManager; } public static GPSManager getInstance(MapManager mapHelper, LocationManager lm, Context app, Bundle savedInstanceState){ gpsManager = new GPSManager(mapHelper, lm, app, savedInstanceState); return gpsManager; } private GPSManager(MapManager mapHelper, LocationManager lm, Context app, Bundle savedInstanceState){ this.mapHelper = mapHelper; locationManager = lm; context = app; locationActivity = (RecordLocationActivity)app; geocoder = new Geocoder(context, Locale.getDefault()); setupGPS(savedInstanceState); } /* Sets up the GPS with receiving updates via GPS and networks */ private void setupGPS(Bundle savedInstanceState){ requestUpdateListeners(); //If no location found in state if(!retrieveLocationOnStart(savedInstanceState)){ //Tries to draw the user position and centre map to it try{ Location loc = determineLastKnownLocation(); if(loc!=null){ updateLocationActivity(loc); // mapHelper.drawUserPosition(userLocationGeoPoint); // mapHelper.setMapViewToLocation(userLocationGeoPoint); } }catch(NoLocationFoundException e){ // Toast.makeText(context, context.getResources().getString(R.string.gps_no_location_message), Toast.LENGTH_SHORT).show(); Log.e(toString(), "Cannot get a fix on user location: "+e.toString()); } } //location found so draw it else{ mapHelper.drawUserPosition(userLocationGeoPoint); } } /* Returns the last known location of the current user as a geo point, containing the latitude and longitude */ private Location determineLastKnownLocation() throws NoLocationFoundException{ Criteria criteria = new Criteria(); criteria.setAccuracy(Criteria.ACCURACY_FINE); criteria.setAltitudeRequired(false); // Log.d(toString(), "locMan: "+ locationManager); // Log.d(toString(), "provid: "+ locationManager.getBestProvider(criteria, true)); String provider = locationManager.getBestProvider(criteria, true); if(provider==null) throw new NoLocationFoundException("No provider - LocationManager"); Location location = locationManager.getLastKnownLocation(provider); if(location==null){ throw new NoLocationFoundException("Originated from FriendFinderActivity.determineUserPosition - LocationManager"); } lastKnownLocation = location; userLocationGeoPoint = new GeoPoint((int)(lastKnownLocation.getLatitude()*1E6), (int)(lastKnownLocation.getLongitude()*1E6)); return lastKnownLocation; } /** removes the gps update listeners*/ public void removeUpdates() { locationManager.removeUpdates(this); } /** Adds the gps update listeneres */ public void requestUpdateListeners() { locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 10000, 10, this); locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 15000, 10, this); } /** Returns the location of the user as a geo point containing latitude and longitutude */ public GeoPoint getUserLocationGeoPoint() { return userLocationGeoPoint; } /** * Saves the last location upon destroying of main activity */ public void saveStateOnDestroy(Bundle savedInstanceState) { //store user location if(userLocationGeoPoint!=null){ savedInstanceState.putInt(USER_LOCATION_LATITUDE_KEY, userLocationGeoPoint.getLatitudeE6()); savedInstanceState.putInt(USER_LOCATION_LONGITUDE_KEY, userLocationGeoPoint.getLongitudeE6()); } } /** * Set last location upon resume * @return true if the location retrieved is successfull, otherwise false */ public boolean retrieveLocationOnStart(Bundle savedInstanceState) { if(savedInstanceState==null) return false; //Retrieve user location if it exists if(savedInstanceState.containsKey(USER_LOCATION_LATITUDE_KEY) && savedInstanceState.containsKey(USER_LOCATION_LONGITUDE_KEY)){ userLocationGeoPoint = new GeoPoint(savedInstanceState.getInt(USER_LOCATION_LATITUDE_KEY),savedInstanceState.getInt(USER_LOCATION_LONGITUDE_KEY)); return true; } return false; } /** Received a location change event from GPS or network provider */ @Override public void onLocationChanged(Location location) { // update last known position lastKnownLocation = location; double lat = 0; double lon = 0; if(userLocationGeoPoint!=null){ lat = userLocationGeoPoint.getLatitudeE6()/1E6; lon = userLocationGeoPoint.getLongitudeE6()/1E6; } GeoPoint newGeoPoint = new GeoPoint((int) ( lastKnownLocation.getLatitude() * 1E6), (int) ( lastKnownLocation.getLongitude() * 1E6)); if((newGeoPoint.getLatitudeE6()/1E6 == lat) && (newGeoPoint.getLongitudeE6()/1E6 == lon)){ return; } userLocationGeoPoint = newGeoPoint; // locationActivity.setGeoCoordinates(userLocationGeoPoint); // add new user position updateLocationActivity(location); Log.i(toString(), "User location changed : "+(int) ( location.getLatitude() * 1E6)+" , "+ (int) ( location.getLongitude() * 1E6)); } /** Converts a location with latitude and longitude coordinates to an address */ public void updateLocationActivity(Location location) { //execute service to get a human readable address from given latitude and longitude coordinates new ReverseGeoCodeCoordinatesService(context, this, geocoder, location, locationActivity.getAddress().trim(),userLocationGeoPoint).execute(); } /** Converts a given address in text to latitude and longitude coordinates in an Address object */ public Address getCoordinatesFromAddress(String addr){ try{ List<Address> addresses = geocoder.getFromLocationName(addr,1); if (addresses == null) { Log.e(toString(), "No lat,long found from addr :"+addr); return null; } Address location = addresses.get(0); location.getLatitude(); location.getLongitude(); return location; } catch (IOException e) { Log.e(toString(), "Geocoding error: "+e); Toast.makeText(context, context.getResources().getString(R.string.errorInGeoCoding), Toast.LENGTH_SHORT).show(); } return null; } @Override public void onProviderDisabled(String provider) {} @Override public void onProviderEnabled(String provider) {} @Override public void onStatusChanged(String provider, int status, Bundle extras) {} public void requestBuildAlertMessageUpdatePosition(String addr, GeoPoint userPoint) { if(alert!=null) alert.dismiss(); alert = AlertBuilder.buildAlertMessageUpdatePosition(locationActivity, mapHelper, locationActivity, addr, userPoint); try{ if(alert!=null) alert.show(); } catch(BadTokenException e){}; } public Geocoder getGeoCoder() { return geocoder; } public void errorReverseGeoCoding() { if(alert!=null) alert.dismiss(); Toast.makeText(context, context.getResources().getString(R.string.gps_no_location_message), Toast.LENGTH_SHORT).show(); Log.e(toString(), "Cannot get a fix on user location: "); } }