5
0
mirror of https://github.com/cwinfo/envayasms.git synced 2024-12-04 12:35:32 +00:00

handle sending and receiving multipart sms messages > 160 chars

This commit is contained in:
Jesse Young 2011-09-23 23:00:51 -07:00
parent 1cf69e882a
commit 6384942c57
10 changed files with 180 additions and 49 deletions

View File

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.envaya.sms"
android:versionCode="6"
android:versionName="2.0-beta 4">
android:versionCode="7"
android:versionName="2.0-beta 5">
<uses-sdk android:minSdkVersion="4" />
@ -56,6 +56,17 @@
<data android:scheme="content" />
</intent-filter>
</receiver>
<!--
we don't really use message delivery notifications yet...
<receiver android:name=".receiver.MessageDeliveryNotifier" android:exported="true">
<intent-filter>
<action android:name="org.envaya.sms.MESSAGE_DELIVERY" />
<data android:scheme="content" />
</intent-filter>
</receiver>
-->
<receiver android:name=".receiver.OutgoingMessagePoller">
</receiver>

View File

@ -228,6 +228,7 @@ class EnvayaSMS_Action_SendStatus extends EnvayaSMS_Action
{
public $status; // EnvayaSMS::STATUS_* values
public $id; // server ID previously used in EnvayaSMS_OutgoingMessage
public $error; // textual descrption of error (if applicable)
function __construct($request)
{
@ -235,5 +236,6 @@ class EnvayaSMS_Action_SendStatus extends EnvayaSMS_Action
$this->type = EnvayaSMS::ACTION_SEND_STATUS;
$this->status = $_POST['status'];
$this->id = $_POST['id'];
$this->error = $_POST['error'];
}
}

View File

@ -72,6 +72,10 @@ public final class App extends Application {
// intent for MessageStatusNotifier to receive status updates for outgoing SMS
// (even if sent by an expansion pack)
public static final String MESSAGE_STATUS_INTENT = "org.envaya.sms.MESSAGE_STATUS";
public static final String MESSAGE_DELIVERY_INTENT = "org.envaya.sms.MESSAGE_DELIVERY";
public static final String STATUS_EXTRA_INDEX = "status";
public static final String STATUS_EXTRA_NUM_PARTS = "num_parts";
public static final int MAX_DISPLAYED_LOG = 4000;
public static final int LOG_TIMESTAMP_INTERVAL = 60000;
@ -180,7 +184,7 @@ public final class App extends Application {
}
public synchronized String chooseOutgoingSmsPackage()
public synchronized String chooseOutgoingSmsPackage(int numParts)
{
outgoingMessageCount++;
@ -211,9 +215,13 @@ public final class App extends Application {
sent.remove(0);
}
if ( (sent.size() + 1) <= OUTGOING_SMS_MAX_COUNT)
if ( (sent.size() + numParts) <= OUTGOING_SMS_MAX_COUNT)
{
sent.add(ct);
// each part counts towards message limit
for (int j = 0; j < numParts; j++)
{
sent.add(ct);
}
return packageName;
}
}
@ -422,12 +430,18 @@ public final class App extends Application {
}
}
public synchronized void notifyOutgoingMessageStatus(Uri uri, int resultCode) {
public synchronized void notifyOutgoingMessageStatus(Uri uri, int resultCode, int partIndex, int numParts) {
OutgoingMessage sms = outgoingMessages.get(uri);
if (sms == null) {
return;
}
if (partIndex != 0)
{
// TODO: process message status for parts other than the first one
return;
}
switch (resultCode) {
case Activity.RESULT_OK:
@ -466,15 +480,31 @@ public final class App extends Application {
public synchronized void sendOutgoingMessage(OutgoingMessage sms) {
if (isTestMode() && !isTestPhoneNumber(sms.getTo()))
String to = sms.getTo();
if (to == null || to.length() == 0)
{
log("Ignoring outgoing SMS; destination is empty");
return;
}
if (isTestMode() && !isTestPhoneNumber(to))
{
// this is mostly to prevent accidentally sending real messages to
// random people while testing...
log("Ignoring outgoing SMS to " + sms.getTo());
log("Ignoring outgoing SMS to " + to);
return;
}
String messageBody = sms.getMessageBody();
if (messageBody == null || messageBody.length() == 0)
{
log("Ignoring outgoing SMS; message body is empty");
return;
}
Uri uri = sms.getUri();
if (outgoingMessages.containsKey(uri)) {
log("Duplicate outgoing " + sms.getLogName() + ", skipping");

View File

@ -3,6 +3,8 @@ package org.envaya.sms;
import android.net.Uri;
import android.telephony.SmsMessage;
import java.security.InvalidParameterException;
import java.util.List;
import org.apache.http.message.BasicNameValuePair;
import org.envaya.sms.task.ForwarderTask;
@ -13,10 +15,27 @@ public class IncomingSms extends IncomingMessage {
protected long timestampMillis;
// constructor for SMS retrieved from android.provider.Telephony.SMS_RECEIVED intent
public IncomingSms(App app, SmsMessage sms) {
super(app, sms.getOriginatingAddress());
this.message = sms.getMessageBody();
this.timestampMillis = sms.getTimestampMillis();
public IncomingSms(App app, List<SmsMessage> smsParts) throws InvalidParameterException {
super(app, smsParts.get(0).getOriginatingAddress());
this.message = smsParts.get(0).getMessageBody();
int numParts = smsParts.size();
for (int i = 1; i < numParts; i++)
{
SmsMessage smsPart = smsParts.get(i);
if (!smsPart.getOriginatingAddress().equals(from))
{
throw new InvalidParameterException(
"Tried to create IncomingSms from two different senders");
}
message = message + smsPart.getMessageBody();
}
this.timestampMillis = smsParts.get(0).getTimestampMillis();
}
// constructor for SMS retrieved from Messaging inbox

View File

@ -4,6 +4,8 @@ package org.envaya.sms;
import org.envaya.sms.receiver.OutgoingMessageRetry;
import android.content.Intent;
import android.net.Uri;
import android.telephony.SmsManager;
import java.util.ArrayList;
public class OutgoingMessage extends QueuedMessage {
@ -12,10 +14,11 @@ public class OutgoingMessage extends QueuedMessage {
private String from;
private String to;
private String localId;
private String localId;
private static int nextLocalId = 1;
public OutgoingMessage(App app)
{
super(app);
@ -84,7 +87,10 @@ public class OutgoingMessage extends QueuedMessage {
public void trySend()
{
String packageName = app.chooseOutgoingSmsPackage();
SmsManager smgr = SmsManager.getDefault();
ArrayList<String> bodyParts = smgr.divideMessage(getMessageBody());
String packageName = app.chooseOutgoingSmsPackage(bodyParts.size());
if (packageName == null)
{
@ -94,7 +100,7 @@ public class OutgoingMessage extends QueuedMessage {
Intent intent = new Intent(packageName + App.OUTGOING_SMS_INTENT_SUFFIX, this.getUri());
intent.putExtra(App.OUTGOING_SMS_EXTRA_TO, getTo());
intent.putExtra(App.OUTGOING_SMS_EXTRA_BODY, getMessageBody());
intent.putExtra(App.OUTGOING_SMS_EXTRA_BODY, bodyParts);
app.sendBroadcast(intent, "android.permission.SEND_SMS");
}

View File

@ -0,0 +1,26 @@
package org.envaya.sms.receiver;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import org.envaya.sms.App;
public class MessageDeliveryNotifier extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
App app = (App) context.getApplicationContext();
Uri uri = intent.getData();
Bundle extras = intent.getExtras();
int index = extras.getInt(App.STATUS_EXTRA_INDEX);
int numParts = extras.getInt(App.STATUS_EXTRA_NUM_PARTS);
app.log("Message " + uri + " part "+index + "/" + numParts + " delivered");
// todo... could notify the server of message delivery
}
}

View File

@ -8,6 +8,7 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import org.envaya.sms.App;
public class MessageStatusNotifier extends BroadcastReceiver {
@ -16,6 +17,10 @@ public class MessageStatusNotifier extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
App app = (App) context.getApplicationContext();
Uri uri = intent.getData();
Bundle extras = intent.getExtras();
int index = extras.getInt(App.STATUS_EXTRA_INDEX);
int numParts = extras.getInt(App.STATUS_EXTRA_NUM_PARTS);
int resultCode = getResultCode();
@ -27,6 +32,6 @@ public class MessageStatusNotifier extends BroadcastReceiver {
}
*/
app.notifyOutgoingMessageStatus(uri, resultCode);
app.notifyOutgoingMessageStatus(uri, resultCode, index, numParts);
}
}

View File

@ -1,12 +1,13 @@
package org.envaya.sms.receiver;
import org.envaya.sms.App;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.telephony.SmsManager;
import org.envaya.sms.App;
import java.util.ArrayList;
public class OutgoingSmsReceiver extends BroadcastReceiver {
@Override
@ -14,18 +15,38 @@ public class OutgoingSmsReceiver extends BroadcastReceiver {
{
Bundle extras = intent.getExtras();
String to = extras.getString(App.OUTGOING_SMS_EXTRA_TO);
String body = extras.getString(App.OUTGOING_SMS_EXTRA_BODY);
ArrayList<String> bodyParts = extras.getStringArrayList(App.OUTGOING_SMS_EXTRA_BODY);
SmsManager smgr = SmsManager.getDefault();
Intent statusIntent = new Intent(App.MESSAGE_STATUS_INTENT, intent.getData());
PendingIntent sentIntent = PendingIntent.getBroadcast(
ArrayList<PendingIntent> sentIntents = new ArrayList<PendingIntent>();
ArrayList<PendingIntent> deliveryIntents = new ArrayList<PendingIntent>();
int numParts = bodyParts.size();
for (int i = 0; i < numParts; i++)
{
Intent statusIntent = new Intent(App.MESSAGE_STATUS_INTENT, intent.getData());
statusIntent.putExtra(App.STATUS_EXTRA_INDEX, i);
statusIntent.putExtra(App.STATUS_EXTRA_NUM_PARTS, numParts);
sentIntents.add(PendingIntent.getBroadcast(
context,
0,
statusIntent,
PendingIntent.FLAG_ONE_SHOT);
PendingIntent.FLAG_ONE_SHOT));
smgr.sendTextMessage(to, null, body, sentIntent, null);
Intent deliveryIntent = new Intent(App.MESSAGE_DELIVERY_INTENT, intent.getData());
deliveryIntent.putExtra(App.STATUS_EXTRA_INDEX, i);
deliveryIntent.putExtra(App.STATUS_EXTRA_NUM_PARTS, numParts);
deliveryIntents.add(PendingIntent.getBroadcast(
context,
0,
deliveryIntent,
PendingIntent.FLAG_ONE_SHOT));
}
smgr.sendMultipartTextMessage(to, null, bodyParts, sentIntents, deliveryIntents);
}
}
}

View File

@ -6,7 +6,9 @@ import android.content.Intent;
import android.os.Bundle;
import android.telephony.SmsMessage;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.envaya.sms.App;
import org.envaya.sms.IncomingMessage;
import org.envaya.sms.IncomingSms;
@ -17,7 +19,6 @@ public class SmsReceiver extends BroadcastReceiver {
private App app;
@Override
// source: http://www.devx.com/wireless/Article/39495/1954
public void onReceive(Context context, Intent intent) {
app = (App) context.getApplicationContext();
@ -27,42 +28,46 @@ public class SmsReceiver extends BroadcastReceiver {
}
try {
boolean hasUnhandledMessage = false;
IncomingMessage sms = getMessageFromIntent(intent);
if (sms.isForwardable())
{
app.forwardToServer(sms);
for (IncomingMessage sms : getMessagesFromIntent(intent)) {
if (sms.isForwardable())
{
app.forwardToServer(sms);
}
else
if (!app.getKeepInInbox())
{
app.log("Ignoring incoming SMS from " + sms.getFrom());
hasUnhandledMessage = true;
}
this.abortBroadcast();
}
}
if (!hasUnhandledMessage && !app.getKeepInInbox())
else
{
this.abortBroadcast();
app.log("Ignoring incoming SMS from " + sms.getFrom());
}
} catch (Throwable ex) {
app.logError("Unexpected error in SmsReceiver", ex, true);
}
}
// from http://github.com/dimagi/rapidandroid
// source: http://www.devx.com/wireless/Article/39495/1954
private List<IncomingMessage> getMessagesFromIntent(Intent intent)
private IncomingMessage getMessageFromIntent(Intent intent)
{
Bundle bundle = intent.getExtras();
List<IncomingMessage> messages = new ArrayList<IncomingMessage>();
// SMSDispatcher may send us multiple pdus from a multipart sms,
// in order (all in one broadcast though)
// The comments in the gtalksms app indicate that we could get PDUs
// from multiple different senders at once, but I don't see how this
// could happen by looking at the SMSDispatcher source code...
// so I'm going to assume it doesn't happen and throw an exception if
// it does.
List<SmsMessage> smsParts = new ArrayList<SmsMessage>();
for (Object pdu : (Object[]) bundle.get("pdus"))
{
SmsMessage sms = SmsMessage.createFromPdu((byte[]) pdu);
messages.add(new IncomingSms(app, sms));
smsParts.add(SmsMessage.createFromPdu((byte[]) pdu));
}
return messages;
return new IncomingSms(app, smsParts);
}
}

View File

@ -217,7 +217,6 @@ public class HttpTask extends AsyncTask<String, Void, HttpResponse> {
try
{
handleResponse(response);
response.getEntity().consumeContent();
}
catch (Throwable ex)
{
@ -225,6 +224,13 @@ public class HttpTask extends AsyncTask<String, Void, HttpResponse> {
app.logError("Error processing server response", ex);
handleFailure();
}
try
{
response.getEntity().consumeContent();
}
catch (IOException ex)
{
}
}
else
{