package com.droidmapper.util;
import java.util.ArrayList;
import java.util.List;
import android.content.Context;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
/**
* Provides a way for the application to get the current device location. The location is retrieved
* from GPS, NETWORK and PASIVE providers.
*/
@Deprecated
public class LocationProvider {
private static final String TAG = LocationProvider.class.getName();
// Constants that define frequency of location updates:
private static final long UPDATE_LOCATION_TIME = 1000L * 60L * 10L;
private static final long UPDATE_LOCATION_DISTANCE = 100L;
private static final long TWO_MINUTES = 1000L * 60L * 2L;
private ArrayList<OnLocationUpdateListener> locationUpdateListeners;
private Location gpsLocation, networkLocation, passiveLocation;
private boolean isCreated, isGpsAvailable, isNetworkAvailable;
private LocationManager locationManager;
/**
* Default constructor. Constructs a new instance of this class from the supplied parameter.
*
* @param context This application's context.
*/
public LocationProvider(Context context) {
if (context == null) {
throw new NullPointerException("Context param can't be null.");
}
isGpsAvailable = true;
isNetworkAvailable = true;
// Initialize the array that will hold location update listeners:
locationUpdateListeners = new ArrayList<OnLocationUpdateListener>(1);
// We need a location manager instance to access location providers:
locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
// Get the last know locations from all three providers:
gpsLocation = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
networkLocation = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
passiveLocation = locationManager.getLastKnownLocation(LocationManager.PASSIVE_PROVIDER);
}
/**
* Registers an OnLocationUpdateListener instance with this instance of LocationProvider.
*
* @param oluListener The listener that wants to listen for location updates.
*/
public void addOnLocationUpdateListener(OnLocationUpdateListener oluListener) {
locationUpdateListeners.add(oluListener);
}
/**
* Unregisters an OnLocationUpdateListener instance from this instance of LocationProvider.
*
* @param oluListener The listener that no longer wants to listen for location updates.
*/
public void removeOnLocationUpdateListener(OnLocationUpdateListener oluListener) {
locationUpdateListeners.remove(oluListener);
}
/**
* Compares the locations acquired from all three providers and based on the location accuracy
* and timeliness returns the best fix.
*
* @return The most accurate and fresh location acquired from any of the three providers.
*/
public Location getBestLocation() {
Location ret = null;
if (isBetterLocation(gpsLocation, networkLocation)) {
if (isBetterLocation(gpsLocation, passiveLocation)) {
if (gpsLocation != null) {
ret = gpsLocation;
}
} else {
if (passiveLocation != null) {
ret = passiveLocation;
}
}
} else {
if (isBetterLocation(networkLocation, passiveLocation)) {
if (networkLocation != null) {
ret = networkLocation;
}
} else {
if (passiveLocation != null) {
ret = passiveLocation;
}
}
}
return ret;
}
/**
* @return <b>true</b> if at least one of the location providers(GPS, Network) is enabled and
* not out of service.
*/
public boolean areProvidersAvailable() {
boolean ret = false;
List<String> allProviders = locationManager.getAllProviders();
if (allProviders.indexOf(LocationManager.GPS_PROVIDER) >= 0
&& locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)
&& isGpsAvailable) {
ret = true;
} else if (allProviders.indexOf(LocationManager.NETWORK_PROVIDER) >= 0
&& locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)
&& isNetworkAvailable) {
ret = true;
}
return ret;
}
/**
* Clients need to call this method to send the command to the instance of this class to start
* listening for location updates.
*/
public void create() {
if (isCreated) {
return;
}
isCreated = true;
isGpsAvailable = true;
isNetworkAvailable = true;
// Get the list of all location providers available on local device:
List<String> allProviders = locationManager.getAllProviders();
// Start listening for location updates on available and enabled providers:
if (allProviders.indexOf(LocationManager.NETWORK_PROVIDER) >= 0
&& locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, UPDATE_LOCATION_TIME,
UPDATE_LOCATION_DISTANCE, locationListener);
}
if (allProviders.indexOf(LocationManager.GPS_PROVIDER) >= 0
&& locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, UPDATE_LOCATION_TIME,
UPDATE_LOCATION_DISTANCE, locationListener);
}
if (allProviders.indexOf(LocationManager.PASSIVE_PROVIDER) >= 0) {
locationManager.requestLocationUpdates(LocationManager.PASSIVE_PROVIDER, 0L, 0L, locationListener);
}
}
/**
* Clients need to call this method to send the command to the instance of this class to stop
* listening for location updates.<br>
* This must be done to preserve memory and lower battery consumption.
*/
public void destroy() {
this.isCreated = false;
locationManager.removeUpdates(locationListener);
locationUpdateListeners.clear();
}
/**
* Determines whether one Location reading is better than the current Location fix.
*
* @param location The new Location that you want to evaluate.
* @param currentBestLocation The current Location fix, to which you want to compare the new one.
* @return <b>true</b> if new location is better then the current location, otherwise <b>false</b>.
*/
private boolean isBetterLocation(Location location, Location currentBestLocation) {
// A new location is always better than no location:
if (currentBestLocation == null) {
return true;
}
if (location == null) {
return false;
}
// Check whether the new location fix is newer or older:
long timeDelta = location.getTime() - currentBestLocation.getTime();
boolean isSignificantlyNewer = timeDelta > TWO_MINUTES;
boolean isSignificantlyOlder = timeDelta < -TWO_MINUTES;
boolean isNewer = timeDelta > 0;
if (isSignificantlyNewer) {
// If it's been more than two minutes since the current location, use the new location
// because the user has likely moved:
return true;
} else if (isSignificantlyOlder) {
// If the new location is more than two minutes older, it must be worse:
return false;
}
// Check whether the new location fix is more or less accurate:
int accuracyDelta = (int) (location.getAccuracy() - currentBestLocation.getAccuracy());
boolean isLessAccurate = accuracyDelta > 0;
boolean isMoreAccurate = accuracyDelta < 0;
boolean isSignificantlyLessAccurate = accuracyDelta > 200;
// Check if the old and new location are from the same provider:
boolean isFromSameProvider = isSameProvider(location.getProvider(), currentBestLocation.getProvider());
// Determine location quality using a combination of timeliness and accuracy:
if (isMoreAccurate) {
return true;
} else if (isNewer && !isLessAccurate) {
return true;
} else if (isNewer && !isSignificantlyLessAccurate && isFromSameProvider) {
return true;
}
return false;
}
/**
* Checks whether providers supplied as parameters are the same.
*
* @param provider1 First provider.
* @param provider2 Second provider.
* @return <b>true</b> if they are the same, otherwise <b>false</b>.
*/
private boolean isSameProvider(String provider1, String provider2) {
if (provider1 == null) {
return provider2 == null;
}
return provider1.equals(provider2);
}
/**
* Notifies all registered listeners device location has been updated.
*/
private void notifyObservers() {
Location bestFixLocation = getBestLocation();
for (OnLocationUpdateListener luListener : locationUpdateListeners) {
luListener.onLocationUpdate(bestFixLocation);
}
}
/**
* An instance of LocationListener that we use to listen for location updates.
*/
private final LocationListener locationListener = new LocationListener() {
/**
* Called when the location has changed.
*
* @param location The new location.
*/
public void onLocationChanged(Location location) {
// Based on the location's provider updated the last known location for that provider,
// if the new location is a better fix:
String provider = location.getProvider();
if (provider == LocationManager.GPS_PROVIDER) {
if (isBetterLocation(location, gpsLocation)) {
gpsLocation = location;
notifyObservers();
}
} else if (provider == LocationManager.NETWORK_PROVIDER) {
if (isBetterLocation(location, networkLocation)) {
networkLocation = location;
notifyObservers();
}
} else if (provider == LocationManager.PASSIVE_PROVIDER) {
if (isBetterLocation(location, passiveLocation)) {
passiveLocation = location;
notifyObservers();
}
}
}
/**
* Called when the provider is disabled by the user. If requestLocationUpdates is called on
* an already disabled provider, this method is called immediately.
*
* @param provider The name of the location provider associated with this update.
*/
public void onProviderDisabled(String provider) {
// Do nothing.
}
/**
* Called when the provider is enabled by the user.
*
* @param provider The name of the location provider associated with this update.
*/
public void onProviderEnabled(String provider) {
// Do nothing.
}
/**
* Called when the provider status changes. This method is called when a provider is unable
* to fetch a location or if the provider has recently become available after a period of
* unavailability.
*
* @param provider The name of the location provider associated with this update.
* @param status The new status of the provider, as per the constants defined in the
* {@link android.location.LocationProvider} class.
* @param extras An optional Bundle which will contain provider specific status variables.
*/
public void onStatusChanged(String provider, int status, Bundle extras) {
if (provider == LocationManager.GPS_PROVIDER) {
isGpsAvailable = (status == android.location.LocationProvider.AVAILABLE);
} else if (provider == LocationManager.NETWORK_PROVIDER) {
isNetworkAvailable = (status == android.location.LocationProvider.AVAILABLE);
} else if (provider == LocationManager.PASSIVE_PROVIDER) {
// Do nothing.
}
}
};
/**
* This interface should be implemented by all classes that want to listen for device location
* updates.
*/
public static interface OnLocationUpdateListener {
/**
* A callback method that will be called to notify the listener that device location has
* changed.
*
* @param bestFixLocation The best possible location acquired from any of the registered
* providers.
*/
public void onLocationUpdate(Location bestFixLocation);
}
}