Open Google Maps on Google devices

This commit is contained in:
Daniele 2022-02-23 22:06:28 +01:00
parent 3ac332535d
commit 73f597fb54
8 changed files with 99 additions and 61 deletions

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="deploymentTargetDropDown">
<runningDeviceTargetSelectedWithDropDown>
<Target>
<type value="RUNNING_DEVICE_TARGET" />
<deviceKey>
<Key>
<type value="VIRTUAL_DEVICE_PATH" />
<value value="$USER_HOME$/.android/avd/Nexus_4_API_30.avd" />
</Key>
</deviceKey>
</Target>
</runningDeviceTargetSelectedWithDropDown>
<timeTargetWasSelectedWithDropDown value="2022-02-23T20:43:47.864894Z" />
</component>
</project>

View File

@ -21,10 +21,13 @@
package="it.danieleverducci.nextcloudmaps"> package="it.danieleverducci.nextcloudmaps">
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<queries> <queries>
<package android:name="com.nextcloud.client" /> <package android:name="com.nextcloud.client" />
<!-- To see if google maps is installed, as it needs a specific intent Uri) -->
<package android:name="com.google.android.apps.maps" />
</queries> </queries>
<application <application

View File

@ -161,7 +161,7 @@ public class GeofavoriteDetailActivity extends NextcloudMapsStyledActivity imple
if (getIntent().getData() != null) { if (getIntent().getData() != null) {
// Opened by external generic intent: parse URI // Opened by external generic intent: parse URI
try { try {
double[] coords = GeoUriParser.parseUri(getIntent().getData()); double[] coords = GeoUriParser.parseUri(getIntent().getData(), false);
mGeofavorite.setLat(coords[0]); mGeofavorite.setLat(coords[0]);
mGeofavorite.setLng(coords[1]); mGeofavorite.setLng(coords[1]);
mViewHolder.hideAccuracy(); mViewHolder.hideAccuracy();

View File

@ -15,25 +15,19 @@ import android.view.inputmethod.InputMethodManager;
import android.widget.Toast; import android.widget.Toast;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat; import androidx.core.app.ActivityCompat;
import androidx.preference.PreferenceManager;
import org.osmdroid.api.IGeoPoint; import org.osmdroid.api.IGeoPoint;
import org.osmdroid.api.IMapController; import org.osmdroid.api.IMapController;
import org.osmdroid.config.Configuration;
import org.osmdroid.config.IConfigurationProvider;
import org.osmdroid.events.MapListener; import org.osmdroid.events.MapListener;
import org.osmdroid.events.ScrollEvent; import org.osmdroid.events.ScrollEvent;
import org.osmdroid.events.ZoomEvent; import org.osmdroid.events.ZoomEvent;
import org.osmdroid.util.GeoPoint; import org.osmdroid.util.GeoPoint;
import org.osmdroid.views.CustomZoomButtonsController; import org.osmdroid.views.CustomZoomButtonsController;
import org.osmdroid.views.MapView; import org.osmdroid.views.MapView;
import org.osmdroid.views.Projection;
import java.util.Locale; import java.util.Locale;
import it.danieleverducci.nextcloudmaps.BuildConfig;
import it.danieleverducci.nextcloudmaps.R; import it.danieleverducci.nextcloudmaps.R;
import it.danieleverducci.nextcloudmaps.activity.NextcloudMapsStyledActivity; import it.danieleverducci.nextcloudmaps.activity.NextcloudMapsStyledActivity;
import it.danieleverducci.nextcloudmaps.activity.detail.GeofavoriteDetailActivity; import it.danieleverducci.nextcloudmaps.activity.detail.GeofavoriteDetailActivity;
@ -64,7 +58,7 @@ public class MapPickerActivity extends NextcloudMapsStyledActivity {
@Override @Override
public void onConfirmButtonPressed() { public void onConfirmButtonPressed() {
double[] coords = mViewHolder.getCurrentCoordinates(); double[] coords = mViewHolder.getCurrentCoordinates();
Uri geoUri = GeoUriParser.createUri(coords[0], coords[1], null); Uri geoUri = GeoUriParser.createGeoUri(coords[0], coords[1], null);
Intent i = new Intent(MapPickerActivity.this, GeofavoriteDetailActivity.class); Intent i = new Intent(MapPickerActivity.this, GeofavoriteDetailActivity.class);
i.setData(geoUri); i.setData(geoUri);
startActivity(i); startActivity(i);

View File

@ -164,7 +164,10 @@ public class Geofavorite implements Serializable {
} }
public Uri getGeoUri() { public Uri getGeoUri() {
return GeoUriParser.createUri(this.lat, this.lng, this.name); return GeoUriParser.createGeoUri(this.lat, this.lng, this.name);
}
public Uri getGmapsUri() {
return GeoUriParser.createGmapsUri(this.lat, this.lng);
} }
public boolean valid() { public boolean valid() {

View File

@ -10,35 +10,79 @@ import it.danieleverducci.nextcloudmaps.model.Geofavorite;
public class GeoUriParser { public class GeoUriParser {
private static final Pattern PATTERN_GEO = Pattern.compile("geo:(-?[\\d.]+),(-?[\\d.]+)"); private static final Pattern PATTERN_GEO = Pattern.compile("geo:(-?[\\d.]+),(-?[\\d.]+)");
// Try to match not only geoUri but also Google Maps Uri
private static final Pattern PATTERN_BROAD = Pattern.compile(
"(?:&query=|&center=|geo:)(-?\\d{1,2}\\.\\d{1,10})(?:,|%2C)(-?\\d{1,3}\\.\\d{1,10})"
);
public static double[] parseUri(Uri uri) throws IllegalArgumentException { /**
* Parses an URI into latitude and longitude
* @param uri to parse
* @param strict if true, the uri must be a valid geo: uri, otherwise a broader check is applied to include other uris, like Google Maps ones
* @return the parsed coordinates in an array [lat,lon]
* @throws IllegalArgumentException if the url could not be parsed
*/
public static double[] parseUri(Uri uri, boolean strict) throws IllegalArgumentException {
if (uri == null) if (uri == null)
throw new IllegalArgumentException("no uri"); throw new IllegalArgumentException("no uri");
Matcher m = PATTERN_GEO.matcher(uri.toString()); // Try to extract coordinates in uri string with regexp
if (m.find() && m.groupCount() == 2) { Pattern pattern = strict ? PATTERN_GEO : PATTERN_BROAD;
String sLat = m.group(1); Matcher m = pattern.matcher(uri.toString());
String sLon = m.group(2); if (!m.find() || m.groupCount() != 2)
try { throw new IllegalArgumentException("unable to parse uri: unable to find coordinates in uri");
return new double[]{Double.parseDouble(sLat), Double.parseDouble(sLon)};
} catch (NumberFormatException e) { // Obtain coordinates from regexp result
throw new IllegalArgumentException("unable to parse uri"); String sLat = m.group(1);
} String sLon = m.group(2);
} else { double[] coords = null;
throw new IllegalArgumentException("unable to parse uri"); try {
// Check coordinates are numeric
coords = new double[]{Double.parseDouble(sLat), Double.parseDouble(sLon)};
} catch (NumberFormatException e) {
throw new IllegalArgumentException("unable to parse uri: coordinates are not double");
} }
// Check coordinates validity
String error = checkCoordsValidity(coords[0], coords[1]);
if (error != null)
throw new IllegalArgumentException(error);
return coords;
} }
public static Uri createUri(double lat, double lon, String name) { public static Uri createGeoUri(double lat, double lon, String name) {
// Check coords validity String error = checkCoordsValidity(lat, lon);
if (lon <= -180 || lon >= 180 ) if (error != null)
throw new IllegalArgumentException("Invalid longitude: " + lon); throw new IllegalArgumentException(error);
if (lat <= -90 || lat >= 90)
throw new IllegalArgumentException("Invalid latitude: " + lat);
String uriStr = "geo:" + lat + "," + lon; String uriStr = "geo:" + lat + "," + lon;
if (name != null) if (name != null)
uriStr += "(" + name + ")"; uriStr += "(" + name + ")";
return Uri.parse(uriStr); return Uri.parse(uriStr);
} }
public static Uri createGmapsUri(double lat, double lon) {
String error = checkCoordsValidity(lat, lon);
if (error != null)
throw new IllegalArgumentException(error);
String uriStr = "https://www.google.com/maps/search/?api=1&query=" + lat + "," + lon;
return Uri.parse(uriStr);
}
/**
* Checks a latitude/longitude is valid
* @param lat latitude
* @param lon longitude
* @return null if valid, a string containing an error otherwise
*/
private static String checkCoordsValidity(double lat, double lon) {
// Check coords validity
if (lon <= -180 || lon >= 180 )
return "Invalid longitude: " + lon;
if (lat <= -90 || lat >= 90)
return "Invalid latitude: " + lat;
return null;
}
} }

View File

@ -1,33 +0,0 @@
package it.danieleverducci.nextcloudmaps.utils;
import android.content.Context;
import android.content.pm.PackageManager;
import android.net.Uri;
/**
* Google maps doesn't honor geouri standard, instead implements its own uri.
* A geouri opens google maps, but the position is ignored, so it is needed to use gmaps own uri.
* Utility to check if gmaps is installed and generate a gmaps uri
*/
public class GoogleMapsUri {
public static boolean isGoogleMapsInstalled(Context context) {
try {
context.getPackageManager().getApplicationInfo("com.google.android.apps.maps", 0);
return true;
} catch (PackageManager.NameNotFoundException e) {
return false;
}
}
public static Uri createGmapsUri(double lat, double lon) {
// Check coords validity
if (lon <= -180 || lon >= 180 )
throw new IllegalArgumentException("Invalid longitude: " + lon);
if (lat <= -90 || lat >= 90)
throw new IllegalArgumentException("Invalid latitude: " + lat);
String uriStr = "https://www.google.com/maps/search/?api=1&query=" + lat + "," + lon;
return Uri.parse(uriStr);
}
}

View File

@ -2,6 +2,7 @@ package it.danieleverducci.nextcloudmaps.utils;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.pm.PackageManager;
import android.util.Log; import android.util.Log;
import it.danieleverducci.nextcloudmaps.R; import it.danieleverducci.nextcloudmaps.R;
@ -22,7 +23,16 @@ public class IntentGenerator {
public static Intent newGeoUriIntent(Context context, Geofavorite item) { public static Intent newGeoUriIntent(Context context, Geofavorite item) {
Intent i = new Intent(); Intent i = new Intent();
i.setAction(Intent.ACTION_VIEW); i.setAction(Intent.ACTION_VIEW);
i.setData(item.getGeoUri()); i.setData(isGoogleMapsInstalled(context) ? item.getGmapsUri() : item.getGeoUri());
return i; return i;
} }
public static boolean isGoogleMapsInstalled(Context context) {
try {
context.getPackageManager().getApplicationInfo("com.google.android.apps.maps", 0);
return true;
} catch (PackageManager.NameNotFoundException e) {
return false;
}
}
} }