Added SMSTO support, added subject/body param support in mailto:, improved handling...
authorsrowen <srowen@59b500cc-1b3d-0410-9834-0bbf25fbcc57>
Fri, 23 May 2008 22:40:13 +0000 (22:40 +0000)
committersrowen <srowen@59b500cc-1b3d-0410-9834-0bbf25fbcc57>
Fri, 23 May 2008 22:40:13 +0000 (22:40 +0000)
git-svn-id: http://zxing.googlecode.com/svn/trunk@402 59b500cc-1b3d-0410-9834-0bbf25fbcc57

android-m3/src/com/google/zxing/client/android/ResultHandler.java
android/src/com/google/zxing/client/android/ResultHandler.java
core/src/com/google/zxing/client/result/EmailAddressParsedResult.java
core/src/com/google/zxing/client/result/EmailDoCoMoParsedResult.java
core/src/com/google/zxing/client/result/ParsedReaderResult.java
core/src/com/google/zxing/client/result/ParsedReaderResultType.java
core/src/com/google/zxing/client/result/SMSTOParsedResult.java [new file with mode: 0644]
core/src/com/google/zxing/client/result/TelParsedResult.java
javame/src/com/google/zxing/client/j2me/ZXingMIDlet.java

index 4c0ad9a..071eb38 100755 (executable)
@@ -19,7 +19,6 @@ package com.google.zxing.client.android;
 import android.content.Intent;
 import android.net.ContentURI;
 import android.provider.Contacts;
-import android.util.Log;
 import android.view.View;
 import android.widget.Button;
 import com.google.zxing.client.result.AddressBookAUParsedResult;
@@ -31,6 +30,7 @@ import com.google.zxing.client.result.GeoParsedResult;
 import com.google.zxing.client.result.ParsedReaderResult;
 import com.google.zxing.client.result.ParsedReaderResultType;
 import com.google.zxing.client.result.SMSParsedResult;
+import com.google.zxing.client.result.SMSTOParsedResult;
 import com.google.zxing.client.result.TelParsedResult;
 import com.google.zxing.client.result.UPCParsedResult;
 import com.google.zxing.client.result.URIParsedResult;
@@ -47,8 +47,6 @@ import java.net.URISyntaxException;
  */
 final class ResultHandler implements Button.OnClickListener {
 
-  private static final String TAG = "ResultHandler";
-
   private final Intent intent;
   private final BarcodeReaderCaptureActivity captureActivity;
 
@@ -90,7 +88,7 @@ final class ResultHandler implements Button.OnClickListener {
     } else if (type.equals(ParsedReaderResultType.EMAIL)) {
       EmailDoCoMoParsedResult emailResult = (EmailDoCoMoParsedResult) result;
       try {
-        intent = new Intent(Intent.SENDTO_ACTION, new ContentURI(emailResult.getTo()));
+        intent = new Intent(Intent.SENDTO_ACTION, new ContentURI(emailResult.getMailtoURI()));
       } catch (URISyntaxException e) {
       }
       putExtra(intent, "subject", emailResult.getSubject());
@@ -98,26 +96,33 @@ final class ResultHandler implements Button.OnClickListener {
     } else if (type.equals(ParsedReaderResultType.EMAIL_ADDRESS)) {
       EmailAddressParsedResult emailResult = (EmailAddressParsedResult) result;
       try {
-        intent = new Intent(Intent.SENDTO_ACTION, new ContentURI("mailto:" + emailResult.getEmailAddress()));
+        intent = new Intent(Intent.SENDTO_ACTION, new ContentURI(emailResult.getMailtoURI()));
       } catch (URISyntaxException e) {
       }
+      putExtra(intent, "subject", emailResult.getSubject());
+      putExtra(intent, "body", emailResult.getBody());
     } else if (type.equals(ParsedReaderResultType.SMS)) {
       SMSParsedResult smsResult = (SMSParsedResult) result;
       try {
         intent = new Intent(Intent.SENDTO_ACTION, new ContentURI(smsResult.getSMSURI()));
       } catch (URISyntaxException e) {
       }
+    } else if (type.equals(ParsedReaderResultType.SMSTO)) {
+      SMSTOParsedResult smsToResult = (SMSTOParsedResult) result;
+      try {
+        intent = new Intent(Intent.SENDTO_ACTION, new ContentURI(smsToResult.getSMSURI()));
+      } catch (URISyntaxException e) {
+      }
     } else if (type.equals(ParsedReaderResultType.TEL)) {
       TelParsedResult telResult = (TelParsedResult) result;
       try {
-        intent = new Intent(Intent.DIAL_ACTION, new ContentURI("tel:" + telResult.getNumber()));
+        intent = new Intent(Intent.DIAL_ACTION, new ContentURI(telResult.getTelURI()));
       } catch (URISyntaxException e) {
       }
     } else if (type.equals(ParsedReaderResultType.GEO)) {
       GeoParsedResult geoResult = (GeoParsedResult) result;
       try {
         ContentURI geoURI = new ContentURI(geoResult.getGeoURI());
-        Log.v(TAG, "Created geo URI: " + geoURI.toString());
         intent = new Intent(Intent.VIEW_ACTION, geoURI);
       } catch (URISyntaxException e) {
       }
index b9fb379..43edd6e 100755 (executable)
@@ -30,6 +30,7 @@ import com.google.zxing.client.result.GeoParsedResult;
 import com.google.zxing.client.result.ParsedReaderResult;
 import com.google.zxing.client.result.ParsedReaderResultType;
 import com.google.zxing.client.result.SMSParsedResult;
+import com.google.zxing.client.result.SMSTOParsedResult;
 import com.google.zxing.client.result.TelParsedResult;
 import com.google.zxing.client.result.UPCParsedResult;
 import com.google.zxing.client.result.URIParsedResult;
@@ -78,21 +79,23 @@ final class ResultHandler implements Button.OnClickListener {
       intent = new Intent(Intent.VIEW_ACTION, Uri.parse(((URLTOParsedResult) result).getURI()));
     } else if (type.equals(ParsedReaderResultType.EMAIL)) {
       EmailDoCoMoParsedResult emailResult = (EmailDoCoMoParsedResult) result;
-      intent = new Intent(Intent.SENDTO_ACTION, Uri.parse(emailResult.getTo()));
+      intent = new Intent(Intent.SENDTO_ACTION, Uri.parse(emailResult.getMailtoURI()));
       putExtra(intent, "subject", emailResult.getSubject());
       putExtra(intent, "body", emailResult.getBody());
     } else if (type.equals(ParsedReaderResultType.EMAIL_ADDRESS)) {
       EmailAddressParsedResult emailResult = (EmailAddressParsedResult) result;
-      intent = new Intent(Intent.SENDTO_ACTION, Uri.parse("mailto:" + emailResult.getEmailAddress()));
-    } else if (type.equals(ParsedReaderResultType.SMS)) {
-      SMSParsedResult smsResult = (SMSParsedResult) result;
-      intent = new Intent(Intent.SENDTO_ACTION, Uri.parse(smsResult.getSMSURI()));
+      intent = new Intent(Intent.SENDTO_ACTION, Uri.parse(emailResult.getMailtoURI()));
+      putExtra(intent, "subject", emailResult.getSubject());
+      putExtra(intent, "body", emailResult.getBody());
     } else if (type.equals(ParsedReaderResultType.SMS)) {
       SMSParsedResult smsResult = (SMSParsedResult) result;
       intent = new Intent(Intent.SENDTO_ACTION, Uri.parse(smsResult.getSMSURI()));
+    } else if (type.equals(ParsedReaderResultType.SMSTO)) {
+      SMSTOParsedResult smsToResult = (SMSTOParsedResult) result;
+      intent = new Intent(Intent.SENDTO_ACTION, Uri.parse(smsToResult.getSMSURI()));
     } else if (type.equals(ParsedReaderResultType.TEL)) {
       TelParsedResult telResult = (TelParsedResult) result;
-      intent = new Intent(Intent.DIAL_ACTION, Uri.parse("tel:" + telResult.getNumber()));
+      intent = new Intent(Intent.DIAL_ACTION, Uri.parse(telResult.getTelURI()));
     } else if (type.equals(ParsedReaderResultType.GEO)) {
       GeoParsedResult geoResult = (GeoParsedResult) result;
       intent = new Intent(Intent.VIEW_ACTION, Uri.parse(geoResult.getGeoURI()));
index fc334b6..5564e7c 100644 (file)
@@ -18,6 +18,8 @@ package com.google.zxing.client.result;
 
 import com.google.zxing.Result;
 
+import java.util.Hashtable;
+
 /**
  * Represents a result that encodes an e-mail address, either as a plain address
  * like "joe@example.org" or a mailto: URL like "mailto:joe@example.org".
@@ -27,31 +29,63 @@ import com.google.zxing.Result;
 public final class EmailAddressParsedResult extends AbstractDoCoMoParsedResult {
 
   private final String emailAddress;
+  private final String subject;
+  private final String body;
+  private final String mailtoURI;
 
-  private EmailAddressParsedResult(String emailAddress) {
+  private EmailAddressParsedResult(String emailAddress, String subject, String body, String mailtoURI) {
     super(ParsedReaderResultType.EMAIL_ADDRESS);
     this.emailAddress = emailAddress;
+    this.subject = subject;
+    this.body = body;
+    this.mailtoURI = mailtoURI;
   }
 
   public static EmailAddressParsedResult parse(Result result) {
     String rawText = result.getText();
+    if (rawText == null) {
+      return null;
+    }
     String emailAddress;
-    if (rawText != null && rawText.startsWith("mailto:")) {
+    if (rawText.startsWith("mailto:")) {
       // If it starts with mailto:, assume it is definitely trying to be an email address
       emailAddress = rawText.substring(7);
+      int queryStart = emailAddress.indexOf('?');
+      if (queryStart >= 0) {
+        emailAddress = emailAddress.substring(0, queryStart);
+      }
+      Hashtable nameValues = parseNameValuePairs(rawText);
+      if (emailAddress.length() == 0) {
+        emailAddress = (String) nameValues.get("to");
+      }
+      String subject = (String) nameValues.get("subject");
+      String body = (String) nameValues.get("body");
+      return new EmailAddressParsedResult(emailAddress, subject, body, rawText);
     } else {
       if (!EmailDoCoMoParsedResult.isBasicallyValidEmailAddress(rawText)) {
         return null;
       }
       emailAddress = rawText;
+      return new EmailAddressParsedResult(emailAddress, null, null, "mailto:" + emailAddress);
     }
-    return new EmailAddressParsedResult(emailAddress);
   }
 
   public String getEmailAddress() {
     return emailAddress;
   }
 
+  public String getSubject() {
+    return subject;
+  }
+
+  public String getBody() {
+    return body;
+  }
+
+  public String getMailtoURI() {
+    return mailtoURI;
+  }
+
   public String getDisplayResult() {
     return emailAddress;
   }
index d410e19..bad6d42 100644 (file)
@@ -68,6 +68,26 @@ public final class EmailDoCoMoParsedResult extends AbstractDoCoMoParsedResult {
     return body;
   }
 
+  public String getMailtoURI() {
+    StringBuffer result = new StringBuffer(to);
+    boolean hasParams = false;
+    if (subject != null) {
+      result.append(hasParams ? '&' : '?');
+      hasParams = true;
+      result.append("subject=");
+      result.append(subject);
+      // TODO we need to escape this?
+    }
+    if (body != null) {
+      result.append(hasParams ? '&' : '?');
+      hasParams = true;
+      result.append("body=");
+      result.append(body);
+      // TODO we need to escape this?
+    }
+    return result.toString();
+  }
+
   public String getDisplayResult() {
     StringBuffer result = new StringBuffer(to);
     maybeAppend(subject, result);
index 95bf734..0f7b41a 100644 (file)
@@ -18,6 +18,8 @@ package com.google.zxing.client.result;
 
 import com.google.zxing.Result;
 
+import java.util.Hashtable;
+
 /**
  * <p>Abstract class representing the result of decoding a barcode, as more than
  * a String -- as some type of structured data. This might be a subclass which represents
@@ -62,6 +64,8 @@ public abstract class ParsedReaderResult {
       return result;
     } else if ((result = SMSParsedResult.parse(theResult)) != null) {
       return result;
+    } else if ((result = SMSTOParsedResult.parse(theResult)) != null) {
+      return result;
     } else if ((result = GeoParsedResult.parse(theResult)) != null) {
       return result;
     } else if ((result = URLTOParsedResult.parse(theResult)) != null) {
@@ -70,12 +74,6 @@ public abstract class ParsedReaderResult {
       return result;
     } else if ((result = UPCParsedResult.parse(theResult)) != null) {
       return result;
-    //} else if ((result = NDEFTextParsedResult.parse(theResult)) != null) {
-    //  return result;
-    //} else if ((result = NDEFURIParsedResult.parse(theResult)) != null) {
-    //  return result;
-    //} else if ((result = NDEFSmartPosterParsedResult.parse(theResult)) != null) {
-    //  return result;
     }
     return TextParsedResult.parse(theResult);
   }
@@ -114,4 +112,109 @@ public abstract class ParsedReaderResult {
     return escaped;
   }
 
+  protected static String urlDecode(String escaped) {
+
+    // No we can't use java.net.URLDecoder here. JavaME doesn't have it.
+    if (escaped == null) {
+      return null;
+    }
+    char[] escapedArray = escaped.toCharArray();
+
+    int first = findFirstEscape(escapedArray);
+    if (first < 0) {
+      return escaped;
+    }
+
+    int max = escapedArray.length;
+    // final length is at most 2 less than original due to at least 1 unescaping
+    StringBuffer unescaped = new StringBuffer(max - 2);
+    // Can append everything up to first escape character
+    unescaped.append(escapedArray, 0, first);
+
+    for (int i = first; i < max; i++) {
+      char c = escapedArray[i];
+      if (c == '+') {
+        // + is translated directly into a space
+        unescaped.append(' ');
+      } else if (c == '%') {
+        // Are there even two more chars? if not we will just copy the escaped sequence and be done
+        if (i >= max - 2) {
+          unescaped.append('%'); // append that % and move on
+        } else {
+          int firstDigitValue = parseHexDigit(escapedArray[++i]);
+          int secondDigitValue = parseHexDigit(escapedArray[++i]);
+          if (firstDigitValue < 0 || secondDigitValue < 0) {
+            // bad digit, just move on
+            unescaped.append('%');
+            unescaped.append(escapedArray[i-1]);
+            unescaped.append(escapedArray[i]);
+          }
+          unescaped.append((char) ((firstDigitValue << 4) + secondDigitValue));
+        }
+      } else {
+        unescaped.append(c);
+      }
+    }
+    return unescaped.toString();
+  }
+
+  private static int findFirstEscape(char[] escapedArray) {
+    int max = escapedArray.length;
+    for (int i = 0; i < max; i++) {
+      char c = escapedArray[i];
+      if (c == '+' || c == '%') {
+        return i;
+      }
+    }
+    return -1;
+  }
+
+  private static int parseHexDigit(char c) {
+    if (c >= 'a') {
+      if (c <= 'f') {
+        return 10 + (c - 'a');
+      }
+    } else if (c >= 'A') {
+      if (c <= 'F') {
+        return 10 + (c - 'A');
+      }
+    } else if (c >= '0') {
+      if (c <= '9') {
+        return c - '0';
+      }
+    }
+    return -1;
+  }
+
+  protected static Hashtable parseNameValuePairs(String uri) {
+    int paramStart = uri.indexOf('?');
+    if (paramStart < 0) {
+      return null;
+    }
+    Hashtable result = new Hashtable(3);
+    paramStart++;
+    int paramEnd;
+    while ((paramEnd = uri.indexOf('&', paramStart)) >= 0) {
+      appendKeyValue(uri, paramStart, paramEnd, result);
+      paramStart = paramEnd + 1;
+    }
+    appendKeyValue(uri, paramStart, uri.length(), result);
+    return result;
+  }
+
+  private static void appendKeyValue(String uri, int paramStart, int paramEnd, Hashtable result) {
+    int separator = uri.indexOf('=', paramStart);
+    if (separator >= 0) {
+      // key = value
+      String key = uri.substring(paramStart, separator);
+      String value = uri.substring(separator + 1, paramEnd);
+      value = urlDecode(value);
+      result.put(key, value);
+    } else {
+      // key, no value
+      String key = uri.substring(paramStart, paramEnd);
+      result.put(key, null);
+    }
+  }
+
 }
index 815f4cf..91582cf 100644 (file)
@@ -37,6 +37,7 @@ public final class ParsedReaderResultType {
   public static final ParsedReaderResultType GEO = new ParsedReaderResultType("GEO");
   public static final ParsedReaderResultType TEL = new ParsedReaderResultType("TEL");
   public static final ParsedReaderResultType SMS = new ParsedReaderResultType("SMS");
+  public static final ParsedReaderResultType SMSTO = new ParsedReaderResultType("SMSTO");
   
   // "optional" types
   public static final ParsedReaderResultType NDEF_TEXT = new ParsedReaderResultType("NDEF_TEXT");
diff --git a/core/src/com/google/zxing/client/result/SMSTOParsedResult.java b/core/src/com/google/zxing/client/result/SMSTOParsedResult.java
new file mode 100644 (file)
index 0000000..6af68ab
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2008 Google Inc.
+ *
+ * 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;
+
+/**
+ * Represents a "SMSTO:" result, which specifies a number to SMS.
+ *
+ * @author srowen@google.com (Sean Owen)
+ */
+public final class SMSTOParsedResult extends ParsedReaderResult {
+
+  private final String number;
+
+  private SMSTOParsedResult(String number) {
+    super(ParsedReaderResultType.SMSTO);
+    this.number = number;
+  }
+
+  public static SMSTOParsedResult parse(Result result) {
+    String rawText = result.getText();
+    if (rawText == null || !rawText.startsWith("SMSTO:")) {
+      return null;
+    }
+    String number = rawText.substring(6);
+    return new SMSTOParsedResult(number);
+  }
+
+  public String getNumber() {
+    return number;
+  }
+
+  public String getDisplayResult() {
+    return number;
+  }
+
+  public String getSMSURI() {
+    return "sms:" + number;
+  }
+
+}
\ No newline at end of file
index 4b92786..1545031 100644 (file)
@@ -26,10 +26,12 @@ import com.google.zxing.Result;
 public final class TelParsedResult extends ParsedReaderResult {
 
   private final String number;
+  private final String telURI;
 
-  private TelParsedResult(String number) {
+  private TelParsedResult(String number, String telURI) {
     super(ParsedReaderResultType.TEL);
     this.number = number;
+    this.telURI = telURI;
   }
 
   public static TelParsedResult parse(Result result) {
@@ -37,6 +39,7 @@ public final class TelParsedResult extends ParsedReaderResult {
     if (rawText == null || !rawText.startsWith("tel:")) {
       return null;
     }
+    String telURI = rawText;
     // Drop tel, query portion
     int queryStart = rawText.indexOf('?', 4);
     if (queryStart < 0) {
@@ -44,13 +47,17 @@ public final class TelParsedResult extends ParsedReaderResult {
     } else {
       rawText = rawText.substring(4, queryStart);
     }
-    return new TelParsedResult(rawText);
+    return new TelParsedResult(rawText, telURI);
   }
 
   public String getNumber() {
     return number;
   }
 
+  public String getTelURI() {
+    return telURI;
+  }
+
   public String getDisplayResult() {
     return number;
   }
index faf238a..505fc32 100644 (file)
@@ -23,6 +23,7 @@ import com.google.zxing.client.result.EmailDoCoMoParsedResult;
 import com.google.zxing.client.result.ParsedReaderResult;
 import com.google.zxing.client.result.ParsedReaderResultType;
 import com.google.zxing.client.result.SMSParsedResult;
+import com.google.zxing.client.result.SMSTOParsedResult;
 import com.google.zxing.client.result.TelParsedResult;
 import com.google.zxing.client.result.UPCParsedResult;
 import com.google.zxing.client.result.URIParsedResult;
@@ -205,21 +206,24 @@ public final class ZXingMIDlet extends MIDlet {
       String uri = ((URLTOParsedResult) result).getURI();
       showOpenURL("Open Web Page?", uri, uri);
     } else if (type.equals(ParsedReaderResultType.EMAIL)) {
-      String email = ((EmailDoCoMoParsedResult) result).getTo();
-      showOpenURL("Compose E-mail?", email, "mailto:" + email);
+      EmailDoCoMoParsedResult emailResult = (EmailDoCoMoParsedResult) result;
+      showOpenURL("Compose E-mail?", emailResult.getTo(), emailResult.getMailtoURI());
     } else if (type.equals(ParsedReaderResultType.EMAIL_ADDRESS)) {
-      String email = ((EmailAddressParsedResult) result).getEmailAddress();
-      showOpenURL("Compose E-mail?", email, "mailto:" + email);
+      EmailAddressParsedResult emailResult = (EmailAddressParsedResult) result;
+      showOpenURL("Compose E-mail?", emailResult.getEmailAddress(), emailResult.getMailtoURI());
     } else if (type.equals(ParsedReaderResultType.SMS)) {
       SMSParsedResult smsResult = (SMSParsedResult) result;
       showOpenURL("Compose SMS?", smsResult.getNumber(), smsResult.getSMSURI());
+    } else if (type.equals(ParsedReaderResultType.SMSTO)) {
+      SMSTOParsedResult smsToResult = (SMSTOParsedResult) result;
+      showOpenURL("Compose SMS?", smsToResult.getNumber(), smsToResult.getSMSURI());
     } else if (type.equals(ParsedReaderResultType.UPC)) {
       String upc = ((UPCParsedResult) result).getUPC();
       String uri = "http://www.upcdatabase.com/item.asp?upc=" + upc;
       showOpenURL("Look Up Barcode Online?", upc, uri);
     } else if (type.equals(ParsedReaderResultType.TEL)) {
-      String number = ((TelParsedResult) result).getNumber();
-      showOpenURL("Dial Number?", number, "tel:" + number);
+      TelParsedResult telResult = (TelParsedResult) result;
+      showOpenURL("Dial Number?", telResult.getNumber(), telResult.getTelURI());
     } else {
       showAlert("Barcode Detected", result.getDisplayResult());
     }