/*
* Geopaparazzi - Digital field mapping on Android based devices
* Copyright (C) 2010 HydroloGIS (www.hydrologis.com)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package eu.geopaparazzi.library.sms;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.Uri;
import android.preference.PreferenceManager;
import android.telephony.SmsManager;
import android.telephony.TelephonyManager;
import android.widget.Toast;
import eu.geopaparazzi.library.R;
import eu.geopaparazzi.library.database.GPLog;
import eu.geopaparazzi.library.util.LibraryConstants;
import eu.geopaparazzi.library.util.PositionUtilities;
import eu.geopaparazzi.library.util.Utilities;
/**
* Utilities for sms handling.
*
* @author Andrea Antonello (www.hydrologis.com)
*/
@SuppressWarnings("nls")
public class SmsUtilities {
public static String SMSHOST = "gp.eu";
/**
* Create a text containing the OSM link to the current position.
*
* @param context the {@link Context} to use.
* @param messageText the text to add before the url.
* @return the position url.
*/
public static String createPositionText( final Context context, String messageText ) {
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
double[] gpsLocation = PositionUtilities.getGpsLocationFromPreferences(preferences);
if (gpsLocation == null) {
gpsLocation = PositionUtilities.getMapCenterFromPreferences(preferences, false, false);
}
StringBuilder sB = new StringBuilder();
if (gpsLocation != null) {
String latString = LibraryConstants.COORDINATE_FORMATTER.format(gpsLocation[1]).replaceAll(",", ".");
String lonString = LibraryConstants.COORDINATE_FORMATTER.format(gpsLocation[0]).replaceAll(",", ".");
// http://www.osm.org/?lat=46.068941&lon=11.169849&zoom=18&layers=M&mlat=42.95647&mlon=12.70393&GeoSMS
// http://maps.google.com/maps?q=46.068941,11.169849&GeoSMS
// google maps has the url that is geosms compliant
sB.append("http://maps.google.com/maps?q=");
sB.append(latString);
sB.append(",");
sB.append(lonString);
sB.append("&GeoSMS");
// TODO use OSM again when the coordinates in the url will be geosms compliant
// sB.append("http://www.osm.org/?lat=");
// sB.append(latString);
// sB.append("&lon=");
// sB.append(lonString);
// sB.append("&zoom=14");
// sB.append("&layers=M&mlat=");
// sB.append(latString);
// sB.append("&mlon=");
// sB.append(lonString);
// sB.append("&GeoSMS");
if (messageText != null)
sB.append(" ").append(messageText);
String msg = sB.toString();
if (sB.toString().length() > 160) {
// if longer than 160 chars it will not work
sB = new StringBuilder(msg);
}
} else {
sB.append(context.getString(R.string.last_position_unknown));
}
return sB.toString();
}
/**
* Send an SMS.
*
* @param context the {@link Context} to use.
* @param number the number to which to send the SMS.
* @param msg the SMS body text.
* @param sendMessage if <code>true</code>, a {@link Toast} tells the user that the message was sent.
*/
public static void sendSMS( Context context, String number, String msg, boolean sendMessage ) {
Object systemService = context.getSystemService(Context.TELEPHONY_SERVICE);
if (systemService instanceof TelephonyManager) {
TelephonyManager telManager = (TelephonyManager) systemService;
String networkOperator = telManager.getNetworkOperator();
if (networkOperator.trim().length() == 0) {
Utilities.messageDialog(context, "This functionality works only when connected to a GSM network.", null);
return;
}
}
SmsManager mng = SmsManager.getDefault();
PendingIntent dummyEvent = PendingIntent.getBroadcast(context, 0, new Intent("com.devx.SMSExample.IGNORE_ME"), 0);
try {
if (msg.length() > 160) {
msg = msg.substring(0, 160);
if (GPLog.LOG)
GPLog.addLogEntry("SMSUTILITIES", "Trimming msg to: " + msg);
}
mng.sendTextMessage(number, null, msg, dummyEvent, dummyEvent);
if (sendMessage)
Utilities.toast(context, R.string.message_sent, Toast.LENGTH_LONG);
} catch (Exception e) {
GPLog.error(context, e.getLocalizedMessage(), e);
Utilities.messageDialog(context, "An error occurred while sending the SMS.", null);
}
}
/**
* Opens the system sms app to send the message.
*
* @param context the {@link Context} to use.
* @param number the number to which to send to or <code>null</code>, in which
* case the number will be prompted in the sms app.
* @param msg the message to send or <code>null</code>.
*/
public static void sendSMSViaApp( Context context, String number, String msg ) {
Object systemService = context.getSystemService(Context.TELEPHONY_SERVICE);
if (systemService instanceof TelephonyManager) {
TelephonyManager telManager = (TelephonyManager) systemService;
int phoneType = telManager.getPhoneType();
if (phoneType == TelephonyManager.PHONE_TYPE_NONE) {
// no phone
Utilities.messageDialog(context, "This functionality works only when connected to a GSM network.", null);
return;
}
}
if (number == null) {
number = "";
}
if (msg == null) {
msg = "";
}
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("sms:" + number));
intent.putExtra("sms_body", msg);
context.startActivity(intent);
}
/**
* Parses a GeoSMS body and tries to extract the coordinates to show them.
*
* @param context the {@link Context} to use.
* @param smsBody the body of the sms.
*/
public static void openGeoSms( final Context context, String smsBody ) {
/*
* a geosms is supposed to be at least in the form:
*
* http://url?params...?XYZASD=lat,lon?params...?GeoSMS
*/
String[] split = smsBody.toLowerCase().split("\\?");
for( String string : split ) {
if (string.startsWith("http") || string.startsWith("www")) {
continue;
}
if (string.contains("=") && string.contains(",")) {
String[] coordsParams = string.split("=");
if (coordsParams.length == 2) {
String possibleCoordinates = coordsParams[1];
if (possibleCoordinates.contains("&")) {
int indexOfAmper = possibleCoordinates.indexOf('&');
possibleCoordinates = possibleCoordinates.substring(0, indexOfAmper);
}
if (possibleCoordinates.contains(",")) {
String[] coordsSplit = possibleCoordinates.split(",");
if (coordsSplit.length == 2) {
String latStr = coordsSplit[0].trim();
String lonStr = coordsSplit[1].trim();
try {
// double lat = Double.parseDouble(latStr);
// double lon = Double.parseDouble(lonStr);
StringBuilder sB = new StringBuilder();
// sb.append("geo:");
// sb.append(lat);
// sb.append(",");
// sb.append(lon);
sB.append("http://maps.google.com/maps?q=");
sB.append(latStr);
sB.append(",");
sB.append(lonStr);
sB.append("&GeoSMS");
final String geoCoords = sB.toString();
NotificationManager notifier = (NotificationManager) context
.getSystemService(Context.NOTIFICATION_SERVICE);
int icon = R.drawable.current_position;
Notification notification = new Notification(icon, "Incoming GeoSMS", System.currentTimeMillis());
final Intent myIntent = new Intent(android.content.Intent.ACTION_VIEW, Uri.parse(geoCoords));
PendingIntent contentIntent = PendingIntent.getActivity(context, 0, myIntent, 0);
notification.setLatestEventInfo(context, "GeoSMS",
"Select here to open the GeoSMS with a dedicated application", contentIntent);
notification.flags |= Notification.FLAG_AUTO_CANCEL;
notifier.notify(0x007, notification);
} catch (Exception e) {
// ignore the param, it was not a coordinate block
}
}
}
}
}
}
}
/**
* Converts an sms data content to the data.
*
* <p>
* The format is of the type <b>gp.eu/n:x,y,desc;n:x,y,z,desc;b:x,y,desc;b:x,y,z,desc;...</b>
* </p>
* <p>
* Where n = note, in which case z can be added and is the altitude; and
* b = bookmark, in which case z can be added and is the zoom.
* </p>
*
* @param url the sms data url to convert.
* @return the list of {@link SmsData} containing notes and bookmarks data.
* @throws IOException
*/
public static List<SmsData> sms2Data( String url ) throws IOException {
List<SmsData> smsDataList = new ArrayList<SmsData>();
url = url.replaceFirst("http://", "");
// remove gp://
url = url.substring(6);
String[] dataSplit = url.split(";");
for( String data : dataSplit ) {
if (data.startsWith("n:") || data.startsWith("b:")) {
String dataTmp = data.substring(2);
String[] values = dataTmp.split(",");
if (values.length < 3) {
throw new IOException();
}
float x = Float.parseFloat(values[0]);
float y = Float.parseFloat(values[1]);
float z = -1;
String descr = null;
if (values.length > 3) {
z = Float.parseFloat(values[2]);
descr = values[3];
} else {
descr = values[2];
}
SmsData smsData = new SmsData();
if (data.startsWith("n:")) {
smsData.TYPE = SmsData.NOTE;
} else if (data.startsWith("b:")) {
smsData.TYPE = SmsData.BOOKMARK;
}
smsData.x = x;
smsData.y = y;
smsData.z = z;
smsData.text = descr;
smsDataList.add(smsData);
}
}
return smsDataList;
}
/**
* Checks if the device supports phone.
*
* @param context
* @return
*/
public static boolean hasPhone( Context context ) {
TelephonyManager telephonyManager1 = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
if (telephonyManager1.getPhoneType() == TelephonyManager.PHONE_TYPE_NONE) {
return false;
} else {
return true;
}
}
}