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:
parent
1cf69e882a
commit
6384942c57
@ -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>
|
||||
|
@ -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'];
|
||||
}
|
||||
}
|
@ -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");
|
||||
|
@ -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
|
||||
|
@ -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");
|
||||
}
|
||||
|
26
src/org/envaya/sms/receiver/MessageDeliveryNotifier.java
Executable file
26
src/org/envaya/sms/receiver/MessageDeliveryNotifier.java
Executable 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
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user