package net.atomcode.bearing.location;
import android.content.Context;
import android.location.Location;
import android.os.Handler;
import android.os.Looper;
import net.atomcode.bearing.Bearing;
import net.atomcode.bearing.BearingTask;
import net.atomcode.bearing.location.provider.GMSLocationProvider;
import net.atomcode.bearing.location.provider.LegacyLocationProvider;
import java.util.Timer;
import java.util.TimerTask;
/**
* Base location task for acquiring locations
*/
public abstract class LocationTask implements BearingTask
{
/**
* Use a cached location when a timeout occurs
*/
public static final int FALLBACK_CACHE = 0x1;
protected boolean isUsingLegacyServices;
protected LocationProvider locationProvider;
protected LocationProviderRequest request;
protected LocationListener listener;
protected int fallback = FALLBACK_NONE; // No fallback by default
protected long timeout = 0; // > 0 means no timeout
protected boolean running = false;
protected String taskId;
public LocationTask(Context context)
{
isUsingLegacyServices = !Bearing.isLocationServicesAvailable(context);
if (isUsingLegacyServices)
{
locationProvider = LegacyLocationProvider.getInstance();
}
else
{
locationProvider = GMSLocationProvider.getInstance();
}
locationProvider.create(context);
request = new LocationProviderRequest();
}
@Override
public BearingTask start()
{
running = true;
if (timeout > 0)
{
new Timer().schedule(new TimerTask()
{
@Override
public void run()
{
if (isRunning())
{
LocationTask.this.cancel();
if (listener != null)
{
listener.onTimeout();
handleTimeoutFallback();
}
}
}
}, timeout);
}
return this;
}
@Override
public void cancel()
{
running = false;
if (taskId != null)
{
locationProvider.cancelUpdates(taskId);
}
}
/**
* Listen for location updates
*/
public LocationTask listen(LocationListener listener)
{
this.listener = listener;
return this;
}
@Override
public boolean isRunning()
{
return running;
}
/*
* ==============================================
* LOCATION TASK API
* ==============================================
*/
/**
* Set the accuracy of the location request(s)
* @param accuracy The accuracy to which the location should be gathered
*/
public LocationTask accuracy(Accuracy accuracy)
{
request.accuracy = accuracy;
return this;
}
/**
* Whether to use a cached location if available,
* and how old does the location need to be to be treated as valid
* @param use Whether to use the cached location
* @param expiry How old does a cached location have to be to be invalid?
*/
public LocationTask cache(boolean use, long expiry)
{
request.useCache = use;
request.cacheExpiry = expiry;
return this;
}
/**
* Fallback for if the timeout is reached
*/
@Override
public LocationTask fallback(int fallback, long timeout)
{
this.fallback = fallback;
this.timeout = timeout;
return this;
}
/*
* ==============================================
* INTERNAL METHODS
* ==============================================
*/
/**
* Handle the timeout fallback here.
* listener is non-null at this point.
*/
private void handleTimeoutFallback()
{
new Handler(Looper.getMainLooper()).post(new Runnable()
{
@Override public void run()
{
if (fallback == FALLBACK_CACHE)
{
Location cachedLocation = locationProvider.getLastKnownLocation(request);
if (cachedLocation != null)
{
listener.onUpdate(cachedLocation);
}
else
{
listener.onFailure();
}
}
}
});
}
}