I'm trying to build a Uri the most correct way for an intent to query a location on a map. In the documentation for a Maps intent, it is states that Uris should be of the form: geo:0,0?q=my+street+address
. I tried using Uri.Builder but found no method to specify the "0,0"
part of the uri as Uri.Builder doesn't have a function to specify the path without prepending a '/'. Currently I'm stuck using the following code:
uri = new Uri.Builder()
.scheme(URL_SCHEME_MAP)
.encodedOpaquePart("0,0?q=" + query)
.build();
Which is OK, but not as nice as I'd like to have it. So I'm wondering if anyone knows of a better/nicer way to do this.
As @providencemac points out, the Udacity Android development course shows how to do this, but it actually uses Uri.Builder
now. However, their code is wrong:
Uri.Builder builder = new Uri.Builder();
builder.scheme("geo")
.path("0,0")
.query(streetAddr);
Uri uri = builder.build();
If you use Google's address as the query location, as the course does, the emulator will still go there, because that's the default. But there's no location marker, and other addresses won't work. Instead, it should be like this:
Uri.Builder builder = new Uri.Builder();
builder.scheme("geo")
.appendPath("0,0")
.appendQueryParameter("q", addressString);
Uri addressUri = builder.build();
You can accomplish this by using a combination of the parse
and buildUpon
methods:
Uri geoLocation = Uri.parse("geo:0,0?").buildUpon()
.appendQueryParameter("q", location)
.build();
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(geoLocation);
I learned this approach from the Udacity class "Developing Android Apps" although they do not fully explain it.
Just to build upon @providencemac answer and provide a bit more context:
Java distinguishes between hierarchical and opaque URI. What you're trying to create here is an opaque URI. Such URI consist of three parts: scheme, opaque part and fragment. The opaque part is basically everything between the scheme separator (:
) and the fragment separator (#
).
So what buildUpon
actually does under the hood for opaque URI is the following:
return new Builder()
.scheme(getScheme())
.opaquePart(getSsp())
.fragment(getFragmentPart());
getScheme
gets everything from the string set by parse
up until :
, getSsp
(SSP means scheme specific part) gets everything in between the :
and possible #
, and getFragmentPart
gets everything after #
.
So @providencemac's answer without using parse
and builtUpon
would look as follows:
uri = new Uri.Builder()
.scheme(URL_SCHEME_MAP)
.encodedOpaquePart("0,0")
.appendQueryParameter("q", query)
.build();
Sadly though while researching this a bit in the sources I noticed a flaw with this as well as the original answer (and thus a possible issue with the mentioned Udacity course). The first two lines in appendQueryParameter
as of SDK 23rev3 look as follows:
// This URI will be hierarchical.
this.opaquePart = null;
So our formerly opaque URI gets transformed to a hierarchical one, without actually being hierarchical as it's neither relative nor does it contain the "://"
part. So the result would look something like "geo:?q=1600+Amphitheatre+Parkway%2C+CA"
, which does work when no specific longitude and latitude are given. Although if you are trying to create the second sample from the documentation like this
uri = new Uri.Builder()
.scheme("geo")
.encodedOpaquePart("47.6,-122.3")
.appendQueryParameter("z", "11")
.build();
you'd end up with "geo:?z=zoom"
, which apparently results in showing the current device's location.
So long story short: I think you should actually stick to the way you initially proposed in your question, as it does produce what you want. Although you should probably use Uri.encode(query)
.
For those who are still having problem with this. I figured this is the closest to Udacity course:
builder.scheme("geo")
.encodedPath("0,0")
.appendQueryParameter("q",streetAddress);
You just have to change Path()
to encodedPath()
.
I read documentation and try all answers and so mine. As you see in documentation there is 4 data uri schema to show location on map.
here is my suggestion for all options:
private Uri getGeoUri(double lat, double log) {
return Uri.parse("geo:" + lat + "," + log);
}
private Uri getGeoUri(double lat, double log, int zoom) {
return Uri.parse("geo:" + lat + "," + log + "?z=" + zoom);
}
private Uri getGeoUri(double lat, double log, String lable) {
return Uri.parse("geo:0,0?q=" + lat + "," + log + "(" + lable + ")");
}
private Uri getGeoUri(String address) {
return Uri.parse("geo:0,0?q=" + address);
}
and this is how to use:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Uri geoLocation = getGeoUri(47.6,-122.3); //1. simple
//Uri geoLocation = getGeoUri(47.6,-122.3, 11); //2. zoom
//Uri geoLocation = getGeoUri(34.99,-106.61, "Treasure"); //3. label
Uri geoLocation = getGeoUri("1600 Amphitheatre Parkway ,CA"); //4. address
openMap(geoLocation);
}
private void openMap(Uri geoLocation) {
Intent i = new Intent(Intent.ACTION_VIEW);
i.setData(geoLocation);
if (i.resolveActivity(getPackageManager()) != null) {
startActivity(i);
}
}
All in one MainActivity.
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Uri geoLocation = getGeoUri(47.6,-122.3); //1. simple
//Uri geoLocation = getGeoUri(47.6,-122.3, 11); //2. zoom
//Uri geoLocation = getGeoUri(34.99,-106.61, "Treasure"); //3. label
Uri geoLocation = getGeoUri("1600 Amphitheatre Parkway ,CA"); //4. address
openMap(geoLocation);
}
private void openMap(Uri geoLocation) {
Intent i = new Intent(Intent.ACTION_VIEW);
i.setData(geoLocation);
if (i.resolveActivity(getPackageManager()) != null) {
startActivity(i);
}
}
private Uri getGeoUri(double lat, double log) {
return Uri.parse("geo:" + lat + "," + log);
}
private Uri getGeoUri(double lat, double log, int zoom) {
return Uri.parse("geo:" + lat + "," + log + "?z=" + zoom);
}
private Uri getGeoUri(double lat, double log, String lable) {
return Uri.parse("geo:0,0?q=" + lat + "," + log + "(" + lable + ")");
}
private Uri getGeoUri(String address) {
return Uri.parse("geo:0,0?q=" + address);
}
}
Enjoy it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With