package com.maciekjanusz.compassproject.navigation; import android.content.Context; import android.location.Location; import android.os.Bundle; import android.support.annotation.Nullable; 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; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.TimeUnit; import de.greenrobot.event.EventBus; /** * This class isolates the logic of location objects retrieval through GoogleApiClient. */ class LocationRetriever implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener { /** * Location request time interval - with fused API 5 sec is minimum */ private static final long REQUEST_INTERVAL_MILLIS = TimeUnit.SECONDS.toMillis(5); /** * GoogleApiClient instance for retrieving locations through fused API */ private GoogleApiClient googleApiClient; /** * LocationRequest object initialized within {@link #createLocationRequest()} */ private LocationRequest locationRequest; /** * LocationListener for returning location through its callback */ private final List<LocationListener> locationListeners = new CopyOnWriteArrayList<>(); /** * Last retrieved location. Can be null. */ @Nullable private volatile Location currentLocation; public LocationRetriever(Context context) { buildGoogleApiClient(context.getApplicationContext()); } /** * Sets up GoogleApiClient. Called in constructor {@link #LocationRetriever(Context)} * @param context Context for GoogleApiClient.Builder */ private synchronized void buildGoogleApiClient(final Context context) { googleApiClient = new GoogleApiClient.Builder(context) .addApi(LocationServices.API) .addConnectionCallbacks(this) .addOnConnectionFailedListener(this) .build(); } /** * This method initializes {@link #locationRequest} with {@link #REQUEST_INTERVAL_MILLIS} * as interval. */ private void createLocationRequest() { locationRequest = new LocationRequest(); locationRequest.setInterval(REQUEST_INTERVAL_MILLIS); locationRequest.setFastestInterval(REQUEST_INTERVAL_MILLIS); locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); } /** * Starts updating location with googleApiClient. */ private void startLocationUpdates() { LocationServices.FusedLocationApi.requestLocationUpdates( googleApiClient, locationRequest, this); } /** * Stops googleApiClient from updating location. */ private void stopLocationUpdates() { LocationServices.FusedLocationApi.removeLocationUpdates( googleApiClient, this); } /** * Call to start retrieving location */ public void startRetrievingLocation() { googleApiClient.connect(); } /** * Call to stop retrieving location */ public void stopRetrievingLocation() { if(googleApiClient.isConnected()) { stopLocationUpdates(); googleApiClient.disconnect(); } } @Override public void onConnected(Bundle bundle) { // when client connects, start location updates createLocationRequest(); startLocationUpdates(); } @Override public void onConnectionSuspended(int i) { } @Override public void onConnectionFailed(ConnectionResult connectionResult) { // forward connection result to activity EventBus.getDefault().post(connectionResult); } @Override public void onLocationChanged(Location location) { // set current location currentLocation = location; // notify listener for(LocationListener locationListener : locationListeners) { locationListener.onLocationChanged(location); } } /** * Getter for current location * @return current location. Might be null */ @Nullable public Location getCurrentLocation() { return currentLocation; } public void registerLocationListener(LocationListener locationListener) { locationListeners.add(locationListener); } public void unregisterLocationListener(LocationListener locationListener) { locationListeners.remove(locationListener); } }