SMSParsedResult smsResult = (SMSParsedResult) getResult();
switch (index) {
case 0:
- sendSMS(smsResult.getNumber(), smsResult.getBody());
+ // Don't know of a way yet to express a SENDTO intent with multiple recipients
+ sendSMS(smsResult.getNumbers()[0], smsResult.getBody());
break;
case 1:
- sendMMS(smsResult.getNumber(), smsResult.getSubject(), smsResult.getBody());
+ sendMMS(smsResult.getNumbers()[0], smsResult.getSubject(), smsResult.getBody());
break;
}
}
public CharSequence getDisplayContents() {
SMSParsedResult smsResult = (SMSParsedResult) getResult();
StringBuffer contents = new StringBuffer();
- ParsedResult.maybeAppend(PhoneNumberUtils.formatNumber(smsResult.getNumber()), contents);
- ParsedResult.maybeAppend(smsResult.getVia(), contents);
+ String[] rawNumbers = smsResult.getNumbers();
+ String[] formattedNumbers = new String[rawNumbers.length];
+ for (int i = 0; i < rawNumbers.length; i++) {
+ formattedNumbers[i] = PhoneNumberUtils.formatNumber(rawNumbers[i]);
+ }
+ ParsedResult.maybeAppend(formattedNumbers, contents);
ParsedResult.maybeAppend(smsResult.getSubject(), contents);
ParsedResult.maybeAppend(smsResult.getBody(), contents);
- ParsedResult.maybeAppend(smsResult.getTitle(), contents);
return contents.toString();
}
*/
public final class GeoParsedResult extends ParsedResult {
- private final String geoURI;
private final double latitude;
private final double longitude;
private final double altitude;
- GeoParsedResult(String geoURI, double latitude, double longitude, double altitude) {
+ GeoParsedResult(double latitude, double longitude, double altitude) {
super(ParsedResultType.GEO);
- this.geoURI = geoURI;
this.latitude = latitude;
this.longitude = longitude;
this.altitude = altitude;
}
public String getGeoURI() {
- return geoURI;
+ StringBuffer result = new StringBuffer();
+ result.append("geo:");
+ result.append(latitude);
+ result.append(',');
+ result.append(longitude);
+ if (altitude > 0) {
+ result.append(',');
+ result.append(altitude);
+ }
+ return result.toString();
}
/**
}
public String getDisplayResult() {
- StringBuffer result = new StringBuffer(50);
+ StringBuffer result = new StringBuffer();
result.append(latitude);
result.append(", ");
result.append(longitude);
- if (altitude > 0.0f) {
+ if (altitude > 0.0) {
result.append(", ");
result.append(altitude);
result.append('m');
double latitude, longitude, altitude;
try {
latitude = Double.parseDouble(geoURIWithoutQuery.substring(0, latitudeEnd));
+ if (latitude > 90.0 || latitude < -90.0) {
+ return null;
+ }
if (longitudeEnd < 0) {
longitude = Double.parseDouble(geoURIWithoutQuery.substring(latitudeEnd + 1));
altitude = 0.0;
longitude = Double.parseDouble(geoURIWithoutQuery.substring(latitudeEnd + 1, longitudeEnd));
altitude = Double.parseDouble(geoURIWithoutQuery.substring(longitudeEnd + 1));
}
+ if (longitude > 180.0 || longitude < -180.0 || altitude < 0) {
+ return null;
+ }
} catch (NumberFormatException nfe) {
return null;
}
- return new GeoParsedResult(rawText.startsWith("GEO:") ? "geo:" + rawText.substring(4) : rawText,
- latitude, longitude, altitude);
+ return new GeoParsedResult(latitude, longitude, altitude);
}
}
\ No newline at end of file
return result;
} else if ((result = SMSMMSResultParser.parse(theResult)) != null) {
return result;
+ } else if ((result = SMSTOMMSTOResultParser.parse(theResult)) != null) {
+ return result;
} else if ((result = GeoResultParser.parse(theResult)) != null) {
return result;
} else if ((result = URLTOResultParser.parse(theResult)) != null) {
import com.google.zxing.Result;
import java.util.Hashtable;
+import java.util.Vector;
/**
- * <p>Parses an "sms:" URI result, which specifies a number to SMS and optional
- * "via" number. See <a href="http://gbiv.com/protocols/uri/drafts/draft-antti-gsm-sms-url-04.txt">
- * the IETF draft</a> on this.</p>
+ * <p>Parses an "sms:" URI result, which specifies a number to SMS.
+ * See <a href="http://tools.ietf.org/html/rfc5724"> RFC 5724</a> on this.</p>
*
- * <p>This actually also parses URIs starting with "mms:", "smsto:", "mmsto:", "SMSTO:", and
- * "MMSTO:", and treats them all the same way, and effectively converts them to an "sms:" URI
- * for purposes of forwarding to the platform.</p>
+ * <p>This class supports "via" syntax for numbers, which is not part of the spec.
+ * For example "+12125551212;via=+12124440101" may appear as a number.
+ * It also supports a "subject" query parameter, which is not mentioned in the spec.
+ * These are included since they were mentioned in earlier IETF drafts and might be
+ * used.</p>
+ *
+ * <p>This actually also parses URIs starting with "mms:" and treats them all the same way,
+ * and effectively converts them to an "sms:" URI for purposes of forwarding to the platform.</p>
*
* @author Sean Owen
*/
if (rawText == null) {
return null;
}
- int prefixLength;
- if (rawText.startsWith("sms:") || rawText.startsWith("SMS:") ||
- rawText.startsWith("mms:") || rawText.startsWith("MMS:")) {
- prefixLength = 4;
- } else if (rawText.startsWith("smsto:") || rawText.startsWith("SMSTO:") ||
- rawText.startsWith("mmsto:") || rawText.startsWith("MMSTO:")) {
- prefixLength = 6;
- } else {
+ if (!(rawText.startsWith("sms:") || rawText.startsWith("SMS:") ||
+ rawText.startsWith("mms:") || rawText.startsWith("MMS:"))) {
return null;
}
}
// Drop sms, query portion
- int queryStart = rawText.indexOf('?', prefixLength);
+ int queryStart = rawText.indexOf('?', 4);
String smsURIWithoutQuery;
// If it's not query syntax, the question mark is part of the subject or message
if (queryStart < 0 || !querySyntax) {
- smsURIWithoutQuery = rawText.substring(prefixLength);
+ smsURIWithoutQuery = rawText.substring(4);
} else {
- smsURIWithoutQuery = rawText.substring(prefixLength, queryStart);
+ smsURIWithoutQuery = rawText.substring(4, queryStart);
}
- int numberEnd = smsURIWithoutQuery.indexOf(';');
- String number;
- String via;
+
+ int lastComma = -1;
+ int comma;
+ Vector numbers = new Vector(1);
+ Vector vias = new Vector(1);
+ while ((comma = smsURIWithoutQuery.indexOf(',', lastComma + 1)) > lastComma) {
+ String numberPart = smsURIWithoutQuery.substring(lastComma + 1, comma);
+ addNumberVia(numbers, vias, numberPart);
+ lastComma = comma;
+ }
+ addNumberVia(numbers, vias, smsURIWithoutQuery.substring(lastComma + 1));
+
+ return new SMSParsedResult(toStringArray(numbers), toStringArray(vias), subject, body);
+ }
+
+ private static void addNumberVia(Vector numbers, Vector vias, String numberPart) {
+ int numberEnd = numberPart.indexOf(';');
if (numberEnd < 0) {
- number = smsURIWithoutQuery;
- via = null;
+ numbers.addElement(numberPart);
+ vias.addElement(null);
} else {
- number = smsURIWithoutQuery.substring(0, numberEnd);
- String maybeVia = smsURIWithoutQuery.substring(numberEnd + 1);
+ numbers.addElement(numberPart.substring(0, numberEnd));
+ String maybeVia = numberPart.substring(numberEnd + 1);
+ String via;
if (maybeVia.startsWith("via=")) {
via = maybeVia.substring(4);
} else {
via = null;
}
+ vias.addElement(via);
}
-
- // Thanks to dominik.wild for suggesting this enhancement to support
- // smsto:number:body URIs
- if (body == null) {
- int bodyStart = number.indexOf(':');
- if (bodyStart >= 0) {
- body = number.substring(bodyStart + 1);
- number = number.substring(0, bodyStart);
- }
- }
- return new SMSParsedResult("sms:" + number, number, via, subject, body, null);
}
}
\ No newline at end of file
*/
public final class SMSParsedResult extends ParsedResult {
- private final String smsURI;
- private final String number;
- private final String via;
+ private final String[] numbers;
+ private final String[] vias;
private final String subject;
private final String body;
- private final String title;
- public SMSParsedResult(String smsURI, String number, String via, String subject, String body, String title) {
+ public SMSParsedResult(String number, String via, String subject, String body) {
super(ParsedResultType.SMS);
- this.smsURI = smsURI;
- this.number = number;
- this.via = via;
+ this.numbers = new String[] {number};
+ this.vias = new String[] {via};
+ this.subject = subject;
+ this.body = body;
+ }
+
+ public SMSParsedResult(String[] numbers, String[] vias, String subject, String body) {
+ super(ParsedResultType.SMS);
+ this.numbers = numbers;
+ this.vias = vias;
this.subject = subject;
this.body = body;
- this.title = title;
}
public String getSMSURI() {
- return smsURI;
+ StringBuffer result = new StringBuffer();
+ result.append("sms:");
+ boolean first = true;
+ for (int i = 0; i < numbers.length; i++) {
+ if (first) {
+ first = false;
+ } else {
+ result.append(',');
+ }
+ result.append(numbers[i]);
+ if (vias[i] != null) {
+ result.append(";via=");
+ result.append(vias[i]);
+ }
+ }
+ boolean hasBody = body != null;
+ boolean hasSubject = subject != null;
+ if (hasBody || hasSubject) {
+ result.append('?');
+ if (hasBody) {
+ result.append("body=");
+ result.append(body);
+ }
+ if (hasSubject) {
+ if (hasBody) {
+ result.append('&');
+ }
+ result.append("subject=");
+ result.append(subject);
+ }
+ }
+ return result.toString();
}
- public String getNumber() {
- return number;
+ public String[] getNumbers() {
+ return numbers;
}
- public String getVia() {
- return via;
+ public String[] getVias() {
+ return vias;
}
public String getSubject() {
return body;
}
- public String getTitle() {
- return title;
- }
-
public String getDisplayResult() {
StringBuffer result = new StringBuffer(100);
- maybeAppend(number, result);
- maybeAppend(via, result);
+ maybeAppend(numbers, result);
maybeAppend(subject, result);
maybeAppend(body, result);
- maybeAppend(title, result);
return result.toString();
}
--- /dev/null
+/*
+ * Copyright 2008 ZXing authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.zxing.client.result;
+
+import com.google.zxing.Result;
+
+/**
+ * <p>Parses an "smsto:" URI result, whose format is not standardized but appears to be like:
+ * <code>smsto:number(:body)</code>.</p>
+ *
+ * <p>This actually also parses URIs starting with "smsto:", "mmsto:", "SMSTO:", and
+ * "MMSTO:", and treats them all the same way, and effectively converts them to an "sms:" URI
+ * for purposes of forwarding to the platform.</p>
+ *
+ * @author Sean Owen
+ */
+final class SMSTOMMSTOResultParser extends ResultParser {
+
+ private SMSTOMMSTOResultParser() {
+ }
+
+ public static SMSParsedResult parse(Result result) {
+ String rawText = result.getText();
+ if (rawText == null) {
+ return null;
+ }
+ if (!(rawText.startsWith("smsto:") || rawText.startsWith("SMSTO:") ||
+ rawText.startsWith("mmsto:") || rawText.startsWith("MMSTO:"))) {
+ return null;
+ }
+ // Thanks to dominik.wild for suggesting this enhancement to support
+ // smsto:number:body URIs
+ String number = rawText.substring(6);
+ String body = null;
+ int bodyStart = number.indexOf(':');
+ if (bodyStart >= 0) {
+ body = number.substring(bodyStart + 1);
+ number = number.substring(0, bodyStart);
+ }
+ return new SMSParsedResult(number, null, null, body);
+ }
+
+}
\ No newline at end of file
public void testGeo() {
doTest("geo:1,2", 1.0, 2.0, 0.0);
- doTest("geo:100.33,-32.3344,3.35", 100.33, -32.3344, 3.35);
+ doTest("geo:80.33,-32.3344,3.35", 80.33, -32.3344, 3.35);
+ doTest("geo:-20.33,132.3344,0.01", -20.33, 132.3344, 0.01);
}
private static void doTest(String contents, double latitude, double longitude, double altitude) {
doTestResult("geo:1,2", "1.0, 2.0", ParsedResultType.GEO);
doTestResult("GEO:1,2", "1.0, 2.0", ParsedResultType.GEO);
doTestResult("geo:1,2,3", "1.0, 2.0, 3.0m", ParsedResultType.GEO);
- doTestResult("geo:100.33,-32.3344,3.35", "100.33, -32.3344, 3.35m", ParsedResultType.GEO);
+ doTestResult("geo:80.33,-32.3344,3.35", "80.33, -32.3344, 3.35m", ParsedResultType.GEO);
doTestResult("geo", "geo", ParsedResultType.TEXT);
doTestResult("geography", "geography", ParsedResultType.TEXT);
}
public void testSMS() {
doTestResult("sms:+15551212", "+15551212", ParsedResultType.SMS);
doTestResult("SMS:+15551212", "+15551212", ParsedResultType.SMS);
+ doTestResult("sms:+15551212;via=999333", "+15551212", ParsedResultType.SMS);
+ doTestResult("sms:+15551212?subject=foo&body=bar", "+15551212\nfoo\nbar", ParsedResultType.SMS);
+ doTestResult("sms:+15551212,+12124440101", "+15551212\n+12124440101", ParsedResultType.SMS);
+ }
+
+ public void testSMSTO() {
doTestResult("SMSTO:+15551212", "+15551212", ParsedResultType.SMS);
doTestResult("smsto:+15551212", "+15551212", ParsedResultType.SMS);
- doTestResult("sms:+15551212;via=999333", "+15551212\n999333", ParsedResultType.SMS);
- doTestResult("sms:+15551212?subject=foo&body=bar", "+15551212\nfoo\nbar", ParsedResultType.SMS);
- doTestResult("sms:+15551212:subject", "+15551212\nsubject", ParsedResultType.SMS);
- doTestResult("sms:+15551212:My message", "+15551212\nMy message", ParsedResultType.SMS);
+ doTestResult("smsto:+15551212:subject", "+15551212\nsubject", ParsedResultType.SMS);
+ doTestResult("smsto:+15551212:My message", "+15551212\nMy message", ParsedResultType.SMS);
// Need to handle question mark in the subject
- doTestResult("sms:+15551212:What's up?", "+15551212\nWhat's up?", ParsedResultType.SMS);
+ doTestResult("smsto:+15551212:What's up?", "+15551212\nWhat's up?", ParsedResultType.SMS);
// Need to handle colon in the subject
- doTestResult("sms:+15551212:Directions: Do this", "+15551212\nDirections: Do this",
+ doTestResult("smsto:+15551212:Directions: Do this", "+15551212\nDirections: Do this",
ParsedResultType.SMS);
- doTestResult("sms:212-555-1212:Here's a longer message. Should be fine.",
+ doTestResult("smsto:212-555-1212:Here's a longer message. Should be fine.",
"212-555-1212\nHere's a longer message. Should be fine.",
ParsedResultType.SMS);
}
public void testMMS() {
doTestResult("mms:+15551212", "+15551212", ParsedResultType.SMS);
doTestResult("MMS:+15551212", "+15551212", ParsedResultType.SMS);
+ doTestResult("mms:+15551212;via=999333", "+15551212", ParsedResultType.SMS);
+ doTestResult("mms:+15551212?subject=foo&body=bar", "+15551212\nfoo\nbar", ParsedResultType.SMS);
+ doTestResult("mms:+15551212,+12124440101", "+15551212\n+12124440101", ParsedResultType.SMS);
+ }
+
+ public void testMMSTO() {
doTestResult("MMSTO:+15551212", "+15551212", ParsedResultType.SMS);
doTestResult("mmsto:+15551212", "+15551212", ParsedResultType.SMS);
- doTestResult("mms:+15551212;via=999333", "+15551212\n999333", ParsedResultType.SMS);
- doTestResult("mms:+15551212?subject=foo&body=bar", "+15551212\nfoo\nbar", ParsedResultType.SMS);
- doTestResult("mms:+15551212:subject", "+15551212\nsubject", ParsedResultType.SMS);
- doTestResult("mms:+15551212:My message", "+15551212\nMy message", ParsedResultType.SMS);
- doTestResult("mms:+15551212:What's up?", "+15551212\nWhat's up?", ParsedResultType.SMS);
- doTestResult("mms:+15551212:Directions: Do this", "+15551212\nDirections: Do this",
+ doTestResult("mmsto:+15551212:subject", "+15551212\nsubject", ParsedResultType.SMS);
+ doTestResult("mmsto:+15551212:My message", "+15551212\nMy message", ParsedResultType.SMS);
+ doTestResult("mmsto:+15551212:What's up?", "+15551212\nWhat's up?", ParsedResultType.SMS);
+ doTestResult("mmsto:+15551212:Directions: Do this", "+15551212\nDirections: Do this",
ParsedResultType.SMS);
- doTestResult("mms:212-555-1212:Here's a longer message. Should be fine.",
+ doTestResult("mmsto:212-555-1212:Here's a longer message. Should be fine.",
"212-555-1212\nHere's a longer message. Should be fine.", ParsedResultType.SMS);
}
import com.google.zxing.Result;
import junit.framework.TestCase;
+import java.util.Arrays;
+
/**
* Tests {@link SMSParsedResult}.
*
}
private static void doTest(String contents, String number, String subject, String body, String via) {
+ doTest(contents, new String[] {number}, subject, body, new String[] {via});
+ }
+
+ private static void doTest(String contents, String[] numbers, String subject, String body, String[] vias) {
Result fakeResult = new Result(contents, null, null, BarcodeFormat.QR_CODE);
ParsedResult result = ResultParser.parseResult(fakeResult);
assertSame(ParsedResultType.SMS, result.getType());
SMSParsedResult smsResult = (SMSParsedResult) result;
- assertEquals(number, smsResult.getNumber());
+ assertTrue(Arrays.equals(numbers, smsResult.getNumbers()));
assertEquals(subject, smsResult.getSubject());
assertEquals(body, smsResult.getBody());
- assertEquals(via, smsResult.getVia());
- assertEquals("sms:" + number, smsResult.getSMSURI());
+ assertTrue(Arrays.equals(vias, smsResult.getVias()));
}
}