In my app I have a button, which opens a Google map with sent coordinates.
final ImageView view = findViewById(R.id.navigate);
view.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent = new Intent(android.content.Intent.ACTION_VIEW,
Uri.parse("http://maps.google.com/maps?daddr="+gps1+","+gps2));
startActivity(intent);
}
});
This is working fine, but I want to offer to the user all navigation apps that he has in his device after button click.
So not to automatically open Google Maps, but let the user choose which app to use.
I found this solution, but this is only for Google maps and Waze. As I can't know which and how many navigation apps the user has on his device, I can't hardcode all existing navigation apps.
String url = "waze://?ll=" + latitude + ", " + longitude + "&navigate=yes";
Intent intentWaze.setPackage("com.waze");
Intent intentWaze = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
String uriGoogle = "google.navigation:q=" + latitude + "," + longitude;
Intent intentGoogleNav.setPackage("com.google.android.apps.maps");
Intent intentGoogleNav = new Intent(Intent.ACTION_VIEW, Uri.parse(uriGoogle));
String title = context.getString(R.string.title);
Intent chooserIntent = Intent.createChooser(intentGoogleNav, title);
Intent[] arr = new Intent[1];
arr[0] = intentWaze;
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, arr);
context.startActivity(chooserIntent);
So is there any solution, which can offer all navigation apps that the user has?
For example for sharing function it works like this:
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT,
infox);
sendIntent.setType("text/plain");
startActivity(Intent.createChooser(sendIntent, getString(R.string.share)));
This will show many apps with sharing possibility. How to do the same for apps with map?
EDIT: I added this to google and waze code, so now I have listed in chooser: Google map, Waze and an unknown android icon, when I click it, it shows all navigation apps on my device! However only if I click that unnamed icon and it only opens those maps without navigation.
String urlx = "geo:" + gps1 + ", " + gps2;
Intent intentOther = new Intent(Intent.ACTION_VIEW, Uri.parse(urlx));
I need to show all those app immediately after button click.
This is a year later and I was actually trying to use the solution above and I encountered some issues. Such as two Waze apps in the selector
I have just rewritten the solution in kotlin and what actually worked for me
val url = "waze://?ll=" + latitude + ", " + longitude + "&navigate=yes"
var intentWaze = Intent(Intent.ACTION_VIEW, Uri.parse(url)).setPackage("com.waze")
val uriGoogle = "google.navigation:q=" + latitude + "," + longitude
var intentGoogleNav = Intent(Intent.ACTION_VIEW, Uri.parse(uriGoogle)).setPackage("com.google.android.apps.maps")
val title: String = context.getString(R.string.app_name)
val chooserIntent = Intent.createChooser(intentGoogleNav, title)
val arr = arrayOfNulls<Intent>(1)
arr[0] = intentWaze
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, arr)
context.startActivity(chooserIntent)
So as I found out, there is no universal way to force navigation routes on all navigation apps in intent chooser, so I solved it like I mentioned above, just I added a parameter to geo like this:
geo:0,0?q=latitude,longitude
and add to manifest:
<data android:scheme="geo"/>
and this shows all navigation apps on my device in the chooser, and mostly shows the point on the map with the coordinates, but some apps like Waze also calculates the route immediately, so I think this is a good solution.
Related
I have two values in latitude and longitude. I have a key. This button must have two options to go to location information,Yandex Navi and Google Maps. When I click on the button, I want to know which one would like to open it. How can I do that?
You can use Intent.createChooser() like:
String url = "yandexmaps://maps.yandex.ru/?pt=" + latitude + "" + longitude + "&z=12&l=map";
Intent intentYandex = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
intentYandex.setPackage("ru.yandex.yandexmaps");
String uriGoogle = "geo:" + latitude + "," + longitude;
Intent intentGoogle = new Intent(Intent.ACTION_VIEW, Uri.parse(uriGoogle));
intentGoogle.setPackage("com.google.android.apps.maps");
String title = "Select";
Intent chooserIntent = Intent.createChooser(intentGoogle, title);
Intent[] arr = new Intent[1];
arr[0] = intentYandex;
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, arr);
startActivity(chooserIntent);
Andrii Omelchenko's answer always opens Google Maps for me. But after change google and Yandex order for chooserIntent, it is worked in my case:
val uriYandex = "yandexnavi://build_route_on_map?lat_to=${latitude}&lon_to=${longitude}"
val intentYandex = Intent(Intent.ACTION_VIEW, Uri.parse(uriYandex))
intentYandex.setPackage("ru.yandex.yandexnavi")
val uriGoogle = Uri.parse("google.navigation:q=${latitude},${longitude}&mode=w")
val intentGoogle = Intent(Intent.ACTION_VIEW, uriGoogle)
intentGoogle.setPackage("com.google.android.apps.maps")
val chooserIntent = Intent.createChooser(intentYandex, title)
val arr = arrayOfNulls<Intent>(1)
arr[0] = intentGoogle
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, arr)
val activities = packageManager.queryIntentActivities(chooserIntent, 0)
if(activities.size>0){
startActivity(chooserIntent)
}else{
//do sth..
}
If it absolutely has to be either Google Maps or Yandex Navi, the easiest way would probably be to figure out which one the user wants to use (via a dialogue or similar), and then set that as the target of a Map Intent. For example, here's an intent from Google's Android documentation that targets Google Maps by app name:
// Creates an Intent that will load a map of San Francisco
Uri gmmIntentUri = Uri.parse("geo:37.7749,-122.4194");
Intent mapIntent = new Intent(Intent.ACTION_VIEW,
gmmIntentUri);
mapIntent.setPackage("com.google.android.apps.maps");
startActivity(mapIntent);
This should also work with Navi by setting the package to "ru.yandex.yandexnavi".
Note, though, that a more standard way to do this would be with a Map Intent that doesn't specify the targeted app. That way, all you would have to provide is the coordinates, and then the user could use their app of choice:
public void showMap(Uri geoLocation) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(geoLocation);
if (intent.resolveActivity(getPackageManager()) != null) {
startActivity(intent);
}
}
Since Waze and Google Maps have different URI formats, I need to create two separate intents in order to make sure that apps will navigate user to the correct location.
The main problem: I don't want to make user select navigation app every time. I want it to behave like this: if user has default navigation app set - use it without asking.
How to have two URIs for separate apps but still have the same interface just like when starting intent with ACTION_VIEW parameter?
This is my code that I am working with. Currently navigation works fine, but user is being asked every time to select navigation app:
if (!StringUtils.isEmpty(address)) {
String q = address + "&mode=d&navigate=yes&geo=" + address + "&ll=" + address;
String urlWaze = "https://waze.com/ul?q=" + q;
Intent wazeIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(urlWaze));
String urlGoogle = "google.navigation:q=" + q;
Intent googleMapsIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(urlGoogle));
googleMapsIntent.setPackage("com.google.android.apps.maps");
String title = getActivity().getResources().getString(R.string.choose_navigation_app);
Intent chooserIntent = Intent.createChooser(wazeIntent, title);
Intent[] arr = new Intent[1];
arr[0] = googleMapsIntent;
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, arr);
getContext().startActivity(chooserIntent);
} else {
Toast.makeText(getContext(), getString(R.string.waypoint_not_have_geolocation), Toast.LENGTH_SHORT).show();
}
As it turns out Waze and Google Maps have very different URIs and in ordet to resolve situation that I descibed in my question, the only solution was to create separate user-settings in my application.
There are a few similar posts but I couldn't find an exact one. basically, I want to open both Google maps and Waze with the same intent. At first I tried this:
final String uri = String.format(Locale.ENGLISH, "geo:%f,%f", latitude, longitude);
final Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(uri));
startActivity(intent);
Waze navigated directly to the right location and Google maps opened the right place. then I realized that Google maps doesn't put a pin on the location so it's hard for the user to know where it is exactly. So I looked around and realized that Google maps requires the "?q=..(label)" for that... I changed the uri construction to:
final String uri = String.format(Locale.ENGLISH, "geo:%f,%f?q=%f,%f (%s)", latitude, longitude, latitude, longitude, name);
But then Waze did 2 things: navigated to the right place AND run a search on the label. This required the user to click the back button to close the search results screen and remain with the navigation to the right place.
I looked everywhere for an answer but failed to find a solution that will achieve both.
At first I thought that it's not possible and Waze has a bug... but then I noticed that Facebook messenger is doing exactly what I want. when clicking on a message with a location it will open both apps: Google maps will have a pin (with a label) and Waze will navigate straight to that location without running a search.
Few questions about the above:
1. (Of course) How can I achieve that?
2. How can I know how the Facebook messenger's intent being built? (Can I catch it in anyway)
3. What's the reason behind having the label only with the "?q=.."?
Thanks
Never mind. I was able to intercept the Facebook messenger with the below app and figured that the URI should be as follows:
String.format(Locale.ENGLISH, "geo:0,0?q=") + android.net.Uri.encode(String.format("%s#%f,%f", label, latitude, longitude), "UTF-8");
The app:
https://play.google.com/store/apps/details?id=uk.co.ashtonbrsc.android.intentintercept&feature=search_result#?t=W251bGwsMSwyLDEsInVrLmNvLmFzaHRvbmJyc2MuYW5kcm9pZC5pbnRlbnRpbnRlcmNlcHQiXQ..
Thanks
Following Nimrod's tip I've installed the app and intercepted the intent from whatsapp's location feature. Here's the full Intent tested on maps and waze:
String uri = "http://maps.google.com/maps?q=loc:"+latitude+","+longitude+" ("+label+")";
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(uri));
intent.setFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
intent.setFlags(Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP);
intent.setData(Uri.parse(uri));
startActivity(intent);
My final solution for opening both Waze & GoogleMap applications to get direction ( works like a charm ) :
String uri = "";
Intent intent;
try {
uri = String.format(Locale.ENGLISH,"geo:" + location.getLat() + "," +location.getLng() + "?q=" + location.getLat()+","+location.getLng()+" ("+location.getName()+")");
intent = new Intent(Intent.ACTION_VIEW, Uri.parse(uri));
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
} catch (ActivityNotFoundException ex) {
try {
Intent unrestrictedIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(uri));
startActivity(unrestrictedIntent);
} catch (ActivityNotFoundException innerEx) {
getSnackbar(getResources().getString(R.string.map_install_application), Snackbar.LENGTH_LONG).show();
}
}
I had the same problem - wanted the navigation app (whatever it is) to show a pin (preferably with a custom label) and be ready to navigate the user there. However, having a label in the query resulted in some apps running a search or (worse) assuming the closest address match to the label and showing that as the destination (ignoring the coordinates). So, to achieve a reliable behaviour I had to forget having a named label and ended up with the following:
final String geoIntentData = "geo:" + latitude + "," + longitude + "?q=" + latitude + "," + longitude;
Intent intent = new Intent(android.content.Intent.ACTION_VIEW, Uri.parse(geoIntentData));
So far it works in all apps I tested (Google Maps, Waze, Sygic, Moovit and even Komoot and Windy Maps). Please let me know if you try this solution and it doesn't work in another app!
In my app users can save the latitude and longitude of a particular location. I want them to able to launch other apps on their phone via a geo intent such as Google Maps so that they can easily get exact directions back to it. Here is the code I am using to generate the geo intent:
public static Intent getFindIntent(Context context) {
Intent intent = new Intent();
SharedPreferences prefs = Tools.getPrefs(context);
String latitude = prefs.getString(Const.LAT_KEY, "");
String longitude = prefs.getString(Const.LONG_KEY, "");
intent.setAction(Intent.ACTION_VIEW);
String uri = String.format(Locale.US, "geo:%s,%s?z=%d&q=%s,%s", latitude, longitude,
Const.ZOOM_LEVEL, latitude, longitude);
intent.setData(Uri.parse(uri));
return intent;
}
Obviously most people will use Google Maps since it's on everyone's phone. When I first released my application Google Maps would start and drop a pin at the exact coordinates specified in the q parameter of the geo uri that is set as data for the intent. With the release of Google Maps 7, maps seems to drop a pin at the closest address to the provided coordinates. This poses a problem to me since users should be able to navigate back to the saved position exactly, and not an address near it. The only place I have found this documented is here. The docs are from the official Android Developer site but they are very sparse. Are there alternatives to the geo intent to provide this functionality or is there something wrong with my code? I think Google Maps is breaking it's API contract since I am providing coordinates and not an address.
To drop the pin use this code:
try {
Intent intent = new Intent(android.content.Intent.ACTION_VIEW,
Uri.parse("geo:" + AppointmentDetailLayout.docLatitude
+ "," + AppointmentDetailLayout.docLongitude
+ "?q=" + AppointmentDetailLayout.docLatitude
+ "," + AppointmentDetailLayout.docLongitude
+ "(" + label + ")"));
intent.setComponent(new ComponentName(
"com.google.android.apps.maps",
"com.google.android.maps.MapsActivity"));
context.startActivity(intent);
} catch (ActivityNotFoundException e) {
try {
context.startActivity(new Intent(
Intent.ACTION_VIEW,
Uri.parse("market://details?id=com.google.android.apps.maps")));
} catch (android.content.ActivityNotFoundException anfe) {
context.startActivity(new Intent(
Intent.ACTION_VIEW,
Uri.parse("http://play.google.com/store/apps/details?id=com.google.android.apps.maps")));
}
e.printStackTrace();
}
For directions use this :
Intent intent = new Intent(android.content.Intent.ACTION_VIEW,
Uri.parse("http://maps.google.com/maps?saddr=" + lat
+ "," + lng + "&daddr="
+ AppointmentDetailLayout.docLatitude + ","
+ AppointmentDetailLayout.docLongitude));
context.startActivity(intent);
I need to search nearby child hospital and find the root from button click using intent,
Intent intent = new Intent(android.content.Intent.ACTION_VIEW,
Uri.parse("http://maps.google.com/maps?&saddr="
+ x
+ ","
+ y
+ "&daddr=nearby child hospitals"
));
startActivity(intent);
x,y as current lat and long.
It will show the hospitals are not in my current location(Shows different country hospitals)
Then, I click back button, then click Get Directions button means (From text box contains my source lat and long, Destinations text box contains nearby child hospitals), it shows my nearer child hospitals.
Is there any way do to this in first (i.e., intent call)?
You can use "geo:" URL scheme to open maps and then search nearby hospitals like this:
String uri = "geo:"+ x + "," + y +"&q=child hospitals";
startActivity(new Intent(android.content.Intent.ACTION_VIEW, Uri.parse(uri)));
For documentation reference, see Invoking Google Applications on Android Devices
Uri gmmIntentUri = Uri.parse("geo:0,0?q=" + query);
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(gmmIntentUri.toString()));
intent.setPackage("com.google.android.apps.maps");
try {
context.startActivity(intent);
} catch (ActivityNotFoundException ex) {
try {
Intent unrestrictedIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(gmmIntentUri.toString()));
context.startActivity(unrestrictedIntent);
} catch (ActivityNotFoundException innerEx) {
Toast.makeText(context, "Please install a maps application", Toast.LENGTH_LONG).show();
}
}
you can use this code, intent open a map and automatic search hospital near me
String uri = "geo:"+ x + "," + y +"?q=hospitals+near+me";
startActivity(new Intent(android.content.Intent.ACTION_VIEW, Uri.parse(uri)));