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 public static GeoPoint parseGeoPoint(final Uri uri) {
50 return parseGeoPoint(uri.toString());
51 }
52
53 private static GeoPoint parseGeoPoint(String body) throws IllegalArgumentException {
54 final Matcher matcher = GEO_URI.matcher(body);
55 if (!matcher.matches()) {
56 throw new IllegalArgumentException("Invalid geo uri");
57 }
58 final double latitude;
59 final double longitude;
60 try {
61 latitude = Double.parseDouble(matcher.group(1));
62 if (latitude > 90.0 || latitude < -90.0) {
63 throw new IllegalArgumentException("Invalid geo uri");
64 }
65 longitude = Double.parseDouble(matcher.group(2));
66 if (longitude > 180.0 || longitude < -180.0) {
67 throw new IllegalArgumentException("Invalid geo uri");
68 }
69 } catch (final NumberFormatException e) {
70 throw new IllegalArgumentException("Invalid geo uri",e);
71 }
72 return new GeoPoint(latitude, longitude);
73 }
74
75 public static ArrayList<Intent> createGeoIntentsFromMessage(Context context, Message message) {
76 final ArrayList<Intent> intents = new ArrayList<>();
77 final GeoPoint geoPoint;
78 try {
79 geoPoint = parseGeoPoint(message.getRawBody());
80 } catch (IllegalArgumentException e) {
81 return intents;
82 }
83 final Conversational conversation = message.getConversation();
84 final String label = getLabel(context, message);
85
86 if (isLocationPluginInstalledAndDesired(context)) {
87 Intent locationPluginIntent = new Intent(SHOW_LOCATION_PACKAGE_NAME);
88 locationPluginIntent.putExtra("latitude", geoPoint.getLatitude());
89 locationPluginIntent.putExtra("longitude", geoPoint.getLongitude());
90 if (message.getStatus() != Message.STATUS_RECEIVED) {
91 locationPluginIntent.putExtra("jid", conversation.getAccount().getJid().toString());
92 locationPluginIntent.putExtra("name", conversation.getAccount().getJid().getLocal());
93 } else {
94 Contact contact = message.getContact();
95 if (contact != null) {
96 locationPluginIntent.putExtra("name", contact.getDisplayName());
97 locationPluginIntent.putExtra("jid", contact.getJid().toString());
98 } else {
99 locationPluginIntent.putExtra("name", UIHelper.getDisplayedMucCounterpart(message.getCounterpart()));
100 }
101 }
102 intents.add(locationPluginIntent);
103 } else {
104 Intent intent = new Intent(context, ShowLocationActivity.class);
105 intent.setAction(SHOW_LOCATION_PACKAGE_NAME);
106 intent.putExtra("latitude", geoPoint.getLatitude());
107 intent.putExtra("longitude", geoPoint.getLongitude());
108 intents.add(intent);
109 }
110
111 intents.add(geoIntent(geoPoint, label));
112
113 Intent httpIntent = new Intent(Intent.ACTION_VIEW);
114 httpIntent.setData(Uri.parse("https://maps.google.com/maps?q=loc:"+ geoPoint.getLatitude() + "," + geoPoint.getLongitude() +label));
115 intents.add(httpIntent);
116 return intents;
117 }
118
119 public static void view(Context context, Message message) {
120 final GeoPoint geoPoint = parseGeoPoint(message.getRawBody());
121 final String label = getLabel(context, message);
122 context.startActivity(geoIntent(geoPoint,label));
123 }
124
125 private static Intent geoIntent(GeoPoint geoPoint, String label) {
126 Intent geoIntent = new Intent(Intent.ACTION_VIEW);
127 geoIntent.setData(Uri.parse("geo:" + geoPoint.getLatitude() + "," + geoPoint.getLongitude() + "?q=" + geoPoint.getLatitude() + "," + geoPoint.getLongitude() + "("+ label+")"));
128 return geoIntent;
129 }
130
131 public static boolean openInOsmAnd(Context context, Message message) {
132 try {
133 final GeoPoint geoPoint = parseGeoPoint(message.getRawBody());
134 final String label = getLabel(context, message);
135 return geoIntent(geoPoint, label).resolveActivity(context.getPackageManager()) != null;
136 } catch (IllegalArgumentException e) {
137 return false;
138 }
139 }
140
141 private static String getLabel(Context context, Message message) {
142 if(message.getStatus() == Message.STATUS_RECEIVED) {
143 try {
144 return URLEncoder.encode(UIHelper.getMessageDisplayName(message),"UTF-8");
145 } catch (UnsupportedEncodingException e) {
146 throw new AssertionError(e);
147 }
148 } else {
149 return context.getString(R.string.me);
150 }
151 }
152}