package org.commcare.utils;
import android.Manifest;
import android.app.Activity;
import android.content.Context;
import android.content.DialogInterface;
import android.content.pm.PackageManager;
import android.location.Location;
import android.location.LocationManager;
import android.support.v4.content.ContextCompat;
import org.commcare.activities.CommCareActivity;
import org.commcare.dalvik.R;
import org.commcare.views.dialogs.StandardAlertDialog;
import org.javarosa.core.model.data.GeoPointData;
import org.javarosa.core.model.data.UncastData;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* Static functions for dealing with GPS data, specifically Location and LocationManager objects.
*
* @author jschweers
*/
public class GeoUtils {
// Good enough accuracy to stop pinging the GPS altogether
public static final double DEFAULT_GOOD_ACCURACY = 5;
public static final double AUTO_CAPTURE_GOOD_ACCURACY = 10;
// Good enough accuracy to ask user if they want to record
public static final double DEFAULT_ACCEPTABLE_ACCURACY = 1600;
// For passive collection, milliseconds to wait for GPS before giving up
public static final int AUTO_CAPTURE_MAX_WAIT_IN_MINUTES = 2;
public static final String ACTION_CHECK_GPS_ENABLED = "org.commcare.utils.GeoUtils.check";
/**
* Format location in a string for user display.
*
* @return String in format "<latitude> <longitude> <altitude> <accuracy>"
*/
public static String locationToString(Location location) {
return String.format("%s %s %s %s", location.getLatitude(), location.getLongitude(), location.getAltitude(), location.getAccuracy());
}
/**
* Get a LocationManager's providers, and trim the list down to providers we care about: GPS and network.
*
* @return Set of String objects that may contain LocationManager.GPS_PROVDER and/or LocationManager.NETWORK_PROVIDER
*/
public static Set<String> evaluateProviders(LocationManager manager) {
HashSet<String> set = new HashSet<>();
List<String> providers = manager.getProviders(true);
for (String provider : providers) {
if (provider.equalsIgnoreCase(LocationManager.GPS_PROVIDER)) {
set.add(LocationManager.GPS_PROVIDER);
}
if (provider.equalsIgnoreCase(LocationManager.NETWORK_PROVIDER)) {
set.add(LocationManager.NETWORK_PROVIDER);
}
}
return set;
}
/**
* Gets the same list of providers returned by evaluateProviders, but filtered out
* to include only providers with the appropriate permissions granted.
*/
public static Set<String> evaluateProvidersWithPermissions(LocationManager manager, Context context) {
HashSet<String> set = new HashSet<>();
List<String> providers = manager.getProviders(true);
for (String provider : providers) {
if (provider.equalsIgnoreCase(LocationManager.GPS_PROVIDER) && ContextCompat.checkSelfPermission(
context, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
set.add(LocationManager.GPS_PROVIDER);
}
if (provider.equalsIgnoreCase(LocationManager.NETWORK_PROVIDER) && ContextCompat.checkSelfPermission(
context, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
set.add(LocationManager.NETWORK_PROVIDER);
}
}
return set;
}
/**
* Display a non-cancel-able dialog asking user if they want to turn on their GPS.
*
* @param onChange Listener to call when dialog button is pressed.
*/
public static void showNoGpsDialog(CommCareActivity activity,
DialogInterface.OnClickListener onChange) {
StandardAlertDialog factory = setupAlertFactory(activity, onChange, null);
activity.showAlertDialog(factory);
}
/**
* Display a (possibly cancelable) dialog asking user if they want to turn on their GPS.
*
* @param onChange Listener to call when dialog button is pressed.
* @param onCancel Listener to call when dialog is canceled.
*/
public static void showNoGpsDialog(Activity activity,
DialogInterface.OnClickListener onChange,
DialogInterface.OnCancelListener onCancel) {
StandardAlertDialog factory = setupAlertFactory(activity, onChange, onCancel);
// NOTE PLM: this dialog will not persist through orientation changes.
factory.showNonPersistentDialog();
}
private static StandardAlertDialog setupAlertFactory(Context context,
DialogInterface.OnClickListener onChange,
DialogInterface.OnCancelListener onCancel) {
StandardAlertDialog factory =
new StandardAlertDialog(context,
StringUtils.getStringRobust(context, R.string.no_gps_title),
StringUtils.getStringRobust(context, R.string.no_gps_message));
factory.setPositiveButton(StringUtils.getStringRobust(context, R.string.change_settings), onChange);
factory.setNegativeButton(StringUtils.getStringRobust(context, R.string.cancel_location), onChange);
if (onCancel != null) {
factory.setOnCancelListener(onCancel);
}
return factory;
}
/**
* Pass in a string representing either a GeoPoint or an address and get back a valid
* GeoURI that can be passed as an intent argument
*/
public static String getGeoIntentURI(String rawInput) {
try {
GeoPointData mGeoPointData = new GeoPointData().cast(new UncastData(rawInput));
String latitude = Double.toString(mGeoPointData.getValue()[0]);
String longitude = Double.toString(mGeoPointData.getValue()[1]);
return "geo:" + latitude + "," + longitude + "?q=" + latitude + "," + longitude;
} catch (IllegalArgumentException iae) {
return "geo:0,0?q=" + rawInput;
}
}
}