summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoseph Herlant <aerostitch@users.noreply.github.com>2019-10-24 13:36:47 -0700
committerGitHub <noreply@github.com>2019-10-24 13:36:47 -0700
commit38512dd79cce2c1eeec27e6f26caf96f0db56b24 (patch)
treec45a5935a5055e040818ed9a531e86d150bc189c
parent1cecebf85ca4ae8ca152a3e8169a7ebc5ff8a368 (diff)
parent7021575af7578fc54c46c61e13835941183b652f (diff)
downloadnavit-aerostitch/issue_898.tar.gz
Merge branch 'trunk' into aerostitch/issue_898aerostitch/issue_898
-rw-r--r--navit/android.c27
-rw-r--r--navit/android/AndroidManifest.xml7
-rw-r--r--navit/android/res/values/strings.xml1
-rw-r--r--navit/android/src/org/navitproject/navit/Navit.java190
-rw-r--r--navit/android/src/org/navitproject/navit/NavitGraphics.java96
-rw-r--r--navit/coord.h8
6 files changed, 248 insertions, 81 deletions
diff --git a/navit/android.c b/navit/android.c
index bddc48be8..4b73b3f5e 100644
--- a/navit/android.c
+++ b/navit/android.c
@@ -11,6 +11,7 @@
#include "callback.h"
#include "country.h"
#include "projection.h"
+#include "coord.h"
#include "map.h"
#include "mapset.h"
#include "navit_nls.h"
@@ -321,7 +322,7 @@ JNIEXPORT jobjectArray JNICALL Java_org_navitproject_navit_NavitGraphics_getAllC
JNIEXPORT jstring JNICALL Java_org_navitproject_navit_NavitGraphics_getCoordForPoint( JNIEnv* env,
- jobject thiz, jint x, jint y, jboolean absolute_coord) {
+ jobject thiz, jint x, jint y, jboolean absoluteCoord) {
jstring return_string = NULL;
@@ -343,13 +344,13 @@ JNIEXPORT jstring JNICALL Java_org_navitproject_navit_NavitGraphics_getCoordForP
pc.pro = transform_get_projection(transform);
char coord_str[32];
- if (absolute_coord) {
+ if (absoluteCoord) {
pcoord_format_absolute(&pc, coord_str, sizeof(coord_str), ",");
} else {
pcoord_format_degree_short(&pc, coord_str, sizeof(coord_str), " ");
}
- dbg(lvl_error,"Display point x=%d y=%d is \"%s\"",x,y,coord_str);
+ dbg(lvl_debug,"Display point x=%d y=%d is \"%s\"",x,y,coord_str);
return_string = (*env)->NewStringUTF(env,coord_str);
return return_string;
@@ -458,12 +459,13 @@ JNIEXPORT jint JNICALL Java_org_navitproject_navit_NavitGraphics_callbackMessage
pc.pro = transform_get_projection(transform);
char coord_str[32];
- //pcoord_format_short(&pc, coord_str, sizeof(coord_str), " ");
pcoord_format_degree_short(&pc, coord_str, sizeof(coord_str), " ");
+
dbg(lvl_debug,"Setting destination to %s",coord_str);
// start navigation asynchronous
navit_set_destination(attr.u.navit, &pc, coord_str, 1);
}
+ break;
case 3: {
// navigate to geo position
char *name;
@@ -478,14 +480,14 @@ JNIEXPORT jint JNICALL Java_org_navitproject_navit_NavitGraphics_callbackMessage
char *p;
char *stopstring;
- // lat
- p = strtok(parse_str, "#");
+ // latitude
+ p = strtok (parse_str,"#");
g.lat = strtof(p, &stopstring);
- // lon
- p = strtok(NULL, "#");
+ // longitude
+ p = strtok (NULL, "#");
g.lng = strtof(p, &stopstring);
- // description
- name = strtok(NULL, "#");
+ // description/name of the place identified by lat and long
+ name = strtok (NULL, "#");
dbg(lvl_debug, "lat=%f", g.lat);
dbg(lvl_debug, "lng=%f", g.lng);
@@ -499,14 +501,14 @@ JNIEXPORT jint JNICALL Java_org_navitproject_navit_NavitGraphics_callbackMessage
pc.y = c.y;
pc.pro = projection_mg;
char coord_str[32];
- if (!name || *name == '\0') {
+ if (!name || *name == '\0') { /* When name is an empty string, use the geo coord instead */
pcoord_format_degree_short(&pc, coord_str, sizeof(coord_str), " ");
name = coord_str;
}
// start navigation asynchronous
navit_set_destination(attr.u.navit, &pc, name, 1);
- break;
}
+ break;
default:
dbg(lvl_error, "Unknown command: %d", channel);
}
@@ -514,7 +516,6 @@ JNIEXPORT jint JNICALL Java_org_navitproject_navit_NavitGraphics_callbackMessage
return ret;
}
-
static char *postal_str(struct search_list_result *res, int level) {
char *ret=NULL;
if (res->town->common.postal)
diff --git a/navit/android/AndroidManifest.xml b/navit/android/AndroidManifest.xml
index e8f153fd4..2bcdb4e19 100644
--- a/navit/android/AndroidManifest.xml
+++ b/navit/android/AndroidManifest.xml
@@ -16,6 +16,8 @@
android:theme="@style/NavitTheme">
<activity android:name="Navit"
android:label="@string/app_name"
+ android:launchMode="singleTask"
+ android:taskAffinity=""
android:configChanges="screenLayout|smallestScreenSize|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|fontScale|screenSize"
android:windowSoftInputMode="adjustResize">
<intent-filter>
@@ -23,6 +25,11 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
+ <action android:name="android.intent.action.VIEW"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <data android:scheme="geo"/>
+ </intent-filter>
+ <intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="google.navigation" />
diff --git a/navit/android/res/values/strings.xml b/navit/android/res/values/strings.xml
index 44ed1483b..5ce99e52a 100644
--- a/navit/android/res/values/strings.xml
+++ b/navit/android/res/values/strings.xml
@@ -31,6 +31,7 @@
<string name="position_popup_title">Position</string>
<string name="position_popup_drive_here">Route to here</string>
<string name="position_popup_view">View</string>
+ <string name="use_position_with">Use position with</string>
<!-- MAP DOWNLOAD -->
<string name="map_delete">Delete this map?</string>
diff --git a/navit/android/src/org/navitproject/navit/Navit.java b/navit/android/src/org/navitproject/navit/Navit.java
index 87ad5d9a8..2fa2f312d 100644
--- a/navit/android/src/org/navitproject/navit/Navit.java
+++ b/navit/android/src/org/navitproject/navit/Navit.java
@@ -71,14 +71,86 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
-
public class Navit extends Activity {
+ /**
+ * Nested class storing the intent that was sent to the main navit activity at startup.
+ **/
+ private class StartupIntent {
+ /**
+ * Constructor.
+ *
+ * @param intent The intent to store in this object
+ **/
+ public StartupIntent(Intent intent) {
+ mStartupIntent = intent;
+ mStartupIntentTimestamp = System.currentTimeMillis();
+ }
+
+ /**
+ * Check if the encapsulated intent still valid or too old.
+ *
+ * @return true if the encapsulated intent is recent enough
+ **/
+ public boolean isRecentEnough() {
+ if (mStartupIntent == null) {
+ return false;
+ }
+ /* We consider the intent is valid for 4s */
+ return (System.currentTimeMillis() <= getExpirationTimeMillis());
+ }
+
+ /**
+ * Compute the system time when the stored intent will become invalid.
+ *
+ * @return The system time for invalidation (in ms)
+ **/
+ private long getExpirationTimeMillis() {
+ if (mStartupIntent == null) {
+ return 0;
+ }
+ /* We give 4s to navit to process the intent */
+ return mStartupIntentTimestamp + 4000L;
+ }
+
+ /**
+ * Getter for the encapsulated intent.
+ *
+ * @return The encapsulated intent
+ **/
+ public Intent getIntent() {
+ return mStartupIntent;
+ }
+
+ /**
+ * Represent this object as a string.
+ *
+ * @return A string containing the summary of the data we store here
+ **/
+ public String toString() {
+ if (mStartupIntent == null) {
+ return "{null}";
+ } else {
+ String validForStr;
+ long remainingValidity = getExpirationTimeMillis() - System.currentTimeMillis();
+ if (remainingValidity < 0) {
+ validForStr = "(expired since " + -remainingValidity + "ms)";
+ } else {
+ validForStr = "(valid for " + remainingValidity + "ms)";
+ }
+ return "{ act=" + mStartupIntent.getAction() + " data=" + mStartupIntent.getDataString()
+ + " " + validForStr + " }";
+ }
+ }
+
+ private Intent mStartupIntent; /*!< The intent we store */
+ private long mStartupIntentTimestamp; /*!< A timestamp (in ms) for when mStartupIntent was recorded */
+ }
+
public static DisplayMetrics sMetrics;
public static boolean sShowSoftKeyboardShowing;
- private static Intent sStartupIntent;
- private static long sStartupIntentTimestamp;
+ private static StartupIntent sStartupIntent;
private static final int MY_PERMISSIONS_REQ_FINE_LOC = 103;
private static final int NavitDownloaderSelectMap_id = 967;
private static final int NavitAddressSearch_id = 70;
@@ -214,6 +286,9 @@ public class Navit extends Activity {
return true;
}
+ /**
+ * Show the first start infoxbox (presentation of navit and link website for more info).
+ **/
private void showInfos() {
SharedPreferences settings = getSharedPreferences(NavitAppConfig.NAVIT_PREFS, MODE_PRIVATE);
boolean firstStart = settings.getBoolean("firstStart", true);
@@ -260,22 +335,21 @@ public class Navit extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
+ Log.d(TAG, "OnCreate");
super.onCreate(savedInstanceState);
windowSetup();
mDialogs = new NavitDialogs(this);
- // only take arguments here, onResume gets called all the time (e.g. when screenblanks, etc.)
- Navit.sStartupIntent = this.getIntent();
- // hack! Remember time stamps, and only allow 4 secs. later in onResume to set target!
- Navit.sStartupIntentTimestamp = System.currentTimeMillis();
- Log.d(TAG, "**1**A " + sStartupIntent.getAction());
- Log.d(TAG, "**1**D " + sStartupIntent.getDataString());
+ /* Only store the startup intent, onResume() gets called all the time (e.g. when screenblanks, etc.) and
+ will process this intent later on if needed */
+ sStartupIntent = new StartupIntent(this.getIntent());
+ Log.d(TAG, "Recording intent " + sStartupIntent.toString());
createNotificationChannel();
buildNotification();
verifyPermissions();
- // get the local language -------------
+ // get the local language
Locale locale = Locale.getDefault();
String lang = locale.getLanguage();
String langc = lang;
@@ -426,6 +500,13 @@ public class Navit extends Activity {
}
@Override
+ public void onNewIntent(Intent intent) {
+ Log.d(TAG, "OnNewIntent");
+ sStartupIntent = new StartupIntent(intent);
+ Log.d(TAG, "Recording intent " + sStartupIntent.toString());
+ }
+
+ @Override
public void onResume() {
super.onResume();
Log.d(TAG, "OnResume");
@@ -435,24 +516,33 @@ public class Navit extends Activity {
// intent_data = "google.navigation:q=48.25676,16.643";
// intent_data = "google.navigation:ll=48.25676,16.643&q=blabla-strasse";
// intent_data = "google.navigation:ll=48.25676,16.643";
+ // intent_data = "geo:48.25676,16.643";
if (sStartupIntent != null) {
- if (System.currentTimeMillis() <= Navit.sStartupIntentTimestamp + 4000L) {
- Log.d(TAG, "**2**A " + sStartupIntent.getAction());
- Log.d(TAG, "**2**D " + sStartupIntent.getDataString());
- String naviScheme = sStartupIntent.getScheme();
- if (naviScheme != null && naviScheme.equals("google.navigation")) {
- parseNavigationURI(sStartupIntent.getData().getSchemeSpecificPart());
+ Log.d(TAG, "Using stored startup intent " + sStartupIntent.toString());
+ if (sStartupIntent.isRecentEnough()) {
+ Intent startupIntent = sStartupIntent.getIntent();
+ String naviScheme = startupIntent.getScheme();
+ if (naviScheme != null) {
+ if (naviScheme.equals("google.navigation")) {
+ parseNavigationURI(startupIntent.getData().getSchemeSpecificPart());
+ } else if (naviScheme.equals("geo")
+ && startupIntent.getAction().equals("android.intent.action.VIEW")) {
+ invokeCallbackOnGeo(startupIntent.getData().getSchemeSpecificPart(),
+ NavitGraphics.MsgType.CLB_SET_DESTINATION,
+ "");
+ }
}
} else {
- Log.e(TAG, "timestamp for navigate_to expired! not using data");
+ Log.e(TAG, "timestamp for startup intent expired! not using data");
}
+ sStartupIntent = null;
}
}
@Override
public void onPause() {
super.onPause();
- Log.d(TAG, "onPause");
+ Log.d(TAG, "OnPause");
}
@Override
@@ -476,6 +566,42 @@ public class Navit extends Activity {
}
}
+ /**
+ * Invoke NavitGraphics.sCallbackHandler on a geographical position
+ *
+ * @param geoString A string containing the target geographical position with a format like "48.25676,16.643"
+ * @param msgType The type of message to send to the callback (see NavitGraphics.MsgType for possible values)
+ * @param name The name/label to associate to the geographical position
+ **/
+ private void invokeCallbackOnGeo(String geoString, NavitGraphics.MsgType msgType, String name) {
+ String[] geo = geoString.split(",");
+ if (geo.length == 2) {
+ try {
+ Bundle b = new Bundle();
+ Float lat = Float.valueOf(geo[0]);
+ Float lon = Float.valueOf(geo[1]);
+ b.putFloat("lat", lat);
+ b.putFloat("lon", lon);
+ b.putString("q", name);
+ Message msg = Message.obtain(NavitGraphics.sCallbackHandler,
+ msgType.ordinal());
+
+ msg.setData(b);
+ msg.sendToTarget();
+ Log.d(TAG, "target found (b): " + geoString);
+ } catch (NumberFormatException e) {
+ e.printStackTrace();
+ }
+ } else {
+ Log.w(TAG, "Ignoring invalid geo string: " + geoString);
+ }
+ }
+
+ /**
+ * Parse google navigation URIs (usually starting with "google.navigation:") and take the appropriate actions
+ *
+ * @param schemeSpecificPart A string containing the URI scheme, for example "ll=48.25676,16.643&q=blabla-strasse"
+ **/
private void parseNavigationURI(String schemeSpecificPart) {
String[] naviData = schemeSpecificPart.split("&");
Pattern p = Pattern.compile("(.*)=(.*)");
@@ -492,39 +618,17 @@ public class Navit extends Activity {
// c: google.navigation:ll=48.25676,16.643
// b: google.navigation:q=48.25676,16.643
- float lat;
- float lon;
- Bundle b = new Bundle();
-
String geoString = params.get("ll");
+ String address = null;
if (geoString != null) {
- String address = params.get("q");
- if (address != null) {
- b.putString("q", address);
- }
+ address = params.get("q");
} else {
geoString = params.get("q");
}
if (geoString != null) {
if (geoString.matches("^[+-]{0,1}\\d+(|\\.\\d*),[+-]{0,1}\\d+(|\\.\\d*)$")) {
- String[] geo = geoString.split(",");
- if (geo.length == 2) {
- try {
- lat = Float.valueOf(geo[0]);
- lon = Float.valueOf(geo[1]);
- b.putFloat("lat", lat);
- b.putFloat("lon", lon);
- Message msg = Message.obtain(NavitGraphics.sCallbackHandler,
- NavitGraphics.MsgType.CLB_SET_DESTINATION.ordinal());
-
- msg.setData(b);
- msg.sendToTarget();
- Log.i(TAG, "target found (b): " + geoString);
- } catch (NumberFormatException e) {
- e.printStackTrace();
- }
- }
+ invokeCallbackOnGeo(geoString, NavitGraphics.MsgType.CLB_SET_DESTINATION, address);
} else {
start_targetsearch_from_intent(geoString);
}
diff --git a/navit/android/src/org/navitproject/navit/NavitGraphics.java b/navit/android/src/org/navitproject/navit/NavitGraphics.java
index 6aee53cf5..cd6ce6944 100644
--- a/navit/android/src/org/navitproject/navit/NavitGraphics.java
+++ b/navit/android/src/org/navitproject/navit/NavitGraphics.java
@@ -41,6 +41,7 @@ import android.net.Uri;
import android.os.Build;
import android.os.Handler;
import android.os.Message;
+import android.os.Parcelable;
import android.support.annotation.RequiresApi;
import android.support.v4.view.ViewConfigurationCompat;
import android.util.Log;
@@ -151,6 +152,9 @@ class NavitGraphics {
static final int ZOOM = 2;
static final int PRESSED = 3;
PointF mPressedPosition = null;
+ // mContextMenuMapViewIntent is the ACTION_VIEW intent for a geo coordinates.
+ // it is used when clicking on view in the map contextual menu
+ Intent mContextMenuMapViewIntent = null;
NavitView(Context context) {
super(context);
@@ -197,6 +201,56 @@ class NavitGraphics {
return insets;
}
+ /**
+ * Create an intent for a view action of a point provided by its x and y position on the display.
+ *
+ * @param x The x coordinates of the point on the display
+ * @param y The y coordinates of the point on the display
+ *
+ * @return An intent to start to view the specified point on a third-party app on Android (can be null if a
+ * view action is not possible)
+ **/
+ protected Intent getViewIntentForDisplayPoint(int x, int y) {
+ Intent result = null;
+
+ /* Check if there is at least one application that can process a geo intent... */
+ String selectedPointCoord = getCoordForPoint(x, y, true);
+ Uri intentUri = Uri.parse("geo:" + selectedPointCoord);
+ Intent defaultShareIntent = new Intent(Intent.ACTION_VIEW, intentUri);
+
+ List<Intent> customShareIntentList = new ArrayList<Intent>();
+ List<ResolveInfo> intentTargetAppList;
+ intentTargetAppList = this.getContext().getPackageManager().queryIntentActivities(defaultShareIntent, 0);
+
+ String selfPackageName = this.getContext().getPackageName(); /* aka: "org.navitproject.navit" */
+
+ if (!intentTargetAppList.isEmpty()) {
+ for (ResolveInfo resolveInfo : intentTargetAppList) {
+ String packageName = resolveInfo.activityInfo.packageName;
+ Intent copiedIntent = new Intent(Intent.ACTION_VIEW, intentUri);
+ if (!packageName.equals(selfPackageName)) {
+ Log.d(TAG, "Adding package \"" + packageName + "\" to app chooser");
+ copiedIntent.setPackage(packageName);
+ copiedIntent.setClassName(
+ resolveInfo.activityInfo.packageName,
+ resolveInfo.activityInfo.name);
+ customShareIntentList.add(copiedIntent);
+ } else {
+ Log.d(TAG, "Excluding ourselves (package " + packageName + ") from intent targets");
+ }
+ }
+ if (customShareIntentList.size() > 0) {
+ result = Intent.createChooser(customShareIntentList.remove(customShareIntentList.size() - 1),
+ NavitAppConfig.getTstring(R.string.use_position_with));
+ result.putExtra(Intent.EXTRA_INITIAL_INTENTS,
+ customShareIntentList.toArray(new Parcelable[customShareIntentList.size()]));
+ Log.d(TAG, "Preparing action intent (" + customShareIntentList.size() + 1
+ + " candidate apps) to view selected coord: " + selectedPointCoord);
+ }
+ }
+ return result;
+ }
+
private static final int MENU_DRIVE_HERE = 1;
private static final int MENU_VIEW = 2;
private static final int MENU_CANCEL = 3;
@@ -208,39 +262,39 @@ class NavitGraphics {
menu.setHeaderTitle(NavitAppConfig.getTstring(R.string.position_popup_title) + " " + clickCoord);
menu.add(1, MENU_DRIVE_HERE, NONE, NavitAppConfig.getTstring(R.string.position_popup_drive_here))
.setOnMenuItemClickListener(this);
- Uri intentUri = Uri.parse("geo:" + getCoordForPoint((int)mPressedPosition.x,
- (int)mPressedPosition.y, true));
- Intent mContextMenuMapViewIntent = new Intent(Intent.ACTION_VIEW, intentUri);
-
- PackageManager packageManager = this.getContext().getPackageManager();
- List<ResolveInfo> activities = packageManager.queryIntentActivities(mContextMenuMapViewIntent,
- PackageManager.MATCH_DEFAULT_ONLY);
- boolean isIntentSafe = (activities.size() > 0); // at least one candidate receiver
- if (isIntentSafe) { // add view with external app option
- menu.add(1, MENU_VIEW, NONE, NavitAppConfig.getTstring(R.string.position_popup_view))
- .setOnMenuItemClickListener(this);
+ mContextMenuMapViewIntent = getViewIntentForDisplayPoint((int)mPressedPosition.x, (int)mPressedPosition.y);
+ if (mContextMenuMapViewIntent != null) {
+ menu.add(1, MENU_VIEW, NONE,
+ NavitAppConfig.getTstring(R.string.position_popup_view)).setOnMenuItemClickListener(this);
} else {
- Log.w(TAG, "No application available to handle ACTION_VIEW intent, option not displayed");
+ Log.w(TAG, "No application available to handle ACTION_VIEW intent, view option not displayed");
}
- menu.add(1, MENU_CANCEL, NONE, getTstring(R.string.cancel)).setOnMenuItemClickListener(this);
+ menu.add(1, MENU_CANCEL, NONE,
+ NavitAppConfig.getTstring(R.string.cancel)).setOnMenuItemClickListener(this);
}
@Override
public boolean onMenuItemClick(MenuItem item) {
int itemId = item.getItemId();
+ if (itemId != MENU_VIEW) {
+ /* Destroy any previous map view intent if the user didn't select the MENU_VIEW action */
+ mContextMenuMapViewIntent = null;
+ }
if (itemId == MENU_DRIVE_HERE) {
Message msg = Message.obtain(sCallbackHandler, MsgType.CLB_SET_DISPLAY_DESTINATION.ordinal(),
(int) mPressedPosition.x, (int) mPressedPosition.y);
msg.sendToTarget();
} else if (itemId == MENU_VIEW) {
- Uri intentUri = Uri.parse("geo:" + getCoordForPoint((int) mPressedPosition.x,
- (int) mPressedPosition.y, true));
- Intent mContextMenuMapViewIntent = new Intent(Intent.ACTION_VIEW, intentUri);
- mContextMenuMapViewIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
- if (mContextMenuMapViewIntent.resolveActivity(this.getContext().getPackageManager()) != null) {
- this.getContext().startActivity(mContextMenuMapViewIntent);
+ if (mContextMenuMapViewIntent != null) {
+ mContextMenuMapViewIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ if (mContextMenuMapViewIntent.resolveActivity(this.getContext().getPackageManager()) != null) {
+ this.getContext().startActivity(mContextMenuMapViewIntent);
+ } else {
+ Log.w(TAG, "View menu selected but intent is not handled by any application. Ignoring...");
+ }
+ mContextMenuMapViewIntent = null; /* Destoy the intent once it has been used */
} else {
- Log.w(TAG, "ACTION_VIEW intent is not handled by any application, discarding...");
+ Log.e(TAG, "User clicked on view on menu but intent was null. Discarding...");
}
}
return true;
@@ -669,7 +723,7 @@ class NavitGraphics {
private native void motionCallback(long id, int x, int y);
- private native String getCoordForPoint(int x, int y, boolean absolutCoord);
+ private native String getCoordForPoint(int x, int y, boolean absoluteCoord);
static native String[][] getAllCountries();
diff --git a/navit/coord.h b/navit/coord.h
index cad6a86e8..f3601830d 100644
--- a/navit/coord.h
+++ b/navit/coord.h
@@ -113,13 +113,13 @@ struct coord_geo_cart {
enum coord_format
{
/**
- * Degrees with absolute decimal places (positive or negative)
- * ie -20.500000 -110.500000
- */
+ * Degrees with absolute decimal places (positive or negative)
+ * ie -20.500000 -110.500000
+ */
DEGREES_DECIMAL_ABSOLUTE,
/**
- * Degrees with decimal places.
+ * Degrees with decimal places (positive with heading)
* ie 20.500000°N 110.500000°E
*/
DEGREES_DECIMAL,