1package eu.siacs.conversations.utils;
2
3import android.content.Context;
4import android.content.Intent;
5import android.content.SharedPreferences;
6import android.net.Uri;
7import android.preference.PreferenceManager;
8
9import org.osmdroid.util.GeoPoint;
10
11import java.io.UnsupportedEncodingException;
12import java.net.URLEncoder;
13import java.util.ArrayList;
14import java.util.regex.Matcher;
15import java.util.regex.Pattern;
16
17import eu.siacs.conversations.R;
18import eu.siacs.conversations.entities.Contact;
19import eu.siacs.conversations.entities.Conversational;
20import eu.siacs.conversations.entities.Message;
21import eu.siacs.conversations.ui.ShareLocationActivity;
22import eu.siacs.conversations.ui.ShowLocationActivity;
23
24public class GeoHelper {
25
26 private static final String SHARE_LOCATION_PACKAGE_NAME = "eu.siacs.conversations.location.request";
27 private static final String SHOW_LOCATION_PACKAGE_NAME = "eu.siacs.conversations.location.show";
28
29 public static Pattern GEO_URI = Pattern.compile("geo:(-?\\d+(?:\\.\\d+)?),(-?\\d+(?:\\.\\d+)?)(?:,-?\\d+(?:\\.\\d+)?)?(?:;crs=[\\w-]+)?(?:;u=\\d+(?:\\.\\d+)?)?(?:;[\\w-]+=(?:[\\w-_.!~*'()]|%[\\da-f][\\da-f])+)*(\\?z=\\d+)?", Pattern.CASE_INSENSITIVE);
30
31 public static boolean isLocationPluginInstalled(Context context) {
32 return new Intent(SHARE_LOCATION_PACKAGE_NAME).resolveActivity(context.getPackageManager()) != null;
33 }
34
35 public static boolean isLocationPluginInstalledAndDesired(Context context) {
36 SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
37 final boolean configured = preferences.getBoolean("use_share_location_plugin", context.getResources().getBoolean(R.bool.use_share_location_plugin));
38 return configured && isLocationPluginInstalled(context);
39 }
40
41 public static Intent getFetchIntent(Context context) {
42 if (isLocationPluginInstalledAndDesired(context)) {
43 return new Intent(SHARE_LOCATION_PACKAGE_NAME);
44 } else {
45 return new Intent(context, ShareLocationActivity.class);
46 }
47 }
48
49 private static GeoPoint parseGeoPoint(String body) throws IllegalArgumentException {
50 Matcher matcher = GEO_URI.matcher(body);
51 if (!matcher.matches()) {
52 throw new IllegalArgumentException("Invalid geo uri");
53 }
54 double latitude;
55 double longitude;
56 try {
57 latitude = Double.parseDouble(matcher.group(1));
58 if (latitude > 90.0 || latitude < -90.0) {
59 throw new IllegalArgumentException("Invalid geo uri");
60 }
61 longitude = Double.parseDouble(matcher.group(2));
62 if (longitude > 180.0 || longitude < -180.0) {
63 throw new IllegalArgumentException("Invalid geo uri");
64 }
65 } catch (NumberFormatException e) {
66 throw new IllegalArgumentException("Invalid geo uri",e);
67 }
68 return new GeoPoint(latitude, longitude);
69 }
70
71 public static ArrayList<Intent> createGeoIntentsFromMessage(Context context, Message message) {
72 final ArrayList<Intent> intents = new ArrayList<>();
73 final GeoPoint geoPoint;
74 try {
75 geoPoint = parseGeoPoint(message.getRawBody());
76 } catch (IllegalArgumentException e) {
77 return intents;
78 }
79 final Conversational conversation = message.getConversation();
80 final String label = getLabel(context, message);
81
82 if (isLocationPluginInstalledAndDesired(context)) {
83 Intent locationPluginIntent = new Intent(SHOW_LOCATION_PACKAGE_NAME);
84 locationPluginIntent.putExtra("latitude", geoPoint.getLatitude());
85 locationPluginIntent.putExtra("longitude", geoPoint.getLongitude());
86 if (message.getStatus() != Message.STATUS_RECEIVED) {
87 locationPluginIntent.putExtra("jid", conversation.getAccount().getJid().toString());
88 locationPluginIntent.putExtra("name", conversation.getAccount().getJid().getLocal());
89 } else {
90 Contact contact = message.getContact();
91 if (contact != null) {
92 locationPluginIntent.putExtra("name", contact.getDisplayName());
93 locationPluginIntent.putExtra("jid", contact.getJid().toString());
94 } else {
95 locationPluginIntent.putExtra("name", UIHelper.getDisplayedMucCounterpart(message.getCounterpart()));
96 }
97 }
98 intents.add(locationPluginIntent);
99 } else {
100 Intent intent = new Intent(context, ShowLocationActivity.class);
101 intent.setAction(SHOW_LOCATION_PACKAGE_NAME);
102 intent.putExtra("latitude", geoPoint.getLatitude());
103 intent.putExtra("longitude", geoPoint.getLongitude());
104 intents.add(intent);
105 }
106
107 intents.add(geoIntent(geoPoint, label));
108
109 Intent httpIntent = new Intent(Intent.ACTION_VIEW);
110 httpIntent.setData(Uri.parse("https://maps.google.com/maps?q=loc:"+ geoPoint.getLatitude() + "," + geoPoint.getLongitude() +label));
111 intents.add(httpIntent);
112 return intents;
113 }
114
115 public static void view(Context context, Message message) {
116 final GeoPoint geoPoint = parseGeoPoint(message.getRawBody());
117 final String label = getLabel(context, message);
118 context.startActivity(geoIntent(geoPoint,label));
119 }
120
121 private static Intent geoIntent(GeoPoint geoPoint, String label) {
122 Intent geoIntent = new Intent(Intent.ACTION_VIEW);
123 geoIntent.setData(Uri.parse("geo:" + geoPoint.getLatitude() + "," + geoPoint.getLongitude() + "?q=" + geoPoint.getLatitude() + "," + geoPoint.getLongitude() + "("+ label+")"));
124 return geoIntent;
125 }
126
127 public static boolean openInOsmAnd(Context context, Message message) {
128 try {
129 final GeoPoint geoPoint = parseGeoPoint(message.getRawBody());
130 final String label = getLabel(context, message);
131 return geoIntent(geoPoint, label).resolveActivity(context.getPackageManager()) != null;
132 } catch (IllegalArgumentException e) {
133 return false;
134 }
135 }
136
137 private static String getLabel(Context context, Message message) {
138 if(message.getStatus() == Message.STATUS_RECEIVED) {
139 try {
140 return URLEncoder.encode(UIHelper.getMessageDisplayName(message),"UTF-8");
141 } catch (UnsupportedEncodingException e) {
142 throw new AssertionError(e);
143 }
144 } else {
145 return context.getString(R.string.me);
146 }
147 }
148}