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