Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save ishmaelmakitla/40efa5a37849299dde64d6a397cbbb84 to your computer and use it in GitHub Desktop.
Save ishmaelmakitla/40efa5a37849299dde64d6a397cbbb84 to your computer and use it in GitHub Desktop.
package <your package>;
import java.util.ArrayList;
import org.json.JSONException;
import org.json.JSONObject;
import za.co.smartcitizens.trafficlights.spotter.models.LastKnownUserPosition;
import za.co.smartcitizens.trafficlights.spotter.models.TrafficLightIntersectionGeofence;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.location.Location;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.util.Log;
import android.widget.Toast;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;
/**
* This utility class is used to provide functionality to detect distance movement for the user so as to automatically refresh the geofences
* closest to the user. This provides a fairly good example of how to use LocationListener in a utility class (not an Activity).
* @author Ishmael Makitla
http://ishLema.co.za
*
*/
public class TrafficLightSpotterUserLocationUtils implements LocationListener{
private static final String TAG = TrafficLightSpotterUserLocationUtils.class.getSimpleName();
private static final String SHARED_PREFERENCES_LAST_LOCATION_KEY = "lastLocation";
private static final int SIGNIFICANT_DISPLACEMENT_THRESHOLD = 5; //5 km distance
private Context context;
private GoogleApiClient googleApiClient;
private Gson gson;
private SharedPreferences prefs;
private GeofenceRefreshRequestListener geofenceRefreshRequestListener;
private static TrafficLightSpotterUserLocationUtils INSTANCE;
public static TrafficLightSpotterUserLocationUtils getInstance(){
if(INSTANCE == null){ INSTANCE = new TrafficLightSpotterUserLocationUtils(); }
return INSTANCE;
}
public void init(Context ctx, GoogleApiClient connectedGoogleAPIClient, GeofenceRefreshRequestListener refreshRequestListener){
this.context = ctx;
this.googleApiClient = connectedGoogleAPIClient;
this.geofenceRefreshRequestListener = refreshRequestListener;
prefs = PreferenceManager.getDefaultSharedPreferences(context);
requestLocationUpdates();
}
/**
* Helper method to connect the Google API Client
*/
private void requestLocationUpdates() {
Log.i(TAG,"requestLocationUpdates");
try{
LocationRequest locationRequest = LocationRequest.create();
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
locationRequest.setInterval(180000); // update every (3) minutes
LocationServices.FusedLocationApi.requestLocationUpdates(googleApiClient, locationRequest, this);
}
catch(Exception e){
Log.e(TAG, "Error at requestLocationUpdates. ", e);
}
}
@Override
public void onLocationChanged(Location location) {
if(location == null){ return; }
Log.i(TAG, "onLocationChanged. Lat "+location.getLatitude()+" , Lon: "+location.getLongitude());
//retrieve last-known location (if it does not exist, then this is the first time we get location updates
processLocationChange(location);
}
/**
* This method measures the distance between the last known location of the user and the current on.
* It does this to calculate how far the user has moved so that it can update the geofences it setups.
*
* @param currentLocation - the most recent user location
*/
private void processLocationChange(Location currentLocation){
if(currentLocation == null){return;}
LastKnownUserPosition userPreviousPosition = getLastKnownUserLocation();
if(userPreviousPosition == null){
//Cannot compare, set this as current location
setNewUserPosition(currentLocation);
return;
}
float[] results = new float[3];
Location.distanceBetween(currentLocation.getLatitude(), currentLocation.getLongitude(), userPreviousPosition.getLatitude(), userPreviousPosition.getLongitude(), results);
float distance = (results.length > 0 ? results[0]: 0);
if( (distance/1000) >= SIGNIFICANT_DISPLACEMENT_THRESHOLD){
//the user has moved quite a distance
Log.i(TAG, "User has moved "+(distance/1000)+"km. It Is Necessary To Refreshe Geofences.");
//set as new location
setNewUserPosition(currentLocation);
//notify the listener
if(geofenceRefreshRequestListener != null){ geofenceRefreshRequestListener.onGeofenceRefreshRequired(currentLocation); }
}
else{
Log.i(TAG, "Distance "+(distance/1000)+"km Too Small To Refreshe Geofence. Ignore");
}
}
/**
*
* @return
*/
private LastKnownUserPosition getLastKnownUserLocation(){
LastKnownUserPosition lastKnownLocation = null;
try{
String lastPositionString = prefs.getString(SHARED_PREFERENCES_LAST_LOCATION_KEY, null);
if(lastPositionString !=null && !lastPositionString.trim().isEmpty()){
lastKnownLocation = LastKnownUserPosition.asLastKnownUserPosition(lastPositionString);
}
}
catch(Exception e){
Log.e(TAG, "Error at getLastKnownUserLocation. ", e);
}
return lastKnownLocation;
}
/**
* Record the current location. This is only done when the displacement is above threshold
* @param newLocation
*/
private void setNewUserPosition(final Location newLocation){
LastKnownUserPosition currentPosition = new LastKnownUserPosition(newLocation.getLatitude(), newLocation.getLongitude());
try{
Editor editor = prefs.edit();
editor.putString(SHARED_PREFERENCES_LAST_LOCATION_KEY, currentPosition.toString());
editor.apply();
}
catch(Exception e){
Log.e(TAG, "Error at setNewUserPosition. ", e);
}
try {
//do something...in my case I was updating the list of users who should receive alerts;
}
catch (JSONException jse) {
Log.e(TAG, "Error While Updating Alert Subscription. ", jse);
}
catch(Exception e){
Log.e(TAG, "Error While Updating Alert Subscription. ", e);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment