Skip to content

Instantly share code, notes, and snippets.

@MehdiFal
Last active November 17, 2017 16:11
Show Gist options
  • Save MehdiFal/6ae11fd67473d488e659ea347e522945 to your computer and use it in GitHub Desktop.
Save MehdiFal/6ae11fd67473d488e659ea347e522945 to your computer and use it in GitHub Desktop.
import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageManager;
import android.location.Location;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import com.corelib.utils.Logger;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.GoogleApiClient.ConnectionCallbacks;
import com.google.android.gms.common.api.GoogleApiClient.OnConnectionFailedListener;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;
import java.util.Calendar;
import java.util.Date;
public class GeoLocService implements ConnectionCallbacks,
OnConnectionFailedListener,
LocationListener {
// The desired interval for location updates. Inexact. Updates may be more or less frequent.
private final static long UPDATE_INTERVAL_IN_MILLISECONDS = 1000;
//The fastest rate for active location updates. Exact Updates will never be more frequent than this value.
private final static long FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS = UPDATE_INTERVAL_IN_MILLISECONDS / 2;
private GoogleApiClient googleApiClient;
private LocationRequest locationRequest;
private LocationResponse locationResponse;
private Location currentLocation;
public GeoLocService (Context context, LocationResponse locationResponse) {
this.locationResponse = locationResponse;
googleApiClient = new GoogleApiClient.Builder (context)
.addConnectionCallbacks (this)
.addOnConnectionFailedListener (this)
.addApi (LocationServices.API)
.build ();
createLocationRequest ();
}
public void onStart () {
if (googleApiClient != null) {
googleApiClient.connect ();
}
}
// Within onPause(), we pause location updates, but leave the
// connection to GoogleApiClient intact. Here, we resume receiving
// location updates if the user has requested them.
public void onResume () {
if (googleApiClient != null && googleApiClient.isConnected ()) {
startLocationUpdates ();
}
}
// Stop location updates to save battery, but don't disconnect the GoogleApiClient object.
public void onPause () {
if (googleApiClient != null && googleApiClient.isConnected ()) {
stopLocationUpdates ();
}
}
public void disconnect () {
if (googleApiClient != null) {
if (googleApiClient.isConnected ()) {
stopLocationUpdates ();
}
googleApiClient.disconnect ();
}
}
protected void createLocationRequest() {
locationRequest = new LocationRequest();
// Sets the desired interval for active location updates. This interval is
// inexact. You may not receive updates at all if no location sources are available, or
// you may receive them slower than requested. You may also receive updates faster than
// requested if other applications are requesting location at a faster interval.
locationRequest.setInterval (UPDATE_INTERVAL_IN_MILLISECONDS);
// Sets the fastest rate for active location updates. This interval is exact, and your
// application will never receive updates faster than this value.
locationRequest.setFastestInterval (FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS);
locationRequest.setPriority (LocationRequest.PRIORITY_HIGH_ACCURACY);
}
// Requests location updates from the FusedLocationApi.
@SuppressLint("MissingPermission")
public void startLocationUpdates () {
Logger.info (GeoLocService.class.getSimpleName () + "-- startLocationUpdates", "Got into the startLocationUpdates");
LocationServices.FusedLocationApi.requestLocationUpdates (googleApiClient, locationRequest, this);
}
// Removes location updates from the FusedLocationApi.
// It is a good practice to remove location requests when the activity is in a paused or
// stopped state. Doing so helps battery performance and is especially
// recommended in applications that request frequent location updates.
public void stopLocationUpdates() {
Logger.info (GeoLocService.class.getSimpleName () + "-- stopLocationUpdates", "Got into the stopLocationUpdates");
LocationServices.FusedLocationApi.removeLocationUpdates(googleApiClient, this);
}
// Runs when a GoogleApiClient object successfully connects.
@SuppressLint ("MissingPermission")
@Override
public void onConnected(Bundle connectionHint) {
Logger.info (GeoLocService.class.getSimpleName () + "-- Success", "Connected to GoogleApiClient");
// If the initial location was never previously requested, we use
// FusedLocationApi.getLastLocation() to get it. If it was previously requested, we store
// its value in the Bundle and check for it in onCreate(). We
// do not request it again unless the user specifically requests location updates by pressing
// the Start Updates button.
// Because we cache the value of the initial location in the Bundle, it means that if the
// user launches the activity,
// moves to a new location, and then changes the device orientation, the original location
// is displayed as the activity is re-created.
if (currentLocation == null) {
currentLocation = LocationServices.FusedLocationApi.getLastLocation (googleApiClient);
sendUpdates ();
}
// If the user presses the Start Updates button before GoogleApiClient connects, we set
// mRequestingLocationUpdates to true (see startUpdatesButtonHandler()). Here, we check
// the value of mRequestingLocationUpdates and if it is true, we start location updates.
startLocationUpdates ();
}
private void sendUpdates () {
Logger.info (GeoLocService.class.getSimpleName () + "-- sendUpdates", "Got into the sendUpdates");
if (locationResponse != null && currentLocation != null) {
Logger.info (GeoLocService.class.getSimpleName () + "-- SendUpdates",
"Retrieved Loc : " + currentLocation.getLatitude () + " : " + currentLocation.getLongitude ()
);
locationResponse.onLocation (currentLocation);
}
}
// Callback that fires when the location changes.
@Override
public void onLocationChanged (Location location) {
double speed = calculateDistance (location, currentLocation);
currentLocation = location;
currentLocation.setSpeed ((float) speed);
lastUpdateTime = Calendar.getInstance ().getTime ();
Logger.info (GeoLocService.class.getSimpleName () + "-- OnLocChanged", "Got into the OnlocationChanged");
sendUpdates ();
}
@Override
public void onConnectionSuspended (int cause) {
// The connection to Google Play services was lost for some reason. We call connect() to
// attempt to re-establish the connection.
Logger.error (GeoLocService.class.getSimpleName () + "-- Error", "Connection suspended");
googleApiClient.connect ();
}
@Override
public void onConnectionFailed (@NonNull ConnectionResult result) {
// Refer to the javadoc for ConnectionResult to see what error codes might be returned in onConnectionFailed.
Logger.error (GeoLocService.class.getSimpleName () + "-- Error", "Connection failed: ConnectionResult.getErrorCode() = " + result.getErrorCode());
if (locationResponse != null) {
locationResponse.onFailure (result.getErrorCode ());
}
}
// TODO : IMPORTANT !!!! make it blocking UI Rendering.......
public static boolean checkLocationPerms (Activity context) {
if (ActivityCompat.checkSelfPermission (context, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
&& ActivityCompat.checkSelfPermission (context, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions (
context,
new String [] {
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.ACCESS_NETWORK_STATE
},
1000
);
return false;
}
return true;
}
public GoogleApiClient getGoogleApiClient () {
return googleApiClient;
}
public interface LocationResponse {
void onLocation (Location location);
void onFailure (int errorCode);
}
}
import android.location.Location;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.view.View;
import android.widget.TextView;
import com.corelib.services.GeoLocService;
import com.corelib.utils.Json;
import com.corelib.utils.Lang;
import com.corelib.utils.Logger;
import com.corelib.workers.LocalWorker;
import com.corelib.workers.callbacks.impls.SimpleLocalWorkerCallback;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import java.io.IOException;
public abstract class LocationActivity extends BaseActivity {
protected final static String Latitude = "latitude";
protected final static String Longitude = "longitude";
protected final static String LastLocation = "lastLocation";
private GeoLocService locationService;
protected Location lastPosition;
@Override
protected void onCreate (Bundle savedInstanceState) {
super.onCreate (savedInstanceState);
if (enableLocTrack ()) {
if (GeoLocService.checkLocationPerms (this)) {
initLocService ();
}
initLastKnownLocation ();
}
}
@Override
protected void onStart () {
super.onStart ();
if (enableLocTrack ()) {
if (locationService != null) {
locationService.onStart ();
}
}
}
@Override
public void onRequestPermissionsResult (int requestCode, @NonNull String [] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult (requestCode, permissions, grantResults);
if (requestCode == PermReqCode) {
if (enableLocTrack ()) {
if (GeoLocService.checkLocationPerms (this)) {
initLocService ();
locationService.onStart ();
}
}
}
}
@Override
protected void onResume () {
super.onResume ();
if (enableLocTrack ()) {
if (locationService != null) {
locationService.onResume ();
}
initLastKnownLocation ();
}
}
@Override
protected void onPause () {
super.onPause ();
if (enableLocTrack ()) {
if (locationService != null) {
locationService.onPause ();
}
persistLastKnownLocation ();
}
}
@Override
protected void onStop () {
if (enableLocTrack ()) {
if (locationService != null) {
locationService.disconnect ();
}
}
super.onStop ();
}
private void initLastKnownLocation () {
localWorker.get (
LastLocation,
LocalWorker.RootAppPrefs,
LocalWorker.Repo.Preferences,
LocalWorker.Type.Json,
new SimpleLocalWorkerCallback () {
@Override
public void onUISuccess (Object response) {
createLocation ((JsonNode)response);
onLocationSuccess (lastPosition, false);
}
}
);
}
protected void fetchLastKnownLocation () {
try {
JsonNode localLoc = (JsonNode)localWorker.get (LastLocation, LocalWorker.RootAppPrefs, LocalWorker.Repo.Preferences);
createLocation (localLoc);
} catch (IOException e) {
Logger.error (LocationActivity.class.getSimpleName () + " --> getLastKnownLocation", e);
}
}
private void createLocation (JsonNode response) {
lastPosition = new Location (Lang.EMPTY);
if (response == null) {
lastPosition.setLatitude (0);
lastPosition.setLongitude (0);
return;
}
lastPosition.setLatitude (response.get ("latitude").asDouble (0));
lastPosition.setLongitude (response.get ("longitude").asDouble (0));
}
private void persistLastKnownLocation () {
if (lastPosition == null) {
lastPosition = new Location (Lang.EMPTY);
lastPosition.setLatitude (0);
lastPosition.setLongitude (0);
}
ObjectNode node = Json.createObject ();
node.put (Latitude, lastPosition.getLatitude ());
node.put (Longitude, lastPosition.getLongitude ());
// store in SharedPrefs
localWorker.post (
LastLocation,
LocalWorker.RootAppPrefs,
LocalWorker.Repo.Preferences,
LocalWorker.Type.Json,
node,
new SimpleLocalWorkerCallback ()
);
}
private void initLocService () {
GeoLocService.LocationResponse response = new GeoLocService.LocationResponse () {
@Override
public void onLocation (final Location location) {
lastPosition = location;
onLocationSuccess (location, true);
}
@Override
public void onFailure (int errorCode) {
onLocationFailure (errorCode);
}
};
locationService = new GeoLocService (getApplicationContext (), response);
}
protected void stopFetchingLocations () {
if (locationService != null) {
locationService.stopLocationUpdates ();
locationService.disconnect ();
}
}
protected GeoLocService getLocationService () {
return locationService;
}
public Location getLastPosition () {
return lastPosition;
}
protected abstract void onLocationSuccess (Location location, boolean gps);
protected abstract void onLocationFailure (int errorCode);
protected abstract boolean enableLocTrack ();
protected abstract boolean requestLocPerm ();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment