package org.droidplanner.services.android.impl.core.gcs.location;
import android.content.Context;
import android.location.Location;
import android.os.Handler;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.common.api.Api;
import com.google.android.gms.location.LocationAvailability;
import com.google.android.gms.location.LocationCallback;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationResult;
import com.google.android.gms.location.LocationServices;
import com.o3dr.services.android.lib.util.googleApi.GoogleApiClientManager;
import com.o3dr.services.android.lib.util.googleApi.GoogleApiClientManager.GoogleApiClientTask;
import org.droidplanner.services.android.impl.core.gcs.follow.LocationRelay;
import org.droidplanner.services.android.impl.core.gcs.location.Location.LocationFinder;
import org.droidplanner.services.android.impl.core.gcs.location.Location.LocationReceiver;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import timber.log.Timber;
/**
* Feeds Location Data from Android's FusedLocation LocationProvider
*/
public class FusedLocation extends LocationCallback implements LocationFinder, GoogleApiClientManager.ManagerListener {
private static final String TAG = FusedLocation.class.getSimpleName();
private static final long MIN_TIME_MS = 16;
private static final float MIN_DISTANCE_M = 0.0f;
private final static Api<? extends Api.ApiOptions.NotRequiredOptions>[] apisList = new Api[]{LocationServices.API};
private final GoogleApiClientManager gApiMgr;
private final GoogleApiClientTask requestLocationUpdate;
private boolean mLocationUpdatesEnabled = false;
private final GoogleApiClientTask removeLocationUpdate = new GoogleApiClientTask() {
@Override
protected void doRun() {
LocationServices.FusedLocationApi.removeLocationUpdates(getGoogleApiClient(),
FusedLocation.this);
}
};
private final Map<String, LocationReceiver> receivers = new ConcurrentHashMap<>();
private final LocationRelay locationRelay;
private final Context context;
public FusedLocation(Context context, final Handler handler) {
this(context, handler, LocationRequest.PRIORITY_HIGH_ACCURACY, MIN_TIME_MS, MIN_TIME_MS, MIN_DISTANCE_M);
}
public FusedLocation(Context context, final Handler handler, final int locationRequestPriority,
final long interval, final long fastestInterval, final float smallestDisplacement) {
this.context = context;
this.locationRelay = new LocationRelay();
requestLocationUpdate = new GoogleApiClientTask() {
@Override
protected void doRun() {
final LocationRequest locationRequest = LocationRequest.create();
locationRequest.setPriority(locationRequestPriority);
locationRequest.setInterval(interval);
locationRequest.setFastestInterval(fastestInterval);
locationRequest.setSmallestDisplacement(smallestDisplacement);
LocationServices.FusedLocationApi.requestLocationUpdates(getGoogleApiClient(),
locationRequest, FusedLocation.this, handler.getLooper());
}
};
gApiMgr = new GoogleApiClientManager(context, handler, apisList);
gApiMgr.setManagerListener(this);
}
@Override
public void enableLocationUpdates(String tag, LocationReceiver receiver) {
receivers.put(tag, receiver);
if(!mLocationUpdatesEnabled) {
gApiMgr.start();
locationRelay.onFollowStart();
mLocationUpdatesEnabled = true;
}
}
@Override
public void disableLocationUpdates(String tag) {
if(mLocationUpdatesEnabled) {
gApiMgr.addTask(removeLocationUpdate);
gApiMgr.stopSafely();
mLocationUpdatesEnabled = false;
}
receivers.remove(tag);
}
@Override
public void onLocationAvailability(LocationAvailability locationAvailability) {
super.onLocationAvailability(locationAvailability);
//TODO: notify the location listener.
}
@Override
public void onLocationResult(LocationResult result) {
final Location androidLocation = result.getLastLocation();
if (androidLocation == null)
return;
org.droidplanner.services.android.impl.core.gcs.location.Location gcsLocation =
locationRelay.toGcsLocation(androidLocation);
if(gcsLocation == null)
return;
Timber.d("Location Lat/Long: " + LocationRelay.getLatLongFromLocation(androidLocation));
notifyLocationUpdate(gcsLocation);
}
private void notifyLocationUpdate(org.droidplanner.services.android.impl.core.gcs.location.Location location) {
if (receivers.isEmpty()) {
Timber.d(TAG, "notifyLocationUpdate(): No receivers");
return;
}
for (LocationReceiver receiver : receivers.values()) {
receiver.onLocationUpdate(location);
}
}
@Override
public void onGoogleApiConnectionError(ConnectionResult result) {
notifyLocationUnavailable();
GooglePlayServicesUtil.showErrorNotification(result.getErrorCode(), this.context);
}
@Override
public void onUnavailableGooglePlayServices(int status) {
notifyLocationUnavailable();
GooglePlayServicesUtil.showErrorNotification(status, this.context);
}
private void notifyLocationUnavailable() {
if (receivers.isEmpty())
return;
for (LocationReceiver listener : receivers.values()) {
listener.onLocationUnavailable();
}
}
@Override
public void onManagerStarted() {
gApiMgr.addTask(requestLocationUpdate);
}
@Override
public void onManagerStopped() {
}
}