package com.adisayoga.earthquake.utils; import java.util.List; import android.content.Context; import android.location.Criteria; import android.location.Location; import android.location.LocationListener; import android.location.LocationManager; import android.os.Bundle; import android.util.Log; /** * This class let's yout find the "best" (most accurate and timely) previously * detected location using whatever providers are available. * <p> * Where a timely/accurate provious location is not detected it will * return the newest location (where one exists) and setup a one-off location * update to find the current location. * <p> * Based on: <a href="http://android-developers.blogspot.com/2011/06/deep-dive-into-location.html"> * A Deep Dive Into Location</a> */ public class LocationFinder { private static final String TAG = "LocationFinder"; /** The default search radius when searching for places enarby. */ public static final int DEFAULT_RADIUS = 150; /** The maximum distance the user should travel between location updates. */ public static final int MAX_DISTANCE = DEFAULT_RADIUS / 2; /** The maximum time that should pass before the user gets a location update */ //public static final long MAX_TIME = AlarmManager.INTERVAL_FIFTEEN_MINUTES; private LocationListener locationListener; private final LocationManager locationManager; private final Criteria criteria; private final Context context; public LocationFinder(Context context) { this.context = context; locationManager = (LocationManager) context.getSystemService( Context.LOCATION_SERVICE); criteria = new Criteria(); /* * Coarse accuracy is specified here to get the fastest possible result. * The calling activity will likely (or have already) request ongoing * updates using the Fine location provider. */ criteria.setAccuracy(Criteria.ACCURACY_COARSE); } /** * Returns the most accourate and timely previously detected location. * Where the last result is beyond the specified maximum distance or * latency a one-off location update is returned via the {@link LocationListener} * specified in {@link setChangedLocationListener}. * * @param minDistance Minimum distance before we require a location update * @param minTime Minimum time require between location updates * @return The most accurate and/or timely previously detected location */ public Location getLastLocation(int minDistance, long minTime) { Location bestResult = null; float bestAccuracy = Float.MAX_VALUE; long bestTime = Long.MAX_VALUE; /* * Iterate through all the providers on the system, keeping note * of the most accurate result within the acceptable time limit. * If no result is found within maxTime, return the newest Location. */ List<String> matchingProviders = locationManager.getAllProviders(); for (String provider : matchingProviders) { Location location = locationManager.getLastKnownLocation(provider); if (location == null) continue; float accuracy = location.getAccuracy(); long time = location.getTime(); if (time < minTime && accuracy < bestAccuracy) { bestResult = location; bestAccuracy = accuracy; bestTime = time; } else if (bestAccuracy == Float.MAX_VALUE && time < minTime && time < bestTime) { bestResult = location; bestTime = time; } } /* * If the best result is beyond the allowed time limit, or the * accuracy of the best result is wider then the acceptable maximum * distance, request a single update. * This check simply implements the same conditions we set when * requesting regular location update every [minTime] and [minDistance]. */ if (locationListener != null && (bestTime > minTime || bestAccuracy > minDistance)) { String provider = locationManager.getBestProvider(criteria, true); if (provider != null) { locationManager.requestLocationUpdates(provider, 0, 0, singleUpdateListener, context.getMainLooper()); } } return bestResult; } /** * Set the {@link LocationListener} that may receiver a one-shot current * location update. * @param locationListener LocationListener */ public void setChangedLocationListener(LocationListener locationListener) { this.locationListener = locationListener; } /** * Cancel the one-shot current location update. */ public void cancel() { locationManager.removeUpdates(singleUpdateListener); } /** * This one-off {@link LocationListener} simply listens for a single * update before unregistering itself. * <p> * The one-off location update is returned via the {@link LocationListener} * specified in {@link setChangedLocationListener}. */ private final LocationListener singleUpdateListener = new LocationListener() { @Override public void onLocationChanged(Location location) { Log.d(TAG, "Single location update received: " + location.getLatitude() + ", " + location.getLongitude()); if (locationListener != null && location != null) { locationListener.onLocationChanged(location); } locationManager.removeUpdates(singleUpdateListener); } @Override public void onStatusChanged(String provider, int status, Bundle extras) { } @Override public void onProviderEnabled(String provider) { } @Override public void onProviderDisabled(String provider) { } }; }