mirror of
https://github.com/cwinfo/envayasms.git
synced 2025-04-04 23:46:21 +00:00
keep messages waiting to be sent in memory; if forwarding fails (in either direction), retry a few times (1m, 10m, 1h, 1d) before giving up; add menu button to retry sending now
This commit is contained in:
parent
307f354deb
commit
2911111490
@ -29,9 +29,6 @@
|
|||||||
</receiver>
|
</receiver>
|
||||||
|
|
||||||
<receiver android:name=".MessageStatusNotifier">
|
<receiver android:name=".MessageStatusNotifier">
|
||||||
<intent-filter>
|
|
||||||
<action android:name="org.envaya.kalsms.SEND_STATUS" />
|
|
||||||
</intent-filter>
|
|
||||||
</receiver>
|
</receiver>
|
||||||
|
|
||||||
<receiver android:name=".OutgoingMessagePoller">
|
<receiver android:name=".OutgoingMessagePoller">
|
||||||
|
BIN
res/drawable-hdpi/ic_menu_magnet.png
Executable file
BIN
res/drawable-hdpi/ic_menu_magnet.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 2.3 KiB |
BIN
res/drawable-ldpi/ic_menu_magnet.png
Executable file
BIN
res/drawable-ldpi/ic_menu_magnet.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
BIN
res/drawable-mdpi/ic_menu_magnet.png
Executable file
BIN
res/drawable-mdpi/ic_menu_magnet.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 1.4 KiB |
@ -12,4 +12,7 @@
|
|||||||
<item android:id="@+id/help"
|
<item android:id="@+id/help"
|
||||||
android:icon="@drawable/ic_menu_puzzle"
|
android:icon="@drawable/ic_menu_puzzle"
|
||||||
android:title="@string/help" />
|
android:title="@string/help" />
|
||||||
|
<item android:id="@+id/retry_now"
|
||||||
|
android:icon="@drawable/ic_menu_magnet"
|
||||||
|
android:title="@string/retry_now" />
|
||||||
</menu>
|
</menu>
|
@ -5,4 +5,5 @@
|
|||||||
<string name="test">Test Connection</string>
|
<string name="test">Test Connection</string>
|
||||||
<string name="check_now">Check Messages</string>
|
<string name="check_now">Check Messages</string>
|
||||||
<string name="help">Help</string>
|
<string name="help">Help</string>
|
||||||
|
<string name="retry_now">Retry</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -4,25 +4,24 @@
|
|||||||
*/
|
*/
|
||||||
package org.envaya.kalsms;
|
package org.envaya.kalsms;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
import android.app.AlarmManager;
|
import android.app.AlarmManager;
|
||||||
import android.app.PendingIntent;
|
import android.app.PendingIntent;
|
||||||
import android.content.ContentValues;
|
|
||||||
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.database.Cursor;
|
|
||||||
import android.database.sqlite.SQLiteDatabase;
|
|
||||||
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.telephony.SmsMessage;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
import java.util.Set;
|
||||||
import org.apache.http.HttpResponse;
|
import org.apache.http.HttpResponse;
|
||||||
import org.apache.http.client.HttpClient;
|
|
||||||
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.HttpConnectionParams;
|
|
||||||
import org.apache.http.params.HttpParams;
|
|
||||||
|
|
||||||
public class App {
|
public class App {
|
||||||
|
|
||||||
@ -36,19 +35,85 @@ public class App {
|
|||||||
|
|
||||||
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 String SEND_STATUS_INTENT = "org.envaya.kalsms.SEND_STATUS";
|
|
||||||
|
private static App app;
|
||||||
|
|
||||||
|
private Map<String, QueuedIncomingSms> incomingSmsMap = new HashMap<String, QueuedIncomingSms>();
|
||||||
|
private Map<String, QueuedOutgoingSms> outgoingSmsMap = new HashMap<String, QueuedOutgoingSms>();
|
||||||
|
|
||||||
public Context context;
|
public Context context;
|
||||||
public SharedPreferences settings;
|
public SharedPreferences settings;
|
||||||
|
|
||||||
|
private class QueuedMessage<T>
|
||||||
|
{
|
||||||
|
public T sms;
|
||||||
|
public long nextAttemptTime = 0;
|
||||||
|
public int numAttempts = 0;
|
||||||
|
|
||||||
|
public boolean canAttemptNow()
|
||||||
|
{
|
||||||
|
return (nextAttemptTime > 0 && nextAttemptTime < System.currentTimeMillis());
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean scheduleNextAttempt()
|
||||||
|
{
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
numAttempts++;
|
||||||
|
|
||||||
|
int sec = 1000;
|
||||||
|
|
||||||
|
if (numAttempts == 1)
|
||||||
|
{
|
||||||
|
log("1st failure; retry in 1 minute");
|
||||||
|
nextAttemptTime = now + sec * 60; // 1 minute
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (numAttempts == 2)
|
||||||
|
{
|
||||||
|
log("2nd failure; retry in 10 minutes");
|
||||||
|
nextAttemptTime = now + sec * 60 * 10; // 10 min
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (numAttempts == 3)
|
||||||
|
{
|
||||||
|
log("3rd failure; retry in 1 hour");
|
||||||
|
nextAttemptTime = now + sec * 60 * 60; // 1 hour
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (numAttempts == 4)
|
||||||
|
{
|
||||||
|
log("4th failure: retry in 1 day");
|
||||||
|
nextAttemptTime = now + sec * 60 * 60 * 24; // 1 day
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
log("5th failure: giving up");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class QueuedIncomingSms extends QueuedMessage<SmsMessage> {
|
||||||
|
public QueuedIncomingSms(SmsMessage sms)
|
||||||
|
{
|
||||||
|
this.sms = sms;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class QueuedOutgoingSms extends QueuedMessage<OutgoingSmsMessage> {
|
||||||
|
public QueuedOutgoingSms(OutgoingSmsMessage sms)
|
||||||
|
{
|
||||||
|
this.sms = sms;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected App(Context context)
|
protected App(Context context)
|
||||||
{
|
{
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.settings = PreferenceManager.getDefaultSharedPreferences(context);
|
this.settings = PreferenceManager.getDefaultSharedPreferences(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static App app;
|
|
||||||
|
|
||||||
public static App getInstance(Context context)
|
public static App getInstance(Context context)
|
||||||
{
|
{
|
||||||
if (app == null)
|
if (app == null)
|
||||||
@ -58,7 +123,7 @@ public class App {
|
|||||||
return app;
|
return app;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void debug(String msg)
|
public void debug(String msg)
|
||||||
{
|
{
|
||||||
Log.d(LOG_NAME, msg);
|
Log.d(LOG_NAME, msg);
|
||||||
}
|
}
|
||||||
@ -176,49 +241,156 @@ public class App {
|
|||||||
return settings.getString("password", "");
|
return settings.getString("password", "");
|
||||||
}
|
}
|
||||||
|
|
||||||
public SQLiteDatabase getWritableDatabase()
|
private void notifyStatus(OutgoingSmsMessage sms, String status, String errorMessage)
|
||||||
{
|
|
||||||
return new DBHelper(context).getWritableDatabase();
|
|
||||||
}
|
|
||||||
|
|
||||||
public HttpClient getHttpClient()
|
|
||||||
{
|
|
||||||
HttpParams httpParameters = new BasicHttpParams();
|
|
||||||
HttpConnectionParams.setConnectionTimeout(httpParameters, 8000);
|
|
||||||
HttpConnectionParams.setSoTimeout(httpParameters, 8000);
|
|
||||||
return new DefaultHttpClient(httpParameters);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void sendSMS(OutgoingSmsMessage sms)
|
|
||||||
{
|
{
|
||||||
String serverId = sms.getServerId();
|
String serverId = sms.getServerId();
|
||||||
|
|
||||||
|
String logMessage;
|
||||||
|
if (status.equals(App.STATUS_SENT))
|
||||||
|
{
|
||||||
|
logMessage = "sent successfully";
|
||||||
|
}
|
||||||
|
else if (status.equals(App.STATUS_FAILED))
|
||||||
|
{
|
||||||
|
logMessage = "could not be sent (" + errorMessage + ")";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
logMessage = "queued";
|
||||||
|
}
|
||||||
|
String smsDesc = sms.getLogName();
|
||||||
|
|
||||||
if (serverId != null)
|
if (serverId != null)
|
||||||
{
|
{
|
||||||
SQLiteDatabase db = this.getWritableDatabase();
|
app.log("Notifying server " + smsDesc + " " + logMessage);
|
||||||
Cursor cursor =
|
|
||||||
db.rawQuery("select 1 from sms_status where server_id=?", new String[] { serverId });
|
|
||||||
|
|
||||||
boolean exists = (cursor.getCount() > 0);
|
new HttpTask(app).execute(
|
||||||
cursor.close();
|
new BasicNameValuePair("id", serverId),
|
||||||
if (exists)
|
new BasicNameValuePair("status", status),
|
||||||
|
new BasicNameValuePair("error", errorMessage),
|
||||||
|
new BasicNameValuePair("action", App.ACTION_SEND_STATUS)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
app.log(smsDesc + " " + logMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void retryStuckMessages(boolean retryAll)
|
||||||
|
{
|
||||||
|
retryStuckOutgoingMessages(retryAll);
|
||||||
|
retryStuckIncomingMessages(retryAll);
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized int getStuckMessageCount()
|
||||||
|
{
|
||||||
|
return outgoingSmsMap.size() + incomingSmsMap.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void retryStuckOutgoingMessages(boolean retryAll)
|
||||||
|
{
|
||||||
|
for (Entry<String, QueuedOutgoingSms> entry : outgoingSmsMap.entrySet())
|
||||||
|
{
|
||||||
|
QueuedOutgoingSms queuedSms = entry.getValue();
|
||||||
|
if (retryAll || queuedSms.canAttemptNow())
|
||||||
{
|
{
|
||||||
log(sms.getLogName() + " already sent, skipping");
|
queuedSms.nextAttemptTime = 0;
|
||||||
return;
|
|
||||||
|
log("Retrying sending " +queuedSms.sms.getLogName()
|
||||||
|
+ " to " + queuedSms.sms.getTo());
|
||||||
|
|
||||||
|
trySendSMS(queuedSms.sms);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ContentValues values = new ContentValues();
|
public synchronized void retryStuckIncomingMessages(boolean retryAll)
|
||||||
values.put("server_id", serverId);
|
{
|
||||||
values.put("status", App.STATUS_QUEUED);
|
for (Entry<String, QueuedIncomingSms> entry : incomingSmsMap.entrySet())
|
||||||
db.insert("sms_status", null, values);
|
{
|
||||||
|
QueuedIncomingSms queuedSms = entry.getValue();
|
||||||
|
if (retryAll || queuedSms.canAttemptNow())
|
||||||
|
{
|
||||||
|
queuedSms.nextAttemptTime = 0;
|
||||||
|
|
||||||
db.close();
|
log("Retrying forwarding SMS from " + queuedSms.sms.getOriginatingAddress());
|
||||||
|
|
||||||
|
trySendMessageToServer(queuedSms.sms);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void notifyOutgoingMessageStatus(String id, int resultCode)
|
||||||
|
{
|
||||||
|
QueuedOutgoingSms queuedSms = outgoingSmsMap.get(id);
|
||||||
|
|
||||||
|
if (queuedSms == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OutgoingSmsMessage sms = queuedSms.sms;
|
||||||
|
|
||||||
|
switch (resultCode) {
|
||||||
|
case Activity.RESULT_OK:
|
||||||
|
this.notifyStatus(sms, App.STATUS_SENT, "");
|
||||||
|
break;
|
||||||
|
case SmsManager.RESULT_ERROR_GENERIC_FAILURE:
|
||||||
|
this.notifyStatus(sms, App.STATUS_FAILED, "generic failure");
|
||||||
|
break;
|
||||||
|
case SmsManager.RESULT_ERROR_RADIO_OFF:
|
||||||
|
this.notifyStatus(sms, App.STATUS_FAILED, "radio off");
|
||||||
|
break;
|
||||||
|
case SmsManager.RESULT_ERROR_NO_SERVICE:
|
||||||
|
this.notifyStatus(sms, App.STATUS_FAILED, "no service");
|
||||||
|
break;
|
||||||
|
case SmsManager.RESULT_ERROR_NULL_PDU:
|
||||||
|
this.notifyStatus(sms, App.STATUS_FAILED, "null PDU");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
this.notifyStatus(sms, App.STATUS_FAILED, "unknown error");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (resultCode) {
|
||||||
|
case SmsManager.RESULT_ERROR_GENERIC_FAILURE:
|
||||||
|
case SmsManager.RESULT_ERROR_RADIO_OFF:
|
||||||
|
case SmsManager.RESULT_ERROR_NO_SERVICE:
|
||||||
|
if (!queuedSms.scheduleNextAttempt())
|
||||||
|
{
|
||||||
|
outgoingSmsMap.remove(id);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
outgoingSmsMap.remove(id);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void sendSMS(OutgoingSmsMessage sms)
|
||||||
|
{
|
||||||
|
String id = sms.getId();
|
||||||
|
if (outgoingSmsMap.containsKey(id))
|
||||||
|
{
|
||||||
|
log(sms.getLogName() + " already sent, skipping");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QueuedOutgoingSms queueEntry = new QueuedOutgoingSms(sms);
|
||||||
|
outgoingSmsMap.put(id, queueEntry);
|
||||||
|
|
||||||
|
log("Sending " +sms.getLogName() + " to " + sms.getTo());
|
||||||
|
trySendSMS(sms);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void trySendSMS(OutgoingSmsMessage sms)
|
||||||
|
{
|
||||||
SmsManager smgr = SmsManager.getDefault();
|
SmsManager smgr = SmsManager.getDefault();
|
||||||
|
|
||||||
Intent intent = new Intent(App.SEND_STATUS_INTENT);
|
Intent intent = new Intent(context, MessageStatusNotifier.class);
|
||||||
intent.putExtra("serverId", serverId);
|
intent.putExtra("id", sms.getId());
|
||||||
|
|
||||||
PendingIntent sentIntent = PendingIntent.getBroadcast(
|
PendingIntent sentIntent = PendingIntent.getBroadcast(
|
||||||
this.context,
|
this.context,
|
||||||
@ -226,7 +398,6 @@ public class App {
|
|||||||
intent,
|
intent,
|
||||||
PendingIntent.FLAG_ONE_SHOT);
|
PendingIntent.FLAG_ONE_SHOT);
|
||||||
|
|
||||||
log("Sending " +sms.getLogName() + " to " + sms.getTo());
|
|
||||||
smgr.sendTextMessage(sms.getTo(), null, sms.getMessage(), sentIntent, null);
|
smgr.sendTextMessage(sms.getTo(), null, sms.getMessage(), sentIntent, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -245,4 +416,86 @@ public class App {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private class ForwarderTask extends HttpTask {
|
||||||
|
|
||||||
|
private SmsMessage originalSms;
|
||||||
|
|
||||||
|
public ForwarderTask(SmsMessage originalSms) {
|
||||||
|
super(app);
|
||||||
|
this.originalSms = originalSms;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getDefaultToAddress()
|
||||||
|
{
|
||||||
|
return originalSms.getOriginatingAddress();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void handleResponse(HttpResponse response) throws Exception {
|
||||||
|
|
||||||
|
for (OutgoingSmsMessage reply : parseResponseXML(response)) {
|
||||||
|
app.sendSMS(reply);
|
||||||
|
}
|
||||||
|
|
||||||
|
app.notifyIncomingMessageStatus(originalSms, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void handleFailure()
|
||||||
|
{
|
||||||
|
app.notifyIncomingMessageStatus(originalSms, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getSmsId(SmsMessage sms)
|
||||||
|
{
|
||||||
|
return sms.getOriginatingAddress() + ":" + sms.getMessageBody() + ":" + sms.getTimestampMillis();
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void sendMessageToServer(SmsMessage sms)
|
||||||
|
{
|
||||||
|
String id = getSmsId(sms);
|
||||||
|
if (incomingSmsMap.containsKey(id))
|
||||||
|
{
|
||||||
|
log("Duplicate incoming SMS, skipping");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QueuedIncomingSms queuedSms = new QueuedIncomingSms(sms);
|
||||||
|
incomingSmsMap.put(id, queuedSms);
|
||||||
|
|
||||||
|
app.log("Received SMS from " + sms.getOriginatingAddress());
|
||||||
|
|
||||||
|
trySendMessageToServer(sms);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void trySendMessageToServer(SmsMessage sms)
|
||||||
|
{
|
||||||
|
String message = sms.getMessageBody();
|
||||||
|
String sender = sms.getOriginatingAddress();
|
||||||
|
|
||||||
|
new ForwarderTask(sms).execute(
|
||||||
|
new BasicNameValuePair("from", sender),
|
||||||
|
new BasicNameValuePair("message", message),
|
||||||
|
new BasicNameValuePair("action", App.ACTION_INCOMING)
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private synchronized void notifyIncomingMessageStatus(SmsMessage sms, boolean success)
|
||||||
|
{
|
||||||
|
String id = getSmsId(sms);
|
||||||
|
|
||||||
|
QueuedIncomingSms queuedSms = incomingSmsMap.get(id);
|
||||||
|
|
||||||
|
if (queuedSms != null)
|
||||||
|
{
|
||||||
|
if (success || !queuedSms.scheduleNextAttempt())
|
||||||
|
{
|
||||||
|
incomingSmsMap.remove(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,43 +0,0 @@
|
|||||||
/*
|
|
||||||
* To change this template, choose Tools | Templates
|
|
||||||
* and open the template in the editor.
|
|
||||||
*/
|
|
||||||
package org.envaya.kalsms;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.database.sqlite.SQLiteDatabase;
|
|
||||||
import android.database.sqlite.SQLiteOpenHelper;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author Jesse
|
|
||||||
*/
|
|
||||||
public class DBHelper extends SQLiteOpenHelper {
|
|
||||||
|
|
||||||
private static final int DATABASE_VERSION = 2;
|
|
||||||
private static final String DATABASE_NAME = "org.envaya.kalsms.db";
|
|
||||||
|
|
||||||
private static final String SMS_STATUS_TABLE_DROP =
|
|
||||||
" DROP TABLE sms_status;";
|
|
||||||
|
|
||||||
private static final String SMS_STATUS_TABLE_CREATE =
|
|
||||||
"CREATE TABLE sms_status (server_id text, status int);"
|
|
||||||
+ "CREATE INDEX server_id_index ON sent_sms (server_id);";
|
|
||||||
|
|
||||||
public DBHelper(Context context) {
|
|
||||||
super(context, DATABASE_NAME, null, DATABASE_VERSION);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCreate(SQLiteDatabase db) {
|
|
||||||
db.execSQL(SMS_STATUS_TABLE_CREATE);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
|
||||||
if (oldVersion < 2)
|
|
||||||
{
|
|
||||||
db.execSQL(SMS_STATUS_TABLE_CREATE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -19,7 +19,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.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.HttpConnectionParams;
|
||||||
|
import org.apache.http.params.HttpParams;
|
||||||
import org.w3c.dom.Document;
|
import org.w3c.dom.Document;
|
||||||
import org.w3c.dom.Element;
|
import org.w3c.dom.Element;
|
||||||
import org.w3c.dom.Node;
|
import org.w3c.dom.Node;
|
||||||
@ -36,6 +40,14 @@ public class HttpTask extends AsyncTask<BasicNameValuePair, Void, HttpResponse>
|
|||||||
this.app = app;
|
this.app = app;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public HttpClient getHttpClient()
|
||||||
|
{
|
||||||
|
HttpParams httpParameters = new BasicHttpParams();
|
||||||
|
HttpConnectionParams.setConnectionTimeout(httpParameters, 8000);
|
||||||
|
HttpConnectionParams.setSoTimeout(httpParameters, 8000);
|
||||||
|
return new DefaultHttpClient(httpParameters);
|
||||||
|
}
|
||||||
|
|
||||||
private String getSignature(String url, BasicNameValuePair... params)
|
private String getSignature(String url, BasicNameValuePair... params)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
@ -78,6 +90,12 @@ public class HttpTask extends AsyncTask<BasicNameValuePair, Void, HttpResponse>
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
String url = app.getServerUrl();
|
String url = app.getServerUrl();
|
||||||
|
|
||||||
|
if (url.length() == 0) {
|
||||||
|
app.log("Can't contact server; Server URL not set");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
HttpPost post = new HttpPost(url);
|
HttpPost post = new HttpPost(url);
|
||||||
|
|
||||||
post.setEntity(new UrlEncodedFormEntity(Arrays.asList(params)));
|
post.setEntity(new UrlEncodedFormEntity(Arrays.asList(params)));
|
||||||
@ -88,7 +106,7 @@ public class HttpTask extends AsyncTask<BasicNameValuePair, Void, HttpResponse>
|
|||||||
post.setHeader("X-Kalsms-PhoneNumber", app.getPhoneNumber());
|
post.setHeader("X-Kalsms-PhoneNumber", app.getPhoneNumber());
|
||||||
post.setHeader("X-Kalsms-Signature", signature);
|
post.setHeader("X-Kalsms-Signature", signature);
|
||||||
|
|
||||||
HttpClient client = app.getHttpClient();
|
HttpClient client = getHttpClient();
|
||||||
HttpResponse response = client.execute(post);
|
HttpResponse response = client.execute(post);
|
||||||
|
|
||||||
int statusCode = response.getStatusLine().getStatusCode();
|
int statusCode = response.getStatusLine().getStatusCode();
|
||||||
|
@ -5,8 +5,6 @@ import android.content.Context;
|
|||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.telephony.SmsMessage;
|
import android.telephony.SmsMessage;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import org.apache.http.HttpResponse;
|
import org.apache.http.HttpResponse;
|
||||||
|
|
||||||
import org.apache.http.message.BasicNameValuePair;
|
import org.apache.http.message.BasicNameValuePair;
|
||||||
@ -15,70 +13,6 @@ public class IncomingMessageForwarder extends BroadcastReceiver {
|
|||||||
|
|
||||||
private App app;
|
private App app;
|
||||||
|
|
||||||
private List<SmsStatus> retryList = new ArrayList<SmsStatus>();
|
|
||||||
|
|
||||||
private class SmsStatus
|
|
||||||
{
|
|
||||||
public SmsMessage smsMessage;
|
|
||||||
public long nextAttemptTime;
|
|
||||||
public int numAttempts = 0;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private class ForwarderTask extends HttpTask {
|
|
||||||
|
|
||||||
private SmsMessage originalSms;
|
|
||||||
|
|
||||||
public ForwarderTask(SmsMessage originalSms) {
|
|
||||||
super(app);
|
|
||||||
this.originalSms = originalSms;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected String getDefaultToAddress()
|
|
||||||
{
|
|
||||||
return originalSms.getOriginatingAddress();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void handleResponse(HttpResponse response) throws Exception {
|
|
||||||
for (OutgoingSmsMessage reply : parseResponseXML(response)) {
|
|
||||||
app.sendSMS(reply);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void sendMessageToServer(SmsMessage sms)
|
|
||||||
{
|
|
||||||
String serverUrl = app.getServerUrl();
|
|
||||||
String message = sms.getMessageBody();
|
|
||||||
String sender = sms.getOriginatingAddress();
|
|
||||||
|
|
||||||
app.log("Received SMS from " + sender);
|
|
||||||
|
|
||||||
if (serverUrl.length() == 0) {
|
|
||||||
app.log("Can't forward SMS to server; Server URL not set");
|
|
||||||
} else {
|
|
||||||
app.log("Forwarding incoming SMS to server");
|
|
||||||
|
|
||||||
new ForwarderTask(sms).execute(
|
|
||||||
new BasicNameValuePair("from", sender),
|
|
||||||
new BasicNameValuePair("message", message),
|
|
||||||
new BasicNameValuePair("action", App.ACTION_INCOMING)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void smsReceived(Intent intent) {
|
|
||||||
|
|
||||||
for (SmsMessage sms : getMessagesFromIntent(intent)) {
|
|
||||||
sendMessageToServer(sms);
|
|
||||||
|
|
||||||
//DeleteSMSFromInbox(context, mesg);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
// source: http://www.devx.com/wireless/Article/39495/1954
|
// source: http://www.devx.com/wireless/Article/39495/1954
|
||||||
public void onReceive(Context context, Intent intent) {
|
public void onReceive(Context context, Intent intent) {
|
||||||
@ -88,7 +22,12 @@ public class IncomingMessageForwarder extends BroadcastReceiver {
|
|||||||
String action = intent.getAction();
|
String action = intent.getAction();
|
||||||
|
|
||||||
if (action.equals("android.provider.Telephony.SMS_RECEIVED")) {
|
if (action.equals("android.provider.Telephony.SMS_RECEIVED")) {
|
||||||
smsReceived(intent);
|
|
||||||
|
for (SmsMessage sms : getMessagesFromIntent(intent)) {
|
||||||
|
app.sendMessageToServer(sms);
|
||||||
|
|
||||||
|
//DeleteSMSFromInbox(context, mesg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (Throwable ex) {
|
} catch (Throwable ex) {
|
||||||
app.logError("Unexpected error in IncomingMessageForwarder", ex, true);
|
app.logError("Unexpected error in IncomingMessageForwarder", ex, true);
|
||||||
|
@ -93,19 +93,11 @@ public class Main extends Activity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void onResume() {
|
|
||||||
App.debug("RESUME");
|
|
||||||
super.onResume();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Called when the activity is first created. */
|
/** Called when the activity is first created. */
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
App.debug("STARTED");
|
|
||||||
|
|
||||||
this.app = App.getInstance(this.getApplication());
|
this.app = App.getInstance(this.getApplication());
|
||||||
|
|
||||||
setContentView(R.layout.main);
|
setContentView(R.layout.main);
|
||||||
@ -138,6 +130,9 @@ public class Main extends Activity {
|
|||||||
case R.id.check_now:
|
case R.id.check_now:
|
||||||
app.checkOutgoingMessages();
|
app.checkOutgoingMessages();
|
||||||
return true;
|
return true;
|
||||||
|
case R.id.retry_now:
|
||||||
|
app.retryStuckMessages(true);
|
||||||
|
return true;
|
||||||
case R.id.help:
|
case R.id.help:
|
||||||
startActivity(new Intent(this, Help.class));
|
startActivity(new Intent(this, Help.class));
|
||||||
return true;
|
return true;
|
||||||
@ -161,6 +156,14 @@ public class Main extends Activity {
|
|||||||
return(true);
|
return(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onPrepareOptionsMenu(Menu menu) {
|
||||||
|
MenuItem item = menu.findItem(R.id.retry_now);
|
||||||
|
int stuckMessages = app.getStuckMessageCount();
|
||||||
|
item.setEnabled(stuckMessages > 0);
|
||||||
|
item.setTitle("Retry Now (" + stuckMessages + ")");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onStop(){
|
protected void onStop(){
|
||||||
|
@ -4,76 +4,21 @@
|
|||||||
*/
|
*/
|
||||||
package org.envaya.kalsms;
|
package org.envaya.kalsms;
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
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.telephony.SmsManager;
|
import android.telephony.SmsManager;
|
||||||
import org.apache.http.message.BasicNameValuePair;
|
|
||||||
|
|
||||||
public class MessageStatusNotifier extends BroadcastReceiver {
|
public class MessageStatusNotifier extends BroadcastReceiver {
|
||||||
|
|
||||||
private App app;
|
|
||||||
|
|
||||||
public void notifyStatus(String serverId, String status, String errorMessage)
|
|
||||||
{
|
|
||||||
String logMessage;
|
|
||||||
if (status.equals(App.STATUS_SENT))
|
|
||||||
{
|
|
||||||
logMessage = "sent successfully";
|
|
||||||
}
|
|
||||||
else if (status.equals(App.STATUS_FAILED))
|
|
||||||
{
|
|
||||||
logMessage = "could not be sent (" + errorMessage + ")";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
logMessage = "queued";
|
|
||||||
}
|
|
||||||
String smsDesc = serverId == null ? "SMS reply" : ("SMS id=" + serverId);
|
|
||||||
|
|
||||||
if (serverId != null)
|
|
||||||
{
|
|
||||||
app.log("Notifying server " + smsDesc + " " + logMessage);
|
|
||||||
|
|
||||||
new HttpTask(app).execute(
|
|
||||||
new BasicNameValuePair("id", serverId),
|
|
||||||
new BasicNameValuePair("status", status),
|
|
||||||
new BasicNameValuePair("error", errorMessage),
|
|
||||||
new BasicNameValuePair("action", App.ACTION_SEND_STATUS)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
app.log(smsDesc + " " + logMessage);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(Context context, Intent intent) {
|
public void onReceive(Context context, Intent intent) {
|
||||||
app = App.getInstance(context);
|
App app = App.getInstance(context);
|
||||||
|
|
||||||
String serverId = intent.getExtras().getString("serverId");
|
String id = intent.getExtras().getString("id");
|
||||||
|
|
||||||
switch (getResultCode()) {
|
int resultCode = getResultCode();
|
||||||
case Activity.RESULT_OK:
|
|
||||||
this.notifyStatus(serverId, App.STATUS_SENT, "");
|
app.notifyOutgoingMessageStatus(id, resultCode);
|
||||||
break;
|
|
||||||
case SmsManager.RESULT_ERROR_GENERIC_FAILURE:
|
|
||||||
this.notifyStatus(serverId, App.STATUS_FAILED, "generic failure");
|
|
||||||
break;
|
|
||||||
case SmsManager.RESULT_ERROR_RADIO_OFF:
|
|
||||||
this.notifyStatus(serverId, App.STATUS_FAILED, "radio off");
|
|
||||||
break;
|
|
||||||
case SmsManager.RESULT_ERROR_NO_SERVICE:
|
|
||||||
this.notifyStatus(serverId, App.STATUS_FAILED, "no service");
|
|
||||||
break;
|
|
||||||
case SmsManager.RESULT_ERROR_NULL_PDU:
|
|
||||||
this.notifyStatus(serverId, App.STATUS_FAILED, "null PDU");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
this.notifyStatus(serverId, App.STATUS_FAILED, "unknown error");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,5 +12,6 @@ public class OutgoingMessagePoller extends BroadcastReceiver {
|
|||||||
public void onReceive(Context context, Intent intent) {
|
public void onReceive(Context context, Intent intent) {
|
||||||
app = App.getInstance(context);
|
app = App.getInstance(context);
|
||||||
app.checkOutgoingMessages();
|
app.checkOutgoingMessages();
|
||||||
|
app.retryStuckMessages(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,8 +8,23 @@ public class OutgoingSmsMessage {
|
|||||||
private String from;
|
private String from;
|
||||||
private String to;
|
private String to;
|
||||||
|
|
||||||
|
private String localId;
|
||||||
|
|
||||||
|
private static int nextLocalId = 1;
|
||||||
|
|
||||||
public OutgoingSmsMessage()
|
public OutgoingSmsMessage()
|
||||||
{
|
{
|
||||||
|
this.localId = "_o" + getNextLocalId();
|
||||||
|
}
|
||||||
|
|
||||||
|
static synchronized int getNextLocalId()
|
||||||
|
{
|
||||||
|
return nextLocalId++;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getId()
|
||||||
|
{
|
||||||
|
return (serverId == null) ? localId : serverId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getLogName()
|
public String getLogName()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user