package system; import java.util.ArrayList; import java.util.List; import listeners.eventManagerListeners.LocationEventListener; import system.StepManager.OnStepListener; import util.Log; import android.content.Context; import android.location.Criteria; import android.location.Location; import android.location.LocationListener; import android.location.LocationManager; import android.os.Bundle; public abstract class SimpleLocationManager { private static final String LOG_TAG = "SimpleLocationManager"; private static final long MIN_MS_BEFOR_UPDATE = 200; private static final float MIN_DIST_FOR_UPDATE = 0f; private static boolean stepDetectionEnabled = true; private static int numberOfSimulatedStepsInSameDirection = 4; /** * This is needed to use step detection only if the accuracy from the other * location providers is not to bad */ private static float minimumAverageAccuracy = 200; private static SimpleLocationManager instance; private final Context context; private LocationListener gpslistener; private ArrayList<LocationListener> myListeners; private OnStepListener stepListener; private StepManager stepManager; public SimpleLocationManager(Context context) { this.context = context; } public static float getMinimumAverageAccuracy() { return minimumAverageAccuracy; } public static int getNumberOfSimulatedStepsInSameDirection() { return numberOfSimulatedStepsInSameDirection; } public static void setStepDetectionEnabled(boolean stepDetectionEnabled) { SimpleLocationManager.stepDetectionEnabled = stepDetectionEnabled; } public static boolean isStepDetectionEnabled() { return stepDetectionEnabled; } public static void setMinimumAverageAccuracy(float minimumAverageAccuracy) { SimpleLocationManager.minimumAverageAccuracy = minimumAverageAccuracy; } public static void setNumberOfSimulatedStepsInSameDirection( int numberOfSimulatedStepsInSameDirection) { SimpleLocationManager.numberOfSimulatedStepsInSameDirection = numberOfSimulatedStepsInSameDirection; } public static SimpleLocationManager getInstance(Context context) { if (instance == null) { instance = new ConcreteSimpleLocationManager(context); } return instance; } public static boolean resetInstance() { if (instance == null) { return false; } instance.pauseLocationManagerUpdates(); instance = null; return true; } private LocationListener initListener() { return new LocationListener() { @Override public void onStatusChanged(String provider, int status, Bundle extras) { for (int i = 0; i < myListeners.size(); i++) { myListeners.get(i) .onStatusChanged(provider, status, extras); } } @Override public void onProviderEnabled(String provider) { for (int i = 0; i < myListeners.size(); i++) { myListeners.get(i).onProviderEnabled(provider); } } @Override public void onProviderDisabled(String provider) { for (int i = 0; i < myListeners.size(); i++) { myListeners.get(i).onProviderDisabled(provider); } } @Override public void onLocationChanged(Location location) { onLocationEventFromGPS(location, myListeners); } }; } /** * This method buffers the location and passes the buffered location down to * the locationListeners * * @param location * @param listenersToInform */ public abstract void onLocationEventFromGPS(Location location, ArrayList<LocationListener> listenersToInform); /** * will pause updates from the {@link LocationManager} to the * {@link SimpleLocationManager} */ public boolean pauseLocationManagerUpdates() { // its important to use instance here and not getInstance()! if (gpslistener != null) { Log.i(LOG_TAG, "Pausing position updates!"); getLocationManager().removeUpdates(gpslistener); gpslistener = null; } if (stepListener != null) { Log.i(LOG_TAG, "Pausing step updates!"); stepManager.unRegisterStepListener(stepListener); stepListener = null; stepManager = null; return true; } return false; } private LocationManager getLocationManager() { return (LocationManager) context .getSystemService(Context.LOCATION_SERVICE); } /** * @return null if there is no current location measured yet */ public abstract Location getCurrentBUfferedLocation(); /** * @param accuracy * see the {@link Criteria#setAccuracy(int)} method for possible * parameter types * @return */ public Location getCurrentLocation(int accuracy) { Location l = getCurrentBUfferedLocation(); if (l != null) { return l; } if (context != null) { try { LocationManager lm = getLocationManager(); Criteria criteria = new Criteria(); criteria.setAccuracy(accuracy); return lm.getLastKnownLocation(lm.getBestProvider(criteria, true)); } catch (Exception e) { Log.e(LOG_TAG, "Could not receive the current location"); e.printStackTrace(); return null; } } Log.e(LOG_TAG, "The passed activity was null!"); return null; } /** * This method will try to get the most accurate position currently * available. This includes also the last known position of the device if no * current position sources can't be accessed so the returned position might * be outdated <br> * <br> * If you need permanent location updates better create a * {@link LocationEventListener} and register it at * {@link EventManager#addOnLocationChangedAction(LocationEventListener)} * instead of calling this method here frequently. * * @return */ public Location getCurrentLocation() { Location l = getCurrentBUfferedLocation(); if (l != null) { return l; } Log.w(LOG_TAG, "buffered current location object was null, " + "will use the one from the android LocationManager!"); l = getCurrentLocation(Criteria.ACCURACY_FINE); if (l == null) { Log.e(LOG_TAG, "Fine accuracy position could not be detected! Will use coarse location."); l = getCurrentLocation(Criteria.ACCURACY_COARSE); if (l == null) { Log.e(LOG_TAG, "Coarse accuracy position could not be detected! Last try.."); try { LocationManager lm = getLocationManager(); Log.d(LOG_TAG, "Searching through " + lm.getAllProviders().size() + " location providers"); for (int i = lm.getAllProviders().size() - 1; i >= 0; i--) { l = lm.getLastKnownLocation(lm.getAllProviders().get(i)); if (l != null) { break; } } } catch (Exception e) { } } } Log.d(LOG_TAG, "current position=" + l); return l; } public String findBestLocationProvider() { LocationManager locationManager = getLocationManager(); if (locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) { Log.i(LOG_TAG, "GPS was enabled so this method should " + "come to the conclusion to use GPS as " + "the location source!"); } /* * To register the EventManager in the LocationManager a Criteria object * has to be created and as the primary attribute accuracy should be * used to get as accurate position data as possible: */ Criteria criteria = new Criteria(); criteria.setAccuracy(Criteria.ACCURACY_FINE); String provider = locationManager.getBestProvider(criteria, true); if (provider == null) { Log.w(LOG_TAG, "No location-provider with the " + "specified requierments found.. Trying to find " + "an alternative."); List<String> providerList = locationManager.getProviders(true); for (String possibleProvider : providerList) { if (possibleProvider != null) { Log.w(LOG_TAG, "Location-provider alternative " + "found: " + possibleProvider); provider = possibleProvider; } } if (provider == null) { Log.w(LOG_TAG, "No location-provider alternative " + "found!"); } } if (!provider.equals(LocationManager.GPS_PROVIDER)) { Log.w(LOG_TAG, "The best location provider was not " + LocationManager.GPS_PROVIDER + ", it was " + provider); } return provider; } public boolean requestLocationUpdates(String provider, long minMsBeforUpdate, float minDistForUpdate, LocationListener locationListener) { registerSimpleEventManagerAsListenerIfNotDoneJet(provider, minMsBeforUpdate, minDistForUpdate); return addToListeners(locationListener); } private void registerSimpleEventManagerAsListenerIfNotDoneJet( String provider, long minMsBeforUpdate, float minDistForUpdate) { if (gpslistener == null) { gpslistener = initListener(); Log.i(LOG_TAG, "Created location listener and now registering for updates.."); Log.i(LOG_TAG, " > provider=" + provider); Log.i(LOG_TAG, " > minMsBeforUpdate=" + minMsBeforUpdate); Log.i(LOG_TAG, " > minDistForUpdate=" + minDistForUpdate); getLocationManager().requestLocationUpdates(provider, minMsBeforUpdate, minDistForUpdate, gpslistener); } if (stepListener == null) { stepListener = new OnStepListener() { @Override public void onStep(double compassAngle, double steplength) { if (!stepDetectionEnabled) { return; } Log.d(LOG_TAG, "Step detected"); Log.d(LOG_TAG, " > compassAngle=" + compassAngle); Log.d(LOG_TAG, " > distance=" + steplength); Location location = getCurrentBUfferedLocation(); if (location != null) { Log.i(LOG_TAG, "location.getAccuracy()=" + location.getAccuracy()); } if (location != null) { if (location.getAccuracy() < minimumAverageAccuracy) { for (int i = 0; i < numberOfSimulatedStepsInSameDirection; i++) { location = StepManager .newLocationOneStepFurther(location, steplength, compassAngle); onLocationEventFromSteps(location, myListeners); } } else { Log.w(LOG_TAG, "Location accuracy was to low, wont use step"); } } else { Log.w(LOG_TAG, "Current location was unknown, cant do steps"); } } }; if (stepManager == null) { stepManager = new StepManager(); } stepManager.registerStepListener(context, stepListener); Log.i(LOG_TAG, "Step listener registered"); } } public StepManager getStepManager() { return stepManager; } public abstract void onLocationEventFromSteps(Location location, ArrayList<LocationListener> listenersToInform); public boolean requestLocationUpdates(LocationListener locationListener) { return requestLocationUpdates(findBestLocationProvider(), MIN_MS_BEFOR_UPDATE, MIN_DIST_FOR_UPDATE, locationListener); } private boolean addToListeners(LocationListener locationListener) { if (myListeners == null) { myListeners = new ArrayList<LocationListener>(); } if (!myListeners.contains(locationListener)) { Log.i(LOG_TAG, "Adding listener " + locationListener + " to list"); myListeners.add(locationListener); return true; } return false; } /** * @param maxNrOfBufferedLocations * the nr of locations in the location buffer. the lower the * number the faster it will move to the newes position but it * will also become more fragile to outliers in the measurements. * the default value is 15 */ public abstract void setMaxNrOfBufferedLocations( int maxNrOfBufferedLocations); }