diff --git a/src/org/envaya/kalsms/App.java b/src/org/envaya/kalsms/App.java index 4e8afe2..5d4f9e6 100755 --- a/src/org/envaya/kalsms/App.java +++ b/src/org/envaya/kalsms/App.java @@ -1,26 +1,17 @@ -/* - * To change this template, choose Tools | Templates - * and open the template in the editor. - */ package org.envaya.kalsms; import android.app.Activity; import android.app.AlarmManager; import android.app.PendingIntent; -import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; -import android.database.Cursor; -import android.net.Uri; import android.os.SystemClock; import android.preference.PreferenceManager; import android.telephony.SmsManager; -import android.telephony.SmsMessage; import android.util.Log; import java.util.HashMap; import java.util.Map; -import org.apache.http.HttpResponse; import org.apache.http.message.BasicNameValuePair; public class App { @@ -34,104 +25,13 @@ public class App { public static final String LOG_NAME = "KALSMS"; public static final String LOG_INTENT = "org.envaya.kalsms.LOG"; private static App app; - private Map incomingSmsMap = new HashMap(); - private Map outgoingSmsMap = new HashMap(); + + private Map incomingSmsMap = new HashMap(); + private Map outgoingSmsMap = new HashMap(); + public Context context; public SharedPreferences settings; - private abstract class QueuedMessage { - - public T sms; - public long nextAttemptTime = 0; - public int numAttempts = 0; - - public boolean canAttemptNow() { - return (nextAttemptTime > 0 && nextAttemptTime < SystemClock.elapsedRealtime()); - } - - public boolean scheduleNextAttempt() { - long now = SystemClock.elapsedRealtime(); - numAttempts++; - - if (numAttempts > 4) { - log("5th failure: giving up"); - return false; - } - - int second = 1000; - int minute = second * 60; - - if (numAttempts == 1) { - log("1st failure; retry in 1 minute"); - nextAttemptTime = now + 1 * minute; - } else if (numAttempts == 2) { - log("2nd failure; retry in 10 minutes"); - nextAttemptTime = now + 10 * minute; - } else if (numAttempts == 3) { - log("3rd failure; retry in 1 hour"); - nextAttemptTime = now + 60 * minute; - } else { - log("4th failure: retry in 1 day"); - nextAttemptTime = now + 24 * 60 * minute; - } - - AlarmManager alarm = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); - - PendingIntent pendingIntent = PendingIntent.getBroadcast(context, - 0, - getAttemptIntent(), - 0); - - alarm.set( - AlarmManager.ELAPSED_REALTIME_WAKEUP, - nextAttemptTime, - pendingIntent); - - return true; - } - - public abstract void attemptNow(); - - protected abstract Intent getAttemptIntent(); - } - - private class QueuedIncomingSms extends QueuedMessage { - - public QueuedIncomingSms(SmsMessage sms) { - this.sms = sms; - } - - public void attemptNow() { - log("Retrying forwarding SMS from " + sms.getOriginatingAddress()); - trySendMessageToServer(sms); - } - - protected Intent getAttemptIntent() { - Intent intent = new Intent(context, IncomingMessageRetry.class); - intent.setData(Uri.parse("kalsms://incoming/" + getSmsId(sms))); - return intent; - } - } - - private class QueuedOutgoingSms extends QueuedMessage { - - public QueuedOutgoingSms(OutgoingSmsMessage sms) { - this.sms = sms; - } - - public void attemptNow() { - log("Retrying sending " + sms.getLogName() + " to " + sms.getTo()); - trySendSMS(sms); - } - - protected Intent getAttemptIntent() { - Intent intent = new Intent(context, OutgoingMessageRetry.class); - intent.setData(Uri.parse("kalsms://outgoing/" + sms.getId())); - log("id=" + sms.getId()); - return intent; - } - } - protected App(Context context) { this.context = context; this.settings = PreferenceManager.getDefaultSharedPreferences(context); @@ -144,24 +44,12 @@ public class App { return app; } - public void debug(String msg) { - Log.d(LOG_NAME, msg); - } - - public void log(String msg) { - Log.d(LOG_NAME, msg); - - Intent broadcast = new Intent(App.LOG_INTENT); - broadcast.putExtra("message", msg); - context.sendBroadcast(broadcast); - } - - public void checkOutgoingMessages() { + public void checkOutgoingMessages() + { String serverUrl = getServerUrl(); if (serverUrl.length() > 0) { log("Checking for outgoing messages"); - new PollerTask().execute( - new BasicNameValuePair("action", App.ACTION_OUTGOING)); + new PollerTask(this).execute(); } else { log("Can't check outgoing messages; server URL not set"); } @@ -191,28 +79,6 @@ public class App { } } - public void logError(Throwable ex) { - logError("ERROR", ex); - } - - public void logError(String msg, Throwable ex) { - logError(msg, ex, false); - } - - public void logError(String msg, Throwable ex, boolean detail) { - log(msg + ": " + ex.getClass().getName() + ": " + ex.getMessage()); - - if (detail) { - for (StackTraceElement elem : ex.getStackTrace()) { - log(elem.getClassName() + ":" + elem.getMethodName() + ":" + elem.getLineNumber()); - } - Throwable innerEx = ex.getCause(); - if (innerEx != null) { - logError("Inner exception:", innerEx, true); - } - } - } - public String getDisplayString(String str) { if (str.length() == 0) { return "(not set)"; @@ -246,7 +112,7 @@ public class App { return settings.getString("password", ""); } - private void notifyStatus(OutgoingSmsMessage sms, String status, String errorMessage) { + private void notifyStatus(OutgoingMessage sms, String status, String errorMessage) { String serverId = sms.getServerId(); String logMessage; @@ -262,11 +128,12 @@ public class App { 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)); + new HttpTask(app, + new BasicNameValuePair("id", serverId), + new BasicNameValuePair("status", status), + new BasicNameValuePair("error", errorMessage), + new BasicNameValuePair("action", App.ACTION_SEND_STATUS) + ).execute(); } else { app.log(smsDesc + " " + logMessage); } @@ -282,26 +149,36 @@ public class App { } public synchronized void retryStuckOutgoingMessages() { - for (QueuedOutgoingSms queuedSms : outgoingSmsMap.values()) { - queuedSms.attemptNow(); + for (OutgoingMessage sms : outgoingSmsMap.values()) { + sms.retryNow(); } } public synchronized void retryStuckIncomingMessages() { - for (QueuedIncomingSms queuedSms : incomingSmsMap.values()) { - queuedSms.attemptNow(); + for (IncomingMessage sms : incomingSmsMap.values()) { + sms.retryNow(); } } + + public synchronized void setIncomingMessageStatus(IncomingMessage sms, boolean success) { + String id = sms.getId(); + if (success) + { + incomingSmsMap.remove(id); + } + else if (!sms.scheduleRetry()) + { + incomingSmsMap.remove(id); + } + } public synchronized void notifyOutgoingMessageStatus(String id, int resultCode) { - QueuedOutgoingSms queuedSms = outgoingSmsMap.get(id); + OutgoingMessage sms = outgoingSmsMap.get(id); - if (queuedSms == null) { + if (sms == null) { return; } - OutgoingSmsMessage sms = queuedSms.sms; - switch (resultCode) { case Activity.RESULT_OK: this.notifyStatus(sms, App.STATUS_SENT, ""); @@ -327,7 +204,7 @@ public class App { case SmsManager.RESULT_ERROR_GENERIC_FAILURE: case SmsManager.RESULT_ERROR_RADIO_OFF: case SmsManager.RESULT_ERROR_NO_SERVICE: - if (!queuedSms.scheduleNextAttempt()) { + if (!sms.scheduleRetry()) { outgoingSmsMap.remove(id); } break; @@ -335,135 +212,82 @@ public class App { outgoingSmsMap.remove(id); break; } - } - public synchronized void sendSMS(OutgoingSmsMessage sms) { + public synchronized void sendOutgoingMessage(OutgoingMessage 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); + outgoingSmsMap.put(id, sms); log("Sending " + sms.getLogName() + " to " + sms.getTo()); - trySendSMS(sms); + sms.trySend(); } - private void trySendSMS(OutgoingSmsMessage sms) { - SmsManager smgr = SmsManager.getDefault(); - - Intent intent = new Intent(context, MessageStatusNotifier.class); - intent.setData(Uri.parse("kalsms://outgoing/" + sms.getId())); - - PendingIntent sentIntent = PendingIntent.getBroadcast( - this.context, - 0, - intent, - PendingIntent.FLAG_ONE_SHOT); - - smgr.sendTextMessage(sms.getTo(), null, sms.getMessage(), sentIntent, null); - } - - private class PollerTask extends HttpTask { - - public PollerTask() { - super(app); - } - - @Override - protected void handleResponse(HttpResponse response) throws Exception { - for (OutgoingSmsMessage reply : parseResponseXML(response)) { - app.sendSMS(reply); - } - } - } - - 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); + public synchronized void forwardToServer(IncomingMessage sms) { + String id = sms.getId(); + if (incomingSmsMap.containsKey(id)) { log("Duplicate incoming SMS, skipping"); return; } - QueuedIncomingSms queuedSms = new QueuedIncomingSms(sms); - incomingSmsMap.put(id, queuedSms); + incomingSmsMap.put(id, sms); - app.log("Received SMS from " + sms.getOriginatingAddress()); + app.log("Received SMS from " + sms.getFrom()); - 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); - } - } + sms.tryForwardToServer(); } public synchronized void retryIncomingMessage(String id) { - QueuedIncomingSms queuedSms = incomingSmsMap.get(id); - if (queuedSms != null) { - queuedSms.attemptNow(); + IncomingMessage sms = incomingSmsMap.get(id); + if (sms != null) { + sms.retryNow(); } } public synchronized void retryOutgoingMessage(String id) { - QueuedOutgoingSms queuedSms = outgoingSmsMap.get(id); - if (queuedSms != null) { - queuedSms.attemptNow(); + OutgoingMessage sms = outgoingSmsMap.get(id); + if (sms != null) { + sms.retryNow(); } } + + public void debug(String msg) { + Log.d(LOG_NAME, msg); + } + + public void log(String msg) { + Log.d(LOG_NAME, msg); + + Intent broadcast = new Intent(App.LOG_INTENT); + broadcast.putExtra("message", msg); + context.sendBroadcast(broadcast); + } + + public void logError(Throwable ex) { + logError("ERROR", ex); + } + + public void logError(String msg, Throwable ex) { + logError(msg, ex, false); + } + + public void logError(String msg, Throwable ex, boolean detail) { + log(msg + ": " + ex.getClass().getName() + ": " + ex.getMessage()); + + if (detail) { + for (StackTraceElement elem : ex.getStackTrace()) { + log(elem.getClassName() + ":" + elem.getMethodName() + ":" + elem.getLineNumber()); + } + Throwable innerEx = ex.getCause(); + if (innerEx != null) { + logError("Inner exception:", innerEx, true); + } + } + } + } diff --git a/src/org/envaya/kalsms/ForwarderTask.java b/src/org/envaya/kalsms/ForwarderTask.java new file mode 100755 index 0000000..6439934 --- /dev/null +++ b/src/org/envaya/kalsms/ForwarderTask.java @@ -0,0 +1,36 @@ +package org.envaya.kalsms; + +import org.apache.http.HttpResponse; +import org.apache.http.message.BasicNameValuePair; + +public class ForwarderTask extends HttpTask { + + private IncomingMessage originalSms; + + public ForwarderTask(IncomingMessage originalSms, BasicNameValuePair... paramsArr) { + super(originalSms.app, paramsArr); + this.originalSms = originalSms; + + params.add(new BasicNameValuePair("action", App.ACTION_INCOMING)); + } + + @Override + protected String getDefaultToAddress() { + return originalSms.getFrom(); + } + + @Override + protected void handleResponse(HttpResponse response) throws Exception { + + for (OutgoingMessage reply : parseResponseXML(response)) { + app.sendOutgoingMessage(reply); + } + + app.setIncomingMessageStatus(originalSms, true); + } + + @Override + protected void handleFailure() { + app.setIncomingMessageStatus(originalSms, false); + } +} diff --git a/src/org/envaya/kalsms/HttpTask.java b/src/org/envaya/kalsms/HttpTask.java index 938a581..c8bc9df 100755 --- a/src/org/envaya/kalsms/HttpTask.java +++ b/src/org/envaya/kalsms/HttpTask.java @@ -33,14 +33,21 @@ import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; -public class HttpTask extends AsyncTask { +public class HttpTask extends AsyncTask { - private App app; + protected App app; - public HttpTask(App app) + protected String url; + protected List params = new ArrayList(); + + public HttpTask(App app, BasicNameValuePair... paramsArr) { super(); - this.app = app; + this.app = app; + this.url = app.getServerUrl(); + params = new ArrayList(Arrays.asList(paramsArr)); + params.add(new BasicNameValuePair("version", "2")); + params.add(new BasicNameValuePair("phone_number", app.getPhoneNumber())); } public HttpClient getHttpClient() @@ -51,7 +58,7 @@ public class HttpTask extends AsyncTask return new DefaultHttpClient(httpParameters); } - private String getSignature(String url, List params) + private String getSignature() throws NoSuchAlgorithmException, UnsupportedEncodingException { Collections.sort(params, new Comparator() { @@ -83,27 +90,19 @@ public class HttpTask extends AsyncTask return new String(Base64Coder.encode(digest)); } - protected HttpResponse doInBackground(BasicNameValuePair... params) { + protected HttpResponse doInBackground(String... ignored) { try { - 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); - - List paramList - = new ArrayList(Arrays.asList(params)); - - paramList.add(new BasicNameValuePair("version", "2")); - paramList.add(new BasicNameValuePair("phone_number", app.getPhoneNumber())); - - post.setEntity(new UrlEncodedFormEntity(paramList)); + + post.setEntity(new UrlEncodedFormEntity(params)); - String signature = this.getSignature(url, paramList); + String signature = getSignature(); post.setHeader("X-Kalsms-Signature", signature); @@ -145,10 +144,10 @@ public class HttpTask extends AsyncTask return ""; } - protected List parseResponseXML(HttpResponse response) + protected List parseResponseXML(HttpResponse response) throws IOException, ParserConfigurationException, SAXException { - List messages = new ArrayList(); + List messages = new ArrayList(); InputStream responseStream = response.getEntity().getContent(); DocumentBuilder xmlBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); Document xml = xmlBuilder.parse(responseStream); @@ -156,7 +155,8 @@ public class HttpTask extends AsyncTask NodeList smsNodes = xml.getElementsByTagName("Sms"); for (int i = 0; i < smsNodes.getLength(); i++) { Element smsElement = (Element) smsNodes.item(i); - OutgoingSmsMessage sms = new OutgoingSmsMessage(); + + OutgoingMessage sms = new OutgoingMessage(app); sms.setFrom(app.getPhoneNumber()); @@ -169,7 +169,7 @@ public class HttpTask extends AsyncTask sms.setServerId(serverId.equals("") ? null : serverId); Node firstChild = smsElement.getFirstChild(); - sms.setMessage(firstChild != null ? firstChild.getNodeValue(): ""); + sms.setMessageBody(firstChild != null ? firstChild.getNodeValue(): ""); messages.add(sms); } diff --git a/src/org/envaya/kalsms/IncomingMessage.java b/src/org/envaya/kalsms/IncomingMessage.java new file mode 100755 index 0000000..73a09d4 --- /dev/null +++ b/src/org/envaya/kalsms/IncomingMessage.java @@ -0,0 +1,50 @@ +package org.envaya.kalsms; + +import android.content.Intent; +import android.net.Uri; +import android.telephony.SmsMessage; +import org.apache.http.message.BasicNameValuePair; + +public class IncomingMessage extends QueuedMessage { + + public SmsMessage sms; + + public IncomingMessage(App app, SmsMessage sms) { + super(app); + this.sms = sms; + } + + public String getMessageBody() + { + return sms.getMessageBody(); + } + + public String getFrom() + { + return sms.getOriginatingAddress(); + } + + public String getId() + { + return sms.getOriginatingAddress() + ":" + sms.getMessageBody() + ":" + sms.getTimestampMillis(); + } + + public void retryNow() { + app.log("Retrying forwarding SMS from " + sms.getOriginatingAddress()); + tryForwardToServer(); + } + + public void tryForwardToServer() { + new ForwarderTask(this, + new BasicNameValuePair("from", getFrom()), + new BasicNameValuePair("message", getMessageBody()) + ).execute(); + } + + + protected Intent getRetryIntent() { + Intent intent = new Intent(app.context, IncomingMessageRetry.class); + intent.setData(Uri.parse("kalsms://incoming/" + this.getId())); + return intent; + } +} diff --git a/src/org/envaya/kalsms/IncomingMessageForwarder.java b/src/org/envaya/kalsms/IncomingMessageForwarder.java index adf80d6..3c4d43d 100755 --- a/src/org/envaya/kalsms/IncomingMessageForwarder.java +++ b/src/org/envaya/kalsms/IncomingMessageForwarder.java @@ -5,6 +5,8 @@ import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.telephony.SmsMessage; +import java.util.ArrayList; +import java.util.List; public class IncomingMessageForwarder extends BroadcastReceiver { @@ -21,8 +23,8 @@ public class IncomingMessageForwarder extends BroadcastReceiver { if (action.equals("android.provider.Telephony.SMS_RECEIVED")) { - for (SmsMessage sms : getMessagesFromIntent(intent)) { - app.sendMessageToServer(sms); + for (IncomingMessage sms : getMessagesFromIntent(intent)) { + app.forwardToServer(sms); } if (!app.getKeepInInbox()) @@ -37,15 +39,16 @@ public class IncomingMessageForwarder extends BroadcastReceiver { // from http://github.com/dimagi/rapidandroid // source: http://www.devx.com/wireless/Article/39495/1954 - private SmsMessage[] getMessagesFromIntent(Intent intent) { - SmsMessage retMsgs[] = null; - Bundle bdl = intent.getExtras(); - Object pdus[] = (Object[]) bdl.get("pdus"); - retMsgs = new SmsMessage[pdus.length]; - for (int n = 0; n < pdus.length; n++) { - byte[] byteData = (byte[]) pdus[n]; - retMsgs[n] = SmsMessage.createFromPdu(byteData); + private List getMessagesFromIntent(Intent intent) + { + Bundle bundle = intent.getExtras(); + List messages = new ArrayList(); + + for (Object pdu : (Object[]) bundle.get("pdus")) + { + SmsMessage sms = SmsMessage.createFromPdu((byte[]) pdu); + messages.add(new IncomingMessage(app, sms)); } - return retMsgs; + return messages; } } \ No newline at end of file diff --git a/src/org/envaya/kalsms/Main.java b/src/org/envaya/kalsms/Main.java index 0fb931f..fac47fc 100755 --- a/src/org/envaya/kalsms/Main.java +++ b/src/org/envaya/kalsms/Main.java @@ -34,14 +34,13 @@ public class Main extends Activity { private class TestTask extends HttpTask { public TestTask() { - super(app); + super(Main.this.app, new BasicNameValuePair("action", App.ACTION_OUTGOING)); } @Override protected void handleResponse(HttpResponse response) throws Exception { - parseResponseXML(response); - + parseResponseXML(response); app.log("Server connection OK!"); } } @@ -138,9 +137,7 @@ public class Main extends Activity { return true; case R.id.test: app.log("Testing server connection..."); - new TestTask().execute( - new BasicNameValuePair("action", App.ACTION_OUTGOING) - ); + new TestTask().execute(); return true; default: return super.onOptionsItemSelected(item); diff --git a/src/org/envaya/kalsms/OutgoingMessage.java b/src/org/envaya/kalsms/OutgoingMessage.java new file mode 100755 index 0000000..335eb95 --- /dev/null +++ b/src/org/envaya/kalsms/OutgoingMessage.java @@ -0,0 +1,107 @@ + +package org.envaya.kalsms; + +import android.app.PendingIntent; +import android.content.Intent; +import android.net.Uri; +import android.telephony.SmsManager; + +public class OutgoingMessage extends QueuedMessage { + + private String serverId; + private String message; + private String from; + private String to; + + private String localId; + + private static int nextLocalId = 1; + + public OutgoingMessage(App app) + { + super(app); + this.localId = "_o" + getNextLocalId(); + } + + static synchronized int getNextLocalId() + { + return nextLocalId++; + } + + public String getId() + { + return (serverId == null) ? localId : serverId; + } + + public String getLogName() + { + return (serverId == null) ? "SMS reply" : ("SMS id=" + serverId); + } + + public String getServerId() + { + return serverId; + } + + public void setServerId(String id) + { + this.serverId = id; + } + + public String getMessageBody() + { + return message; + } + + public void setMessageBody(String message) + { + this.message = message; + } + + public String getFrom() + { + return from; + } + + public void setFrom(String from) + { + this.from = from; + } + + public String getTo() + { + return to; + } + + public void setTo(String to) + { + this.to = to; + } + + public void retryNow() { + app.log("Retrying sending " + getLogName() + " to " + getTo()); + trySend(); + } + + public void trySend() + { + SmsManager smgr = SmsManager.getDefault(); + + Intent intent = new Intent(app.context, MessageStatusNotifier.class); + intent.setData(Uri.parse("kalsms://outgoing/" + getId())); + + PendingIntent sentIntent = PendingIntent.getBroadcast( + app.context, + 0, + intent, + PendingIntent.FLAG_ONE_SHOT); + + smgr.sendTextMessage(getTo(), null, getMessageBody(), sentIntent, null); + } + + protected Intent getRetryIntent() { + Intent intent = new Intent(app.context, OutgoingMessageRetry.class); + intent.setData(Uri.parse("kalsms://outgoing/" + getId())); + return intent; + } +} diff --git a/src/org/envaya/kalsms/OutgoingSmsMessage.java b/src/org/envaya/kalsms/OutgoingSmsMessage.java deleted file mode 100755 index 8b7ddf5..0000000 --- a/src/org/envaya/kalsms/OutgoingSmsMessage.java +++ /dev/null @@ -1,75 +0,0 @@ - -package org.envaya.kalsms; - -public class OutgoingSmsMessage { - - private String serverId; - private String message; - private String from; - private String to; - - private String localId; - - private static int nextLocalId = 1; - - public OutgoingSmsMessage() - { - this.localId = "_o" + getNextLocalId(); - } - - static synchronized int getNextLocalId() - { - return nextLocalId++; - } - - public String getId() - { - return (serverId == null) ? localId : serverId; - } - - public String getLogName() - { - return (serverId == null) ? "SMS reply" : ("SMS id=" + serverId); - } - - public String getServerId() - { - return serverId; - } - - public void setServerId(String id) - { - this.serverId = id; - } - - public String getMessage() - { - return message; - } - - public void setMessage(String message) - { - this.message = message; - } - - public String getFrom() - { - return from; - } - - public void setFrom(String from) - { - this.from = from; - } - - public String getTo() - { - return to; - } - - public void setTo(String to) - { - this.to = to; - } - -} diff --git a/src/org/envaya/kalsms/PollerTask.java b/src/org/envaya/kalsms/PollerTask.java new file mode 100755 index 0000000..b7a1526 --- /dev/null +++ b/src/org/envaya/kalsms/PollerTask.java @@ -0,0 +1,19 @@ + +package org.envaya.kalsms; + +import org.apache.http.HttpResponse; +import org.apache.http.message.BasicNameValuePair; + +public class PollerTask extends HttpTask { + + public PollerTask(App app) { + super(app, new BasicNameValuePair("action", App.ACTION_OUTGOING)); + } + + @Override + protected void handleResponse(HttpResponse response) throws Exception { + for (OutgoingMessage reply : parseResponseXML(response)) { + app.sendOutgoingMessage(reply); + } + } +} \ No newline at end of file diff --git a/src/org/envaya/kalsms/QueuedMessage.java b/src/org/envaya/kalsms/QueuedMessage.java new file mode 100755 index 0000000..7d887e8 --- /dev/null +++ b/src/org/envaya/kalsms/QueuedMessage.java @@ -0,0 +1,69 @@ +package org.envaya.kalsms; + +import android.app.AlarmManager; +import android.app.PendingIntent; +import android.content.Context; +import android.content.Intent; +import android.os.SystemClock; + +public abstract class QueuedMessage +{ + protected long nextRetryTime = 0; + protected int numRetries = 0; + + public App app; + + public QueuedMessage(App app) + { + this.app = app; + } + + public boolean canRetryNow() { + return (nextRetryTime > 0 && nextRetryTime < SystemClock.elapsedRealtime()); + } + + public boolean scheduleRetry() { + long now = SystemClock.elapsedRealtime(); + numRetries++; + + if (numRetries > 4) { + app.log("5th failure: giving up"); + return false; + } + + int second = 1000; + int minute = second * 60; + + if (numRetries == 1) { + app.log("1st failure; retry in 1 minute"); + nextRetryTime = now + 1 * minute; + } else if (numRetries == 2) { + app.log("2nd failure; retry in 10 minutes"); + nextRetryTime = now + 10 * minute; + } else if (numRetries == 3) { + app.log("3rd failure; retry in 1 hour"); + nextRetryTime = now + 60 * minute; + } else { + app.log("4th failure: retry in 1 day"); + nextRetryTime = now + 24 * 60 * minute; + } + + AlarmManager alarm = (AlarmManager) app.context.getSystemService(Context.ALARM_SERVICE); + + PendingIntent pendingIntent = PendingIntent.getBroadcast(app.context, + 0, + getRetryIntent(), + 0); + + alarm.set( + AlarmManager.ELAPSED_REALTIME_WAKEUP, + nextRetryTime, + pendingIntent); + + return true; + } + + public abstract void retryNow(); + + protected abstract Intent getRetryIntent(); +}