Skip to content

Instantly share code, notes, and snippets.

@sydneyitguy
Created July 10, 2016 07:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sydneyitguy/50cc6bba66a60ff0404875803a87e58f to your computer and use it in GitHub Desktop.
Save sydneyitguy/50cc6bba66a60ff0404875803a87e58f to your computer and use it in GitHub Desktop.
Abstract class to extend for Google Play Fused Location Service
import android.Manifest;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.location.Location;
import android.location.LocationListener;
import android.os.Bundle;
import android.provider.Settings;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AlertDialog;
import android.util.Log;
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.LocationRequest;
import com.google.android.gms.location.LocationServices;
/**
* Created by seb on 7/8/16.
*/
public abstract class LocationActivity extends BaseActivity implements ConnectionCallbacks, OnConnectionFailedListener, LocationListener {
protected static final String TAG = "LocationActivity";
// The desired interval for location updates. Inexact. Updates may be more or less frequent.
public static final long UPDATE_INTERVAL_IN_MILLISECONDS = 10000; // 10s
// The fastest rate for active location updates. Exact. Updates will never be more frequent than this value.
public static final long FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS = 3000; // 3s
// Keys for storing activity state in the Bundle.
private final static String REQUESTING_LOCATION_UPDATES_KEY = "requesting-location-updates-key";
private final static String LOCATION_KEY = "location-key";
private final static String LAST_UPDATED_TIME_STRING_KEY = "last-updated-time-string-key";
// Provides the entry point to Google Play services.
private GoogleApiClient mGoogleApiClient;
// Stores parameters for requests to the FusedLocationProviderApi.
private LocationRequest mLocationRequest;
// Represents a geographical location.
private Location mCurrentLocation;
/**
* Tracks the status of the location updates request.
*/
private Boolean isRequestingLocationUpdates;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Update values using data stored in the Bundle.
updateValuesFromBundle(savedInstanceState);
// Kick off the process of building a GoogleApiClient and requesting the LocationServices API.
buildGoogleApiClient();
isRequestingLocationUpdates = true;
startLocationUpdates();
}
@Override
protected void onStart() {
super.onStart();
mGoogleApiClient.connect();
}
@Override
public void onResume() {
super.onResume();
// Within {@code onPause()}, we pause location updates, but leave the
// connection to GoogleApiClient intact. Here, we resume receiving
// location updates if the user has requested them.
if (mGoogleApiClient.isConnected() && isRequestingLocationUpdates) {
startLocationUpdates();
}
}
@Override
protected void onPause() {
super.onPause();
// Stop location updates to save battery, but don't disconnect the GoogleApiClient object.
if (mGoogleApiClient.isConnected()) {
stopLocationUpdates();
}
}
@Override
protected void onStop() {
mGoogleApiClient.disconnect();
super.onStop();
}
/**
* Updates fields based on data stored in the bundle.
*
* @param savedInstanceState The activity state saved in the Bundle.
*/
private void updateValuesFromBundle(Bundle savedInstanceState) {
Log.d(TAG, "Updating values from bundle");
if (savedInstanceState != null) {
// Update the value of isRequestingLocationUpdates from the Bundle, and make sure that
// the Start Updates and Stop Updates buttons are correctly enabled or disabled.
if (savedInstanceState.keySet().contains(REQUESTING_LOCATION_UPDATES_KEY)) {
isRequestingLocationUpdates = savedInstanceState.getBoolean(
REQUESTING_LOCATION_UPDATES_KEY);
}
// Update the value of mCurrentLocation from the Bundle and update the UI to show the
// correct latitude and longitude.
if (savedInstanceState.keySet().contains(LOCATION_KEY)) {
// Since LOCATION_KEY was found in the Bundle, we can be sure that mCurrentLocation
// is not null.
mCurrentLocation = savedInstanceState.getParcelable(LOCATION_KEY);
}
updateUserLocation();
}
}
/**
* Builds a GoogleApiClient. Uses the {@code #addApi} method to request the
* LocationServices API.
*/
private synchronized void buildGoogleApiClient() {
Log.i(TAG, "Building GoogleApiClient");
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
createLocationRequest();
}
/**
* Sets up the location request. Android has two location request settings:
* {@code ACCESS_COARSE_LOCATION} and {@code ACCESS_FINE_LOCATION}. These settings control
* the accuracy of the current location. This sample uses ACCESS_FINE_LOCATION, as defined in
* the AndroidManifest.xml.
*
* When the ACCESS_FINE_LOCATION setting is specified, combined with a fast update
* interval (5 seconds), the Fused Location Provider API returns location updates that are
* accurate to within a few feet.
*
* These settings are appropriate for mapping applications that show real-time location
* updates.
*/
private void createLocationRequest() {
mLocationRequest = 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.
mLocationRequest.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.
mLocationRequest.setFastestInterval(FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS);
mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY); // PRIORITY_HIGH_ACCURACY?
}
/**
* Requests location updates from the FusedLocationApi.
*/
private void startLocationUpdates() {
// The final argument to {@code requestLocationUpdates()} is a LocationListener
// (http://developer.android.com/reference/com/google/android/gms/location/LocationListener.html).
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
showAlert();
return;
}
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, (com.google.android.gms.location.LocationListener) this);
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
stopLocationUpdates();
startLocationUpdates();
}
/**
* Updates the latitude, the longitude, and the last location time in the UI.
*/
private void updateUserLocation() {
Log.i(TAG, "User location has changed to [" + mCurrentLocation.getLatitude() + "," + mCurrentLocation.getLongitude() + "]");
// TODO: Do stuff on location updates
}
/**
* Removes location updates from the FusedLocationApi.
*/
private void stopLocationUpdates() {
// 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.
// The final argument to {@code requestLocationUpdates()} is a LocationListener
// (http://developer.android.com/reference/com/google/android/gms/location/LocationListener.html).
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, (com.google.android.gms.location.LocationListener) this);
}
/**
* Runs when a GoogleApiClient object successfully connects.
*/
@Override
public void onConnected(Bundle connectionHint) {
Log.i(TAG, "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 (mCurrentLocation == null) {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
showAlert();
return;
}
mCurrentLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
updateUserLocation();
}
// If the user presses the Start Updates button before GoogleApiClient connects, we set
// isRequestingLocationUpdates to true (see startUpdatesButtonHandler()). Here, we check
// the value of isRequestingLocationUpdates and if it is true, we start location updates.
if (isRequestingLocationUpdates) {
startLocationUpdates();
}
}
/**
* Callback that fires when the location changes.
*/
@Override
public void onLocationChanged(Location location) {
mCurrentLocation = location;
updateUserLocation();
}
@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.
Log.i(TAG, "Connection suspended");
mGoogleApiClient.connect();
}
@Override
public void onConnectionFailed(ConnectionResult result) {
// Refer to the javadoc for ConnectionResult to see what error codes might be returned in
// onConnectionFailed.
Log.i(TAG, "Connection failed: ConnectionResult.getErrorCode() = " + result.getErrorCode());
}
/**
* Stores activity data in the Bundle.
*/
@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
savedInstanceState.putBoolean(REQUESTING_LOCATION_UPDATES_KEY, isRequestingLocationUpdates);
savedInstanceState.putParcelable(LOCATION_KEY, mCurrentLocation);
super.onSaveInstanceState(savedInstanceState);
}
private void showAlert() {
final AlertDialog.Builder dialog = new AlertDialog.Builder(this);
dialog.setTitle("Enable Location")
.setMessage("Your Locations Settings is set to 'Off'.\nPlease Enable Location to " +
"use this app")
.setPositiveButton("Location Settings", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface paramDialogInterface, int paramInt) {
Intent myIntent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
startActivity(myIntent);
}
})
.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface paramDialogInterface, int paramInt) {
}
});
dialog.show();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment