mirror of
https://github.com/cwinfo/envayasms.git
synced 2024-11-09 10:20:25 +00:00
support for incoming MMS
This commit is contained in:
parent
60d49414e1
commit
d994b10c35
@ -33,19 +33,12 @@
|
|||||||
android:label="@string/app_name">
|
android:label="@string/app_name">
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<receiver android:name=".receiver.SMSReceiver">
|
<receiver android:name=".receiver.SmsReceiver">
|
||||||
<intent-filter android:priority="101">
|
<intent-filter android:priority="101">
|
||||||
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
|
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</receiver>
|
</receiver>
|
||||||
|
|
||||||
<receiver android:name=".receiver.MMSReceiver">
|
|
||||||
<intent-filter android:priority="101">
|
|
||||||
<action android:name="android.provider.Telephony.WAP_PUSH_RECEIVED" />
|
|
||||||
<data android:mimeType="application/vnd.wap.mms-message" />
|
|
||||||
</intent-filter>
|
|
||||||
</receiver>
|
|
||||||
|
|
||||||
<receiver android:name=".receiver.MessageStatusNotifier">
|
<receiver android:name=".receiver.MessageStatusNotifier">
|
||||||
</receiver>
|
</receiver>
|
||||||
|
|
||||||
@ -63,5 +56,8 @@
|
|||||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</receiver>
|
</receiver>
|
||||||
|
|
||||||
|
<service android:name=".CheckMmsInboxService">
|
||||||
|
</service>
|
||||||
</application>
|
</application>
|
||||||
</manifest>
|
</manifest>
|
BIN
libs/httpmime-4.1.2.jar
Executable file
BIN
libs/httpmime-4.1.2.jar
Executable file
Binary file not shown.
@ -42,4 +42,5 @@
|
|||||||
android:summaryOff="Incoming SMS will not be stored in Messaging inbox"
|
android:summaryOff="Incoming SMS will not be stored in Messaging inbox"
|
||||||
android:summaryOn="Incoming SMS will be stored in Messaging inbox"
|
android:summaryOn="Incoming SMS will be stored in Messaging inbox"
|
||||||
></CheckBoxPreference>
|
></CheckBoxPreference>
|
||||||
|
|
||||||
</PreferenceScreen>
|
</PreferenceScreen>
|
@ -10,9 +10,11 @@ import android.app.PendingIntent;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
|
import android.net.Uri;
|
||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
import android.telephony.SmsManager;
|
import android.telephony.SmsManager;
|
||||||
|
import android.text.Html;
|
||||||
import android.text.SpannableStringBuilder;
|
import android.text.SpannableStringBuilder;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import java.text.DateFormat;
|
import java.text.DateFormat;
|
||||||
@ -26,23 +28,55 @@ public final class App extends Application {
|
|||||||
public static final String ACTION_OUTGOING = "outgoing";
|
public static final String ACTION_OUTGOING = "outgoing";
|
||||||
public static final String ACTION_INCOMING = "incoming";
|
public static final String ACTION_INCOMING = "incoming";
|
||||||
public static final String ACTION_SEND_STATUS = "send_status";
|
public static final String ACTION_SEND_STATUS = "send_status";
|
||||||
|
|
||||||
public static final String STATUS_QUEUED = "queued";
|
public static final String STATUS_QUEUED = "queued";
|
||||||
public static final String STATUS_FAILED = "failed";
|
public static final String STATUS_FAILED = "failed";
|
||||||
public static final String STATUS_SENT = "sent";
|
public static final String STATUS_SENT = "sent";
|
||||||
|
|
||||||
|
public static final String MESSAGE_TYPE_MMS = "mms";
|
||||||
|
public static final String MESSAGE_TYPE_SMS = "sms";
|
||||||
|
|
||||||
public static final String LOG_NAME = "KALSMS";
|
public static final String LOG_NAME = "KALSMS";
|
||||||
public static final String LOG_INTENT = "org.envaya.kalsms.LOG";
|
public static final String LOG_INTENT = "org.envaya.kalsms.LOG";
|
||||||
|
|
||||||
public static final int MAX_DISPLAYED_LOG = 15000;
|
public static final int MAX_DISPLAYED_LOG = 15000;
|
||||||
public static final int LOG_TIMESTAMP_INTERVAL = 60000;
|
public static final int LOG_TIMESTAMP_INTERVAL = 60000;
|
||||||
|
|
||||||
private long lastLogTime = 0;
|
// Each QueuedMessage is identified within our internal Map by its Uri.
|
||||||
private SpannableStringBuilder displayedLog = new SpannableStringBuilder();
|
// Currently QueuedMessage instances are only available within KalSMS,
|
||||||
private Map<String, IncomingMessage> incomingSmsMap = new HashMap<String, IncomingMessage>();
|
// (but they could be made available to other applications later via a ContentProvider)
|
||||||
private Map<String, OutgoingMessage> outgoingSmsMap = new HashMap<String, OutgoingMessage>();
|
public static final Uri CONTENT_URI = Uri.parse("content://org.envaya.kalsms");
|
||||||
|
public static final Uri INCOMING_URI = Uri.withAppendedPath(CONTENT_URI, "incoming");
|
||||||
|
public static final Uri OUTGOING_URI = Uri.withAppendedPath(CONTENT_URI, "outgoing");
|
||||||
|
|
||||||
public SharedPreferences getSettings()
|
private Map<Uri, IncomingMessage> incomingMessages = new HashMap<Uri, IncomingMessage>();
|
||||||
|
private Map<Uri, OutgoingMessage> outgoingMessages = new HashMap<Uri, OutgoingMessage>();
|
||||||
|
|
||||||
|
private SharedPreferences settings;
|
||||||
|
private MmsObserver mmsObserver;
|
||||||
|
private SpannableStringBuilder displayedLog = new SpannableStringBuilder();
|
||||||
|
private long lastLogTime;
|
||||||
|
|
||||||
|
private MmsUtils mmsUtils;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate()
|
||||||
{
|
{
|
||||||
return PreferenceManager.getDefaultSharedPreferences(this);
|
super.onCreate();
|
||||||
|
|
||||||
|
settings = PreferenceManager.getDefaultSharedPreferences(this);
|
||||||
|
mmsUtils = new MmsUtils(this);
|
||||||
|
|
||||||
|
log(Html.fromHtml(
|
||||||
|
isEnabled() ? "<b>SMS gateway running.</b>" : "<b>SMS gateway disabled.</b>"));
|
||||||
|
|
||||||
|
log("Server URL is: " + getDisplayString(getServerUrl()));
|
||||||
|
log("Your phone number is: " + getDisplayString(getPhoneNumber()));
|
||||||
|
|
||||||
|
mmsObserver = new MmsObserver(this);
|
||||||
|
mmsObserver.register();
|
||||||
|
|
||||||
|
setOutgoingMessageAlarm();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void checkOutgoingMessages()
|
public void checkOutgoingMessages()
|
||||||
@ -92,29 +126,29 @@ public final class App extends Application {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public String getServerUrl() {
|
public String getServerUrl() {
|
||||||
return getSettings().getString("server_url", "");
|
return settings.getString("server_url", "");
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getPhoneNumber() {
|
public String getPhoneNumber() {
|
||||||
return getSettings().getString("phone_number", "");
|
return settings.getString("phone_number", "");
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getOutgoingPollSeconds() {
|
public int getOutgoingPollSeconds() {
|
||||||
return Integer.parseInt(getSettings().getString("outgoing_interval", "0"));
|
return Integer.parseInt(settings.getString("outgoing_interval", "0"));
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isEnabled()
|
public boolean isEnabled()
|
||||||
{
|
{
|
||||||
return getSettings().getBoolean("enabled", false);
|
return settings.getBoolean("enabled", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean getKeepInInbox()
|
public boolean getKeepInInbox()
|
||||||
{
|
{
|
||||||
return getSettings().getBoolean("keep_in_inbox", false);
|
return settings.getBoolean("keep_in_inbox", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getPassword() {
|
public String getPassword() {
|
||||||
return getSettings().getString("password", "");
|
return settings.getString("password", "");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void notifyStatus(OutgoingMessage sms, String status, String errorMessage) {
|
private void notifyStatus(OutgoingMessage sms, String status, String errorMessage) {
|
||||||
@ -150,35 +184,45 @@ public final class App extends Application {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public synchronized int getStuckMessageCount() {
|
public synchronized int getStuckMessageCount() {
|
||||||
return outgoingSmsMap.size() + incomingSmsMap.size();
|
return outgoingMessages.size() + incomingMessages.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void retryStuckOutgoingMessages() {
|
public synchronized void retryStuckOutgoingMessages() {
|
||||||
for (OutgoingMessage sms : outgoingSmsMap.values()) {
|
for (OutgoingMessage sms : outgoingMessages.values()) {
|
||||||
sms.retryNow();
|
sms.retryNow();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void retryStuckIncomingMessages() {
|
public synchronized void retryStuckIncomingMessages() {
|
||||||
for (IncomingMessage sms : incomingSmsMap.values()) {
|
for (IncomingMessage sms : incomingMessages.values()) {
|
||||||
sms.retryNow();
|
sms.retryNow();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void setIncomingMessageStatus(IncomingMessage sms, boolean success) {
|
public synchronized void setIncomingMessageStatus(IncomingMessage message, boolean success) {
|
||||||
String id = sms.getId();
|
Uri uri = message.getUri();
|
||||||
if (success)
|
if (success)
|
||||||
{
|
{
|
||||||
incomingSmsMap.remove(id);
|
incomingMessages.remove(uri);
|
||||||
}
|
|
||||||
else if (!sms.scheduleRetry())
|
if (message instanceof IncomingMms)
|
||||||
{
|
{
|
||||||
incomingSmsMap.remove(id);
|
IncomingMms mms = (IncomingMms)message;
|
||||||
|
if (!getKeepInInbox())
|
||||||
|
{
|
||||||
|
log("Deleting MMS " + mms.getId() + " from inbox...");
|
||||||
|
mmsUtils.deleteFromInbox(mms);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!message.scheduleRetry())
|
||||||
|
{
|
||||||
|
incomingMessages.remove(uri);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void notifyOutgoingMessageStatus(String id, int resultCode) {
|
public synchronized void notifyOutgoingMessageStatus(Uri uri, int resultCode) {
|
||||||
OutgoingMessage sms = outgoingSmsMap.get(id);
|
OutgoingMessage sms = outgoingMessages.get(uri);
|
||||||
|
|
||||||
if (sms == null) {
|
if (sms == null) {
|
||||||
return;
|
return;
|
||||||
@ -210,52 +254,52 @@ public final class App extends Application {
|
|||||||
case SmsManager.RESULT_ERROR_RADIO_OFF:
|
case SmsManager.RESULT_ERROR_RADIO_OFF:
|
||||||
case SmsManager.RESULT_ERROR_NO_SERVICE:
|
case SmsManager.RESULT_ERROR_NO_SERVICE:
|
||||||
if (!sms.scheduleRetry()) {
|
if (!sms.scheduleRetry()) {
|
||||||
outgoingSmsMap.remove(id);
|
outgoingMessages.remove(uri);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
outgoingSmsMap.remove(id);
|
outgoingMessages.remove(uri);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void sendOutgoingMessage(OutgoingMessage sms) {
|
public synchronized void sendOutgoingMessage(OutgoingMessage sms) {
|
||||||
String id = sms.getId();
|
Uri uri = sms.getUri();
|
||||||
if (outgoingSmsMap.containsKey(id)) {
|
if (outgoingMessages.containsKey(uri)) {
|
||||||
log(sms.getLogName() + " already sent, skipping");
|
log(sms.getLogName() + " already sent, skipping");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
outgoingSmsMap.put(id, sms);
|
outgoingMessages.put(uri, sms);
|
||||||
|
|
||||||
log("Sending " + sms.getLogName() + " to " + sms.getTo());
|
log("Sending " + sms.getLogName() + " to " + sms.getTo());
|
||||||
sms.trySend();
|
sms.trySend();
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void forwardToServer(IncomingMessage sms) {
|
public synchronized void forwardToServer(IncomingMessage message) {
|
||||||
String id = sms.getId();
|
Uri uri = message.getUri();
|
||||||
|
|
||||||
if (incomingSmsMap.containsKey(id)) {
|
if (incomingMessages.containsKey(uri)) {
|
||||||
log("Duplicate incoming SMS, skipping");
|
log("Duplicate incoming "+message.getDisplayType()+", skipping");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
incomingSmsMap.put(id, sms);
|
incomingMessages.put(uri, message);
|
||||||
|
|
||||||
log("Received SMS from " + sms.getFrom());
|
log("Received "+message.getDisplayType()+" from " + message.getFrom());
|
||||||
|
|
||||||
sms.tryForwardToServer();
|
message.tryForwardToServer();
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void retryIncomingMessage(String id) {
|
public synchronized void retryIncomingMessage(Uri uri) {
|
||||||
IncomingMessage sms = incomingSmsMap.get(id);
|
IncomingMessage message = incomingMessages.get(uri);
|
||||||
if (sms != null) {
|
if (message != null) {
|
||||||
sms.retryNow();
|
message.retryNow();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void retryOutgoingMessage(String id) {
|
public synchronized void retryOutgoingMessage(Uri uri) {
|
||||||
OutgoingMessage sms = outgoingSmsMap.get(id);
|
OutgoingMessage sms = outgoingMessages.get(uri);
|
||||||
if (sms != null) {
|
if (sms != null) {
|
||||||
sms.retryNow();
|
sms.retryNow();
|
||||||
}
|
}
|
||||||
@ -265,7 +309,7 @@ public final class App extends Application {
|
|||||||
Log.d(LOG_NAME, msg);
|
Log.d(LOG_NAME, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void log(CharSequence msg)
|
public synchronized void log(CharSequence msg)
|
||||||
{
|
{
|
||||||
Log.d(LOG_NAME, msg.toString());
|
Log.d(LOG_NAME, msg.toString());
|
||||||
|
|
||||||
@ -303,7 +347,7 @@ public final class App extends Application {
|
|||||||
sendBroadcast(broadcast);
|
sendBroadcast(broadcast);
|
||||||
}
|
}
|
||||||
|
|
||||||
public CharSequence getDisplayedLog()
|
public synchronized CharSequence getDisplayedLog()
|
||||||
{
|
{
|
||||||
return displayedLog;
|
return displayedLog;
|
||||||
}
|
}
|
||||||
@ -330,4 +374,8 @@ public final class App extends Application {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public MmsUtils getMmsUtils()
|
||||||
|
{
|
||||||
|
return mmsUtils;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
49
src/org/envaya/kalsms/CheckMmsInboxService.java
Executable file
49
src/org/envaya/kalsms/CheckMmsInboxService.java
Executable file
@ -0,0 +1,49 @@
|
|||||||
|
|
||||||
|
package org.envaya.kalsms;
|
||||||
|
|
||||||
|
import android.app.IntentService;
|
||||||
|
import android.content.Intent;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class CheckMmsInboxService extends IntentService
|
||||||
|
{
|
||||||
|
private App app;
|
||||||
|
private MmsUtils mmsUtils;
|
||||||
|
|
||||||
|
public CheckMmsInboxService(String name)
|
||||||
|
{
|
||||||
|
super(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CheckMmsInboxService()
|
||||||
|
{
|
||||||
|
this("CheckMmsInboxService");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate() {
|
||||||
|
super.onCreate();
|
||||||
|
|
||||||
|
app = (App)this.getApplicationContext();
|
||||||
|
|
||||||
|
mmsUtils = app.getMmsUtils();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onHandleIntent(Intent intent)
|
||||||
|
{
|
||||||
|
List<IncomingMms> messages = mmsUtils.getMessagesInInbox();
|
||||||
|
for (IncomingMms mms : messages)
|
||||||
|
{
|
||||||
|
if (mmsUtils.isNewMms(mms))
|
||||||
|
{
|
||||||
|
// prevent forwarding MMS messages that existed in inbox
|
||||||
|
// before KalSMS started, or re-forwarding MMS multiple
|
||||||
|
// times if we don't delete them.
|
||||||
|
mmsUtils.markOldMms(mms);
|
||||||
|
|
||||||
|
app.forwardToServer(mms);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,32 +1,21 @@
|
|||||||
package org.envaya.kalsms;
|
package org.envaya.kalsms;
|
||||||
|
|
||||||
import org.envaya.kalsms.task.ForwarderTask;
|
|
||||||
import org.envaya.kalsms.receiver.IncomingMessageRetry;
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.telephony.SmsMessage;
|
import org.envaya.kalsms.receiver.IncomingMessageRetry;
|
||||||
import org.apache.http.message.BasicNameValuePair;
|
|
||||||
|
|
||||||
public class IncomingMessage extends QueuedMessage {
|
public abstract class IncomingMessage extends QueuedMessage {
|
||||||
|
|
||||||
public String from;
|
protected String from;
|
||||||
public String message;
|
|
||||||
public long timestampMillis;
|
|
||||||
|
|
||||||
public IncomingMessage(App app, SmsMessage sms) {
|
public IncomingMessage(App app, String from)
|
||||||
super(app);
|
{
|
||||||
this.from = sms.getOriginatingAddress();
|
|
||||||
this.message = sms.getMessageBody();
|
|
||||||
this.timestampMillis = sms.getTimestampMillis();
|
|
||||||
}
|
|
||||||
|
|
||||||
public IncomingMessage(App app, String from, String message, long timestampMillis) {
|
|
||||||
super(app);
|
super(app);
|
||||||
this.from = from;
|
this.from = from;
|
||||||
this.message = message;
|
|
||||||
this.timestampMillis = timestampMillis;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public abstract String getDisplayType();
|
||||||
|
|
||||||
public boolean isForwardable()
|
public boolean isForwardable()
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
@ -36,37 +25,21 @@ public class IncomingMessage extends QueuedMessage {
|
|||||||
return from.length() > 5;
|
return from.length() > 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getMessageBody()
|
|
||||||
{
|
|
||||||
return message;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getFrom()
|
public String getFrom()
|
||||||
{
|
{
|
||||||
return from;
|
return from;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getId()
|
|
||||||
{
|
|
||||||
return from + ":" + message + ":" + timestampMillis;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void retryNow() {
|
public void retryNow() {
|
||||||
app.log("Retrying forwarding SMS from " + from);
|
app.log("Retrying forwarding message from " + from);
|
||||||
tryForwardToServer();
|
tryForwardToServer();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void tryForwardToServer() {
|
|
||||||
new ForwarderTask(this,
|
|
||||||
new BasicNameValuePair("from", getFrom()),
|
|
||||||
new BasicNameValuePair("message", getMessageBody())
|
|
||||||
).execute();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected Intent getRetryIntent() {
|
protected Intent getRetryIntent() {
|
||||||
Intent intent = new Intent(app, IncomingMessageRetry.class);
|
Intent intent = new Intent(app, IncomingMessageRetry.class);
|
||||||
intent.setData(Uri.parse("kalsms://incoming/" + this.getId()));
|
intent.setData(this.getUri());
|
||||||
return intent;
|
return intent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public abstract void tryForwardToServer();
|
||||||
}
|
}
|
||||||
|
163
src/org/envaya/kalsms/IncomingMms.java
Executable file
163
src/org/envaya/kalsms/IncomingMms.java
Executable file
@ -0,0 +1,163 @@
|
|||||||
|
|
||||||
|
package org.envaya.kalsms;
|
||||||
|
|
||||||
|
import android.net.Uri;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
import org.json.*;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import org.apache.http.entity.mime.FormBodyPart;
|
||||||
|
import org.apache.http.entity.mime.content.ByteArrayBody;
|
||||||
|
import org.apache.http.entity.mime.content.ContentBody;
|
||||||
|
import org.apache.http.entity.mime.content.InputStreamBody;
|
||||||
|
import org.apache.http.message.BasicNameValuePair;
|
||||||
|
import org.envaya.kalsms.task.ForwarderTask;
|
||||||
|
|
||||||
|
public class IncomingMms extends IncomingMessage {
|
||||||
|
List<MmsPart> parts;
|
||||||
|
long id;
|
||||||
|
String contentLocation;
|
||||||
|
|
||||||
|
public IncomingMms(App app, String from, long id)
|
||||||
|
{
|
||||||
|
super(app, from);
|
||||||
|
this.parts = new ArrayList<MmsPart>();
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDisplayType()
|
||||||
|
{
|
||||||
|
return "MMS";
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<MmsPart> getParts()
|
||||||
|
{
|
||||||
|
return parts;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addPart(MmsPart part)
|
||||||
|
{
|
||||||
|
parts.add(part);
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getId()
|
||||||
|
{
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getContentLocation()
|
||||||
|
{
|
||||||
|
return contentLocation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setContentLocation(String contentLocation)
|
||||||
|
{
|
||||||
|
this.contentLocation = contentLocation;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
StringBuilder builder = new StringBuilder();
|
||||||
|
builder.append("MMS id=");
|
||||||
|
builder.append(id);
|
||||||
|
builder.append(" from=");
|
||||||
|
builder.append(from);
|
||||||
|
builder.append(":\n");
|
||||||
|
|
||||||
|
for (MmsPart part : parts)
|
||||||
|
{
|
||||||
|
builder.append(" ");
|
||||||
|
builder.append(part.toString());
|
||||||
|
builder.append("\n");
|
||||||
|
}
|
||||||
|
return builder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void tryForwardToServer()
|
||||||
|
{
|
||||||
|
app.log("Forwarding MMS to server...");
|
||||||
|
|
||||||
|
List<FormBodyPart> formParts = new ArrayList<FormBodyPart>();
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
String message = "";
|
||||||
|
JSONArray partsMetadata = new JSONArray();
|
||||||
|
|
||||||
|
for (MmsPart part : parts)
|
||||||
|
{
|
||||||
|
String formFieldName = "part" + i;
|
||||||
|
String text = part.getText();
|
||||||
|
String contentType = part.getContentType();
|
||||||
|
String partName = part.getName();
|
||||||
|
|
||||||
|
if ("text/plain".equals(contentType))
|
||||||
|
{
|
||||||
|
message = text;
|
||||||
|
}
|
||||||
|
|
||||||
|
ContentBody body;
|
||||||
|
|
||||||
|
if (text != null)
|
||||||
|
{
|
||||||
|
if (contentType != null)
|
||||||
|
{
|
||||||
|
contentType += "; charset=utf-8";
|
||||||
|
}
|
||||||
|
|
||||||
|
body = new ByteArrayBody(text.getBytes(), contentType, partName);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
body = new InputStreamBody(part.openInputStream(),
|
||||||
|
contentType, partName);
|
||||||
|
}
|
||||||
|
catch (IOException ex)
|
||||||
|
{
|
||||||
|
app.logError("Error opening data for " + part.toString(), ex);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
JSONObject partMetadata = new JSONObject();
|
||||||
|
partMetadata.put("name", formFieldName);
|
||||||
|
partMetadata.put("cid", part.getContentId());
|
||||||
|
partMetadata.put("type", part.getContentType());
|
||||||
|
partMetadata.put("filename", part.getName());
|
||||||
|
partsMetadata.put(partMetadata);
|
||||||
|
}
|
||||||
|
catch (JSONException ex)
|
||||||
|
{
|
||||||
|
app.logError("Error encoding MMS part metadata for " + part.toString(), ex);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
formParts.add(new FormBodyPart(formFieldName, body));
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
ForwarderTask task = new ForwarderTask(this,
|
||||||
|
new BasicNameValuePair("from", getFrom()),
|
||||||
|
new BasicNameValuePair("message", message),
|
||||||
|
new BasicNameValuePair("message_type", App.MESSAGE_TYPE_MMS),
|
||||||
|
new BasicNameValuePair("mms_parts", partsMetadata.toString())
|
||||||
|
);
|
||||||
|
|
||||||
|
task.setFormParts(formParts);
|
||||||
|
task.execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Uri getUri()
|
||||||
|
{
|
||||||
|
return Uri.withAppendedPath(App.INCOMING_URI, "mms/" + id);
|
||||||
|
}
|
||||||
|
}
|
56
src/org/envaya/kalsms/IncomingSms.java
Executable file
56
src/org/envaya/kalsms/IncomingSms.java
Executable file
@ -0,0 +1,56 @@
|
|||||||
|
|
||||||
|
package org.envaya.kalsms;
|
||||||
|
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.telephony.SmsMessage;
|
||||||
|
import org.apache.http.message.BasicNameValuePair;
|
||||||
|
import org.envaya.kalsms.task.ForwarderTask;
|
||||||
|
|
||||||
|
|
||||||
|
public class IncomingSms extends IncomingMessage {
|
||||||
|
|
||||||
|
protected String message;
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
// constructor for SMS retrieved from Messaging inbox
|
||||||
|
public IncomingSms(App app, String from, String message, long timestampMillis) {
|
||||||
|
super(app, from);
|
||||||
|
this.message = message;
|
||||||
|
this.timestampMillis = timestampMillis;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMessageBody()
|
||||||
|
{
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDisplayType()
|
||||||
|
{
|
||||||
|
return "SMS";
|
||||||
|
}
|
||||||
|
|
||||||
|
public Uri getUri()
|
||||||
|
{
|
||||||
|
return Uri.withAppendedPath(App.INCOMING_URI,
|
||||||
|
"sms/" +
|
||||||
|
Uri.encode(from) + "/"
|
||||||
|
+ timestampMillis + "/" +
|
||||||
|
Uri.encode(message));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void tryForwardToServer() {
|
||||||
|
new ForwarderTask(this,
|
||||||
|
new BasicNameValuePair("from", getFrom()),
|
||||||
|
new BasicNameValuePair("message_type", App.MESSAGE_TYPE_SMS),
|
||||||
|
new BasicNameValuePair("message", getMessageBody())
|
||||||
|
).execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
51
src/org/envaya/kalsms/MmsObserver.java
Executable file
51
src/org/envaya/kalsms/MmsObserver.java
Executable file
@ -0,0 +1,51 @@
|
|||||||
|
package org.envaya.kalsms;
|
||||||
|
|
||||||
|
import android.app.IntentService;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.database.ContentObserver;
|
||||||
|
import android.os.Handler;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
final class MmsObserver extends ContentObserver {
|
||||||
|
|
||||||
|
private App app;
|
||||||
|
|
||||||
|
public MmsObserver(App app) {
|
||||||
|
super(new Handler());
|
||||||
|
this.app = app;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void register()
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Content observers can watch the MMS inbox URI for changes;
|
||||||
|
* This is the URL passed to PduPersister.persist by
|
||||||
|
* com.android.mms.transaction.RetrieveTransaction.run
|
||||||
|
*/
|
||||||
|
app.getContentResolver().registerContentObserver(
|
||||||
|
MmsUtils.OBSERVER_URI, true, this);
|
||||||
|
app.log("MMS content observer registered");
|
||||||
|
|
||||||
|
MmsUtils mmsUtils = app.getMmsUtils();
|
||||||
|
|
||||||
|
List<IncomingMms> messages = mmsUtils.getMessagesInInbox();
|
||||||
|
for (IncomingMms mms : messages)
|
||||||
|
{
|
||||||
|
mmsUtils.markOldMms(mms);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onChange(final boolean selfChange) {
|
||||||
|
super.onChange(selfChange);
|
||||||
|
|
||||||
|
if (!selfChange)
|
||||||
|
{
|
||||||
|
// check MMS inbox in an IntentService since it may be slow
|
||||||
|
// and we only want to do one check at a time
|
||||||
|
app.startService(new Intent(app, CheckMmsInboxService.class));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
113
src/org/envaya/kalsms/MmsPart.java
Executable file
113
src/org/envaya/kalsms/MmsPart.java
Executable file
@ -0,0 +1,113 @@
|
|||||||
|
package org.envaya.kalsms;
|
||||||
|
|
||||||
|
import android.net.Uri;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
public class MmsPart {
|
||||||
|
private App app;
|
||||||
|
private long partId;
|
||||||
|
private String contentType;
|
||||||
|
private String name;
|
||||||
|
private String text;
|
||||||
|
private String cid;
|
||||||
|
|
||||||
|
public MmsPart(App app, long partId)
|
||||||
|
{
|
||||||
|
this.app = app;
|
||||||
|
this.partId = partId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The part id is the local value of the _id column in the MMS part table
|
||||||
|
* (see android.provider.Telephony.Part)
|
||||||
|
*/
|
||||||
|
public long getPartId()
|
||||||
|
{
|
||||||
|
return partId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The content id of a MMS part is used to resolve references in SMIL
|
||||||
|
* like <img region="Image" src="cid:805"/> . Telephony.java claims
|
||||||
|
* that the cid column is an integer, but it is actually a string
|
||||||
|
* like "<0000>" or "<83>".
|
||||||
|
*/
|
||||||
|
public void setContentId(String cid)
|
||||||
|
{
|
||||||
|
this.cid = cid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getContentId()
|
||||||
|
{
|
||||||
|
return cid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Common Content-Type values for MMS parts include:
|
||||||
|
* application/smil
|
||||||
|
* text/plain
|
||||||
|
* image/jpeg
|
||||||
|
*/
|
||||||
|
public void setContentType(String contentType)
|
||||||
|
{
|
||||||
|
this.contentType = contentType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getContentType()
|
||||||
|
{
|
||||||
|
return contentType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The name of an MMS part is the filename of the original file sent
|
||||||
|
* (e.g. Image001.jpg). For text/SMIL parts, the filename is generated by the
|
||||||
|
* sending phone and can usually be ignored.
|
||||||
|
*/
|
||||||
|
public void setName(String name)
|
||||||
|
{
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName()
|
||||||
|
{
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The text is the content of text-based MMS parts (application/smil,
|
||||||
|
* text/plain, or text/html), and is null for multimedia parts.
|
||||||
|
*/
|
||||||
|
public void setText(String text)
|
||||||
|
{
|
||||||
|
this.text = text;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getText()
|
||||||
|
{
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For multimedia parts, the _data column of the MMS Parts table contains the
|
||||||
|
* path on the Android filesystem containing that file, and openInputStream
|
||||||
|
* returns an InputStream for this file.
|
||||||
|
*/
|
||||||
|
public InputStream openInputStream() throws FileNotFoundException
|
||||||
|
{
|
||||||
|
return app.getContentResolver().openInputStream(getContentUri());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
return "part " + partId + ": " + contentType + "; name=" + name + "; cid=" + cid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Uri getContentUri()
|
||||||
|
{
|
||||||
|
return Uri.parse("content://mms/part/" + partId);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
176
src/org/envaya/kalsms/MmsUtils.java
Executable file
176
src/org/envaya/kalsms/MmsUtils.java
Executable file
@ -0,0 +1,176 @@
|
|||||||
|
|
||||||
|
package org.envaya.kalsms;
|
||||||
|
|
||||||
|
import android.content.ContentResolver;
|
||||||
|
import android.database.Cursor;
|
||||||
|
import android.net.Uri;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Utilities for parsing IncomingMms from the MMS content provider tables,
|
||||||
|
* as defined by android.provider.Telephony
|
||||||
|
*
|
||||||
|
* Analogous to com.google.android.mms.pdu.PduPersister from
|
||||||
|
* core/java/com/google/android/mms/pdu in the base Android framework
|
||||||
|
* (https://github.com/android/platform_frameworks_base)
|
||||||
|
*/
|
||||||
|
public class MmsUtils
|
||||||
|
{
|
||||||
|
// constants from android.provider.Telephony
|
||||||
|
public static final Uri OBSERVER_URI = Uri.parse("content://mms-sms/");
|
||||||
|
public static final Uri INBOX_URI = Uri.parse("content://mms/inbox");
|
||||||
|
public static final Uri PART_URI = Uri.parse("content://mms/part");
|
||||||
|
|
||||||
|
// constants from com.google.android.mms.pdu.PduHeaders
|
||||||
|
private static final int PDU_HEADER_FROM = 0x89;
|
||||||
|
private static final int MESSAGE_TYPE_RETRIEVE_CONF = 0x84;
|
||||||
|
|
||||||
|
// todo -- prevent unbounded growth?
|
||||||
|
private final Set<String> seenMmsContentLocations = new HashSet<String>();
|
||||||
|
|
||||||
|
private App app;
|
||||||
|
private ContentResolver contentResolver;
|
||||||
|
|
||||||
|
public MmsUtils(App app)
|
||||||
|
{
|
||||||
|
this.app = app;
|
||||||
|
this.contentResolver = app.getContentResolver();
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<MmsPart> getMmsParts(long id)
|
||||||
|
{
|
||||||
|
Cursor cur = contentResolver.query(PART_URI, new String[] {
|
||||||
|
"_id", "ct", "name", "text", "cid"
|
||||||
|
}, "mid = ?", new String[] { "" + id }, null);
|
||||||
|
|
||||||
|
// assume that if there is at least one part saved in database
|
||||||
|
// then MMS is fully delivered (this seems to be true in practice)
|
||||||
|
|
||||||
|
List<MmsPart> parts = new ArrayList<MmsPart>();
|
||||||
|
|
||||||
|
while (cur.moveToNext())
|
||||||
|
{
|
||||||
|
long partId = cur.getLong(0);
|
||||||
|
|
||||||
|
MmsPart part = new MmsPart(app, partId);
|
||||||
|
part.setContentType(cur.getString(1));
|
||||||
|
part.setName(cur.getString(2));
|
||||||
|
|
||||||
|
// todo interpret charset like com.google.android.mms.pdu.EncodedStringValue
|
||||||
|
part.setText(cur.getString(3));
|
||||||
|
|
||||||
|
part.setContentId(cur.getString(4));
|
||||||
|
|
||||||
|
parts.add(part);
|
||||||
|
}
|
||||||
|
|
||||||
|
cur.close();
|
||||||
|
|
||||||
|
return parts;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* see com.google.android.mms.pdu.PduPersister.loadAddress
|
||||||
|
*/
|
||||||
|
private String getSenderNumber(long mmsId) {
|
||||||
|
|
||||||
|
Uri uri = Uri.parse("content://mms/"+mmsId+"/addr");
|
||||||
|
|
||||||
|
Cursor cur = contentResolver.query(uri,
|
||||||
|
new String[] { "address", "charset", "type" },
|
||||||
|
null, null, null);
|
||||||
|
|
||||||
|
String address = null;
|
||||||
|
while (cur.moveToNext())
|
||||||
|
{
|
||||||
|
int addrType = cur.getInt(2);
|
||||||
|
if (addrType == PDU_HEADER_FROM)
|
||||||
|
{
|
||||||
|
// todo interpret charset like com.google.android.mms.pdu.EncodedStringValue
|
||||||
|
address = cur.getString(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cur.close();
|
||||||
|
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<IncomingMms> getMessagesInInbox()
|
||||||
|
{
|
||||||
|
// the M-Retrieve.conf messages are the 'actual' MMS messages
|
||||||
|
String m_type = "" + MESSAGE_TYPE_RETRIEVE_CONF;
|
||||||
|
|
||||||
|
Cursor c = contentResolver.query(INBOX_URI,
|
||||||
|
new String[] {"_id", "ct_l"},
|
||||||
|
"m_type = ? AND ct_l is not NULL", new String[] { m_type }, null);
|
||||||
|
|
||||||
|
List<IncomingMms> messages = new ArrayList<IncomingMms>();
|
||||||
|
|
||||||
|
while (c.moveToNext())
|
||||||
|
{
|
||||||
|
long id = c.getLong(0);
|
||||||
|
|
||||||
|
IncomingMms mms = new IncomingMms(app, getSenderNumber(id), id);
|
||||||
|
|
||||||
|
mms.setContentLocation(c.getString(1));
|
||||||
|
|
||||||
|
for (MmsPart part : getMmsParts(id))
|
||||||
|
{
|
||||||
|
mms.addPart(part);
|
||||||
|
}
|
||||||
|
|
||||||
|
messages.add(mms);
|
||||||
|
}
|
||||||
|
c.close();
|
||||||
|
|
||||||
|
return messages;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean deleteFromInbox(IncomingMms mms)
|
||||||
|
{
|
||||||
|
String contentLocation = mms.getContentLocation();
|
||||||
|
|
||||||
|
int res;
|
||||||
|
if (contentLocation != null)
|
||||||
|
{
|
||||||
|
Uri uri = Uri.parse("content://mms/inbox");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Delete by content location (ct_l) rather than _id so that
|
||||||
|
* M-Notification.ind and M-Retrieve.conf messages are both deleted
|
||||||
|
* (otherwise it would remain in Messaging inbox with a Download button)
|
||||||
|
*/
|
||||||
|
|
||||||
|
res = contentResolver.delete(uri,
|
||||||
|
"ct_l = ?",
|
||||||
|
new String[] { contentLocation });
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
app.log("mms has no content-location");
|
||||||
|
Uri uri = Uri.parse("content://mms/inbox/" + mms.getId());
|
||||||
|
res = contentResolver.delete(uri, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
app.log(res + " rows deleted");
|
||||||
|
return res > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void markOldMms(IncomingMms mms)
|
||||||
|
{
|
||||||
|
String contentLocation = mms.getContentLocation();
|
||||||
|
if (contentLocation != null)
|
||||||
|
{
|
||||||
|
seenMmsContentLocations.add(contentLocation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized boolean isNewMms(IncomingMms mms)
|
||||||
|
{
|
||||||
|
String contentLocation = mms.getContentLocation();
|
||||||
|
return contentLocation != null && !seenMmsContentLocations.contains(contentLocation);
|
||||||
|
}
|
||||||
|
}
|
@ -30,9 +30,9 @@ public class OutgoingMessage extends QueuedMessage {
|
|||||||
return nextLocalId++;
|
return nextLocalId++;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getId()
|
public Uri getUri()
|
||||||
{
|
{
|
||||||
return (serverId == null) ? localId : serverId;
|
return Uri.withAppendedPath(App.OUTGOING_URI, ((serverId == null) ? localId : serverId));
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getLogName()
|
public String getLogName()
|
||||||
@ -90,7 +90,7 @@ public class OutgoingMessage extends QueuedMessage {
|
|||||||
SmsManager smgr = SmsManager.getDefault();
|
SmsManager smgr = SmsManager.getDefault();
|
||||||
|
|
||||||
Intent intent = new Intent(app, MessageStatusNotifier.class);
|
Intent intent = new Intent(app, MessageStatusNotifier.class);
|
||||||
intent.setData(Uri.parse("kalsms://outgoing/" + getId()));
|
intent.setData(this.getUri());
|
||||||
|
|
||||||
PendingIntent sentIntent = PendingIntent.getBroadcast(
|
PendingIntent sentIntent = PendingIntent.getBroadcast(
|
||||||
app,
|
app,
|
||||||
@ -103,7 +103,7 @@ public class OutgoingMessage extends QueuedMessage {
|
|||||||
|
|
||||||
protected Intent getRetryIntent() {
|
protected Intent getRetryIntent() {
|
||||||
Intent intent = new Intent(app, OutgoingMessageRetry.class);
|
Intent intent = new Intent(app, OutgoingMessageRetry.class);
|
||||||
intent.setData(Uri.parse("kalsms://outgoing/" + getId()));
|
intent.setData(this.getUri());
|
||||||
return intent;
|
return intent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ import android.app.AlarmManager;
|
|||||||
import android.app.PendingIntent;
|
import android.app.PendingIntent;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.net.Uri;
|
||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
|
|
||||||
public abstract class QueuedMessage
|
public abstract class QueuedMessage
|
||||||
@ -63,6 +64,8 @@ public abstract class QueuedMessage
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public abstract Uri getUri();
|
||||||
|
|
||||||
public abstract void retryNow();
|
public abstract void retryNow();
|
||||||
|
|
||||||
protected abstract Intent getRetryIntent();
|
protected abstract Intent getRetryIntent();
|
||||||
|
@ -4,19 +4,12 @@ package org.envaya.kalsms.receiver;
|
|||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import org.envaya.kalsms.App;
|
|
||||||
|
|
||||||
public class BootReceiver extends BroadcastReceiver {
|
public class BootReceiver extends BroadcastReceiver {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(Context context, Intent intent)
|
public void onReceive(Context context, Intent intent)
|
||||||
{
|
{
|
||||||
App app = (App)context.getApplicationContext();
|
// just want to initialize App class to start outgoing message poll timer
|
||||||
if (!app.isEnabled())
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
app.setOutgoingMessageAlarm();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,6 @@ public class IncomingMessageRetry extends BroadcastReceiver
|
|||||||
public void onReceive(Context context, Intent intent)
|
public void onReceive(Context context, Intent intent)
|
||||||
{
|
{
|
||||||
App app = (App) context.getApplicationContext();
|
App app = (App) context.getApplicationContext();
|
||||||
app.retryIncomingMessage(intent.getData().getLastPathSegment());
|
app.retryIncomingMessage(intent.getData());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,27 +0,0 @@
|
|||||||
/*
|
|
||||||
* Based on http://code.google.com/p/android-notifier/, copyright 2011 Rodrigo Damazio
|
|
||||||
* Licensed under the Apache License, Version 2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.envaya.kalsms.receiver;
|
|
||||||
|
|
||||||
import android.content.BroadcastReceiver;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
import org.envaya.kalsms.App;
|
|
||||||
|
|
||||||
public class MMSReceiver extends BroadcastReceiver {
|
|
||||||
|
|
||||||
private App app;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onReceive(Context context, Intent intent) {
|
|
||||||
app = (App) context.getApplicationContext();
|
|
||||||
|
|
||||||
if (!app.isEnabled()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
app.log("WAP Push received");
|
|
||||||
}
|
|
||||||
}
|
|
@ -7,6 +7,7 @@ package org.envaya.kalsms.receiver;
|
|||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.net.Uri;
|
||||||
import org.envaya.kalsms.App;
|
import org.envaya.kalsms.App;
|
||||||
|
|
||||||
public class MessageStatusNotifier extends BroadcastReceiver {
|
public class MessageStatusNotifier extends BroadcastReceiver {
|
||||||
@ -14,7 +15,7 @@ public class MessageStatusNotifier extends BroadcastReceiver {
|
|||||||
@Override
|
@Override
|
||||||
public void onReceive(Context context, Intent intent) {
|
public void onReceive(Context context, Intent intent) {
|
||||||
App app = (App) context.getApplicationContext();
|
App app = (App) context.getApplicationContext();
|
||||||
String id = intent.getData().getLastPathSegment();
|
Uri uri = intent.getData();
|
||||||
|
|
||||||
int resultCode = getResultCode();
|
int resultCode = getResultCode();
|
||||||
|
|
||||||
@ -26,6 +27,6 @@ public class MessageStatusNotifier extends BroadcastReceiver {
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
app.notifyOutgoingMessageStatus(id, resultCode);
|
app.notifyOutgoingMessageStatus(uri, resultCode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,6 @@ public class OutgoingMessageRetry extends BroadcastReceiver
|
|||||||
public void onReceive(Context context, Intent intent)
|
public void onReceive(Context context, Intent intent)
|
||||||
{
|
{
|
||||||
App app = (App) context.getApplicationContext();
|
App app = (App) context.getApplicationContext();
|
||||||
app.retryOutgoingMessage(intent.getData().getLastPathSegment());
|
app.retryOutgoingMessage(intent.getData());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,9 +9,10 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import org.envaya.kalsms.App;
|
import org.envaya.kalsms.App;
|
||||||
import org.envaya.kalsms.IncomingMessage;
|
import org.envaya.kalsms.IncomingMessage;
|
||||||
|
import org.envaya.kalsms.IncomingSms;
|
||||||
|
|
||||||
|
|
||||||
public class SMSReceiver extends BroadcastReceiver {
|
public class SmsReceiver extends BroadcastReceiver {
|
||||||
|
|
||||||
private App app;
|
private App app;
|
||||||
|
|
||||||
@ -64,7 +65,7 @@ public class SMSReceiver extends BroadcastReceiver {
|
|||||||
for (Object pdu : (Object[]) bundle.get("pdus"))
|
for (Object pdu : (Object[]) bundle.get("pdus"))
|
||||||
{
|
{
|
||||||
SmsMessage sms = SmsMessage.createFromPdu((byte[]) pdu);
|
SmsMessage sms = SmsMessage.createFromPdu((byte[]) pdu);
|
||||||
messages.add(new IncomingMessage(app, sms));
|
messages.add(new IncomingSms(app, sms));
|
||||||
}
|
}
|
||||||
return messages;
|
return messages;
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,9 @@ import java.util.ArrayList;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import javax.xml.parsers.DocumentBuilder;
|
import javax.xml.parsers.DocumentBuilder;
|
||||||
import javax.xml.parsers.DocumentBuilderFactory;
|
import javax.xml.parsers.DocumentBuilderFactory;
|
||||||
import javax.xml.parsers.ParserConfigurationException;
|
import javax.xml.parsers.ParserConfigurationException;
|
||||||
@ -22,6 +24,11 @@ import org.apache.http.HttpResponse;
|
|||||||
import org.apache.http.client.HttpClient;
|
import org.apache.http.client.HttpClient;
|
||||||
import org.apache.http.client.entity.UrlEncodedFormEntity;
|
import org.apache.http.client.entity.UrlEncodedFormEntity;
|
||||||
import org.apache.http.client.methods.HttpPost;
|
import org.apache.http.client.methods.HttpPost;
|
||||||
|
import org.apache.http.entity.mime.FormBodyPart;
|
||||||
|
import org.apache.http.entity.mime.HttpMultipartMode;
|
||||||
|
import org.apache.http.entity.mime.MultipartEntity;
|
||||||
|
import org.apache.http.entity.mime.content.ContentBody;
|
||||||
|
import org.apache.http.entity.mime.content.StringBody;
|
||||||
import org.apache.http.impl.client.DefaultHttpClient;
|
import org.apache.http.impl.client.DefaultHttpClient;
|
||||||
import org.apache.http.message.BasicNameValuePair;
|
import org.apache.http.message.BasicNameValuePair;
|
||||||
import org.apache.http.params.BasicHttpParams;
|
import org.apache.http.params.BasicHttpParams;
|
||||||
@ -43,6 +50,9 @@ public class HttpTask extends AsyncTask<String, Void, HttpResponse> {
|
|||||||
protected String url;
|
protected String url;
|
||||||
protected List<BasicNameValuePair> params = new ArrayList<BasicNameValuePair>();
|
protected List<BasicNameValuePair> params = new ArrayList<BasicNameValuePair>();
|
||||||
|
|
||||||
|
private List<FormBodyPart> formParts;
|
||||||
|
private boolean useMultipartPost = false;
|
||||||
|
|
||||||
public HttpTask(App app, BasicNameValuePair... paramsArr)
|
public HttpTask(App app, BasicNameValuePair... paramsArr)
|
||||||
{
|
{
|
||||||
super();
|
super();
|
||||||
@ -53,6 +63,12 @@ public class HttpTask extends AsyncTask<String, Void, HttpResponse> {
|
|||||||
params.add(new BasicNameValuePair("phone_number", app.getPhoneNumber()));
|
params.add(new BasicNameValuePair("phone_number", app.getPhoneNumber()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setFormParts(List<FormBodyPart> formParts)
|
||||||
|
{
|
||||||
|
useMultipartPost = true;
|
||||||
|
this.formParts = formParts;
|
||||||
|
}
|
||||||
|
|
||||||
public HttpClient getHttpClient()
|
public HttpClient getHttpClient()
|
||||||
{
|
{
|
||||||
HttpParams httpParameters = new BasicHttpParams();
|
HttpParams httpParameters = new BasicHttpParams();
|
||||||
@ -103,7 +119,26 @@ public class HttpTask extends AsyncTask<String, Void, HttpResponse> {
|
|||||||
|
|
||||||
HttpPost post = new HttpPost(url);
|
HttpPost post = new HttpPost(url);
|
||||||
|
|
||||||
|
|
||||||
|
if (useMultipartPost)
|
||||||
|
{
|
||||||
|
MultipartEntity entity = new MultipartEntity();//HttpMultipartMode.BROWSER_COMPATIBLE);
|
||||||
|
|
||||||
|
for (BasicNameValuePair param : params)
|
||||||
|
{
|
||||||
|
entity.addPart(param.getName(), new StringBody(param.getValue()));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (FormBodyPart formPart : formParts)
|
||||||
|
{
|
||||||
|
entity.addPart(formPart);
|
||||||
|
}
|
||||||
|
post.setEntity(entity);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
post.setEntity(new UrlEncodedFormEntity(params));
|
post.setEntity(new UrlEncodedFormEntity(params));
|
||||||
|
}
|
||||||
|
|
||||||
String signature = getSignature();
|
String signature = getSignature();
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@ import android.widget.ListView;
|
|||||||
import android.widget.SimpleCursorAdapter;
|
import android.widget.SimpleCursorAdapter;
|
||||||
import org.envaya.kalsms.App;
|
import org.envaya.kalsms.App;
|
||||||
import org.envaya.kalsms.IncomingMessage;
|
import org.envaya.kalsms.IncomingMessage;
|
||||||
|
import org.envaya.kalsms.IncomingSms;
|
||||||
import org.envaya.kalsms.R;
|
import org.envaya.kalsms.R;
|
||||||
|
|
||||||
|
|
||||||
@ -74,7 +75,7 @@ public class ForwardInbox extends ListActivity {
|
|||||||
String body = cur.getString(bodyIndex);
|
String body = cur.getString(bodyIndex);
|
||||||
long date = cur.getLong(dateIndex);
|
long date = cur.getLong(dateIndex);
|
||||||
|
|
||||||
IncomingMessage sms = new IncomingMessage(app, address, body, date);
|
IncomingMessage sms = new IncomingSms(app, address, body, date);
|
||||||
|
|
||||||
app.forwardToServer(sms);
|
app.forwardToServer(sms);
|
||||||
}
|
}
|
||||||
|
@ -3,9 +3,11 @@ package org.envaya.kalsms.ui;
|
|||||||
import org.envaya.kalsms.task.HttpTask;
|
import org.envaya.kalsms.task.HttpTask;
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
|
import android.content.ContentValues;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.IntentFilter;
|
import android.content.IntentFilter;
|
||||||
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
import android.text.Html;
|
import android.text.Html;
|
||||||
@ -19,6 +21,8 @@ import android.widget.TextView;
|
|||||||
import org.apache.http.HttpResponse;
|
import org.apache.http.HttpResponse;
|
||||||
import org.apache.http.message.BasicNameValuePair;
|
import org.apache.http.message.BasicNameValuePair;
|
||||||
import org.envaya.kalsms.App;
|
import org.envaya.kalsms.App;
|
||||||
|
import org.envaya.kalsms.IncomingMms;
|
||||||
|
import org.envaya.kalsms.MmsUtils;
|
||||||
import org.envaya.kalsms.R;
|
import org.envaya.kalsms.R;
|
||||||
|
|
||||||
public class Main extends Activity {
|
public class Main extends Activity {
|
||||||
@ -46,8 +50,6 @@ public class Main extends Activity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private long lastLogTime = 0;
|
|
||||||
|
|
||||||
public void updateLogView()
|
public void updateLogView()
|
||||||
{
|
{
|
||||||
final ScrollView scrollView = (ScrollView) this.findViewById(R.id.info_scroll);
|
final ScrollView scrollView = (ScrollView) this.findViewById(R.id.info_scroll);
|
||||||
@ -81,14 +83,7 @@ public class Main extends Activity {
|
|||||||
|
|
||||||
if (savedInstanceState == null)
|
if (savedInstanceState == null)
|
||||||
{
|
{
|
||||||
app.log(Html.fromHtml(
|
|
||||||
app.isEnabled() ? "<b>SMS gateway running.</b>" : "<b>SMS gateway disabled.</b>"));
|
|
||||||
|
|
||||||
app.log("Server URL is: " + app.getDisplayString(app.getServerUrl()));
|
|
||||||
app.log("Your phone number is: " + app.getDisplayString(app.getPhoneNumber()) );
|
|
||||||
app.log(Html.fromHtml("<b>Press Menu to edit settings.</b>"));
|
app.log(Html.fromHtml("<b>Press Menu to edit settings.</b>"));
|
||||||
|
|
||||||
app.setOutgoingMessageAlarm();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user