package it.geosolutions.geocollect.android.core.mission.utils;
import java.util.Timer;
import java.util.TimerTask;
import android.content.Context;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.util.Log;
/**
* class which tries to acquire the current location within a time limit
* it uses both network and gps provider and will return the first location it gets from
* one of them
* if both not succeed, they are asked for their last known location
* hence it should be quite unlikely that no location is acquired at all
*
* if successful the location is returned, if not null after the TIMEOUT
*
* the TIMEOUT is currently set to 10000 ms -> 10 sec
*
* @author Robert Oehler
*
*/
public class LocationProvider {
private final static String TAG = LocationProvider.class.getSimpleName();
private final int TIMEOUT = 10000;
private Timer timer;
private LocationManager locationManager;
private LocationResultCallback locationResultCallback;
private boolean gps_enabled=false;
private boolean network_enabled=false;
/**
* setup location listeners
* @param context a context
* @param result the result callback
* @return false if no providers are available, true otherwise
*/
public boolean getLocation(Context context, LocationResultCallback result) {
try{
locationResultCallback = result;
if(locationManager == null){
locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
}
//exceptions will be thrown if provider is not permitted.
try{
gps_enabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
}catch(Exception ex){
//does not interest here
}
try{
network_enabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
}catch(Exception ex){
//does not interest here
}
//don't start listeners if no provider is enabled
if(!gps_enabled && !network_enabled){
return false;
}
//if available, get gps location
if(gps_enabled){
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListenerGps);
}
//if available, get network location
if(network_enabled){
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locationListenerNetwork);
}
//start a timer which will start after the timeout threshold
timer = new Timer();
timer.schedule(new GetLastLocation(), TIMEOUT);
}catch(final Exception e){
Log.e(TAG, "error gotLocation",e);
}
return true;
}
LocationListener locationListenerGps = new LocationListener() {
public void onLocationChanged(Location location) {
try{
//gps location found, cancel timer, report location, remove listener
timer.cancel();
locationResultCallback.gotLocation(location);
locationManager.removeUpdates(this);
locationManager.removeUpdates(locationListenerNetwork);
}catch(final Exception e){
Log.e(TAG, "error gotLocation",e);
}finally{
try{
locationManager.removeUpdates(this);
locationManager.removeUpdates(locationListenerNetwork);
}catch(Exception e){
// ignore
}
}
}
public void onProviderDisabled(String provider) {}
public void onProviderEnabled(String provider) {}
public void onStatusChanged(String provider, int status, Bundle extras) {}
};
LocationListener locationListenerNetwork = new LocationListener() {
public void onLocationChanged(Location location) {
try{
//network location found, cancel timer, report location, remove listener
timer.cancel();
locationResultCallback.gotLocation(location);
locationManager.removeUpdates(this);
locationManager.removeUpdates(locationListenerGps);
}catch(final Exception e){
Log.e(TAG, "error gotLocation",e);
}
}
public void onProviderDisabled(String provider) {}
public void onProviderEnabled(String provider) {}
public void onStatusChanged(String provider, int status, Bundle extras) {}
};
class GetLastLocation extends TimerTask {
@Override
public void run() {
try{
//the TIMEOUT period was reached, the listeners did not fire, remove updates
locationManager.removeUpdates(locationListenerGps);
locationManager.removeUpdates(locationListenerNetwork);
//check if there is at least a last known location
Location net_loc=null, gps_loc=null;
if(gps_enabled){
gps_loc=locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
}
if(network_enabled){
net_loc=locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
}
//if there are both values use the latest one
if(gps_loc!=null && net_loc!=null){
if(gps_loc.getTime() > net_loc.getTime()){
locationResultCallback.gotLocation(gps_loc);
}else{
locationResultCallback.gotLocation(net_loc);
}
return;
}
//if available, report
if(gps_loc != null){
locationResultCallback.gotLocation(gps_loc);
return;
}
if(net_loc != null){
locationResultCallback.gotLocation(net_loc);
return;
}
//all failed, report null
locationResultCallback.gotLocation(null);
}catch(final Exception e){
Log.e(TAG, "error gotLocation",e);
}
}
}
public static abstract class LocationResultCallback{
public abstract void gotLocation(Location location);
}
}