mirror of
https://github.com/cwinfo/envayasms.git
synced 2024-11-09 10:20:25 +00:00
do http requests in AsyncTask so they don't freeze the UI thread; improve log messages; make poll interval configurable
This commit is contained in:
parent
9473ab1610
commit
fc6cda4ea3
@ -25,18 +25,17 @@
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<receiver android:name=".OutgoingMessagePoller">
|
||||
</receiver>
|
||||
|
||||
<receiver android:name=".MessageStatusNotifier">
|
||||
<intent-filter>
|
||||
<action android:name="org.envaya.kalsms.SEND_STATUS" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<receiver android:name=".OutgoingMessagePoller">
|
||||
</receiver>
|
||||
|
||||
<activity android:name=".Prefs"
|
||||
android:label="@string/app_name">
|
||||
</activity>
|
||||
|
||||
</application>
|
||||
</manifest>
|
@ -8,6 +8,6 @@
|
||||
# project structure.
|
||||
|
||||
# Project target.
|
||||
target=android-4
|
||||
target=android-8
|
||||
# Indicates whether an apk should be generated for each density.
|
||||
split.density=false
|
||||
|
@ -1,10 +0,0 @@
|
||||
# This file is automatically generated by Android Tools.
|
||||
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
|
||||
#
|
||||
# This file must *NOT* be checked in Version Control Systems,
|
||||
# as it contains information specific to your local configuration.
|
||||
|
||||
# location of the SDK. This is only used by Ant
|
||||
# For customization when using a Version Control System, please read the
|
||||
# header note.
|
||||
sdk.dir=C:\\android-sdk
|
@ -3,11 +3,14 @@
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent" android:background="#333333">
|
||||
<ScrollView android:id="@+id/info_scroll" android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent" android:layout_weight="1">
|
||||
<TextView
|
||||
android:scrollbars="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:id="@+id/info"
|
||||
android:textColor="#FFFFFF"
|
||||
android:layout_margin="5px"></TextView>
|
||||
</ScrollView>
|
||||
</LinearLayout>
|
||||
|
27
res/values/arrays.xml
Executable file
27
res/values/arrays.xml
Executable file
@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<string-array name="check_intervals">
|
||||
<item>15 sec</item>
|
||||
<item>30 sec</item>
|
||||
<item>1 minute</item>
|
||||
<item>2 minutes</item>
|
||||
<item>5 minutes</item>
|
||||
<item>10 minutes</item>
|
||||
<item>30 minutes</item>
|
||||
<item>1 hour</item>
|
||||
<item>never</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="check_intervals_values">
|
||||
<item>15</item>
|
||||
<item>30</item>
|
||||
<item>60</item>
|
||||
<item>120</item>
|
||||
<item>300</item>
|
||||
<item>600</item>
|
||||
<item>1800</item>
|
||||
<item>3600</item>
|
||||
<item>0</item>
|
||||
</string-array>
|
||||
</resources>
|
@ -4,13 +4,13 @@
|
||||
<EditTextPreference
|
||||
android:key="server_url"
|
||||
android:title="Server URL"
|
||||
android:defaultValue="http://192.168.70.1:3000/"
|
||||
android:defaultValue=""
|
||||
></EditTextPreference>
|
||||
|
||||
<EditTextPreference
|
||||
android:key="phone_number"
|
||||
android:title="Your Phone Number"
|
||||
android:defaultValue="16507993371"
|
||||
android:defaultValue=""
|
||||
></EditTextPreference>
|
||||
|
||||
<EditTextPreference
|
||||
@ -19,9 +19,19 @@
|
||||
android:password="true"
|
||||
></EditTextPreference>
|
||||
|
||||
<ListPreference
|
||||
android:key="outgoing_interval"
|
||||
android:title="Poll interval"
|
||||
android:defaultValue="60"
|
||||
android:entries="@array/check_intervals"
|
||||
android:entryValues="@array/check_intervals_values"
|
||||
></ListPreference>
|
||||
|
||||
<!--
|
||||
<CheckBoxPreference
|
||||
android:key="detailed_log"
|
||||
android:title="Detailed log messages?"
|
||||
android:disableDependentsState="false"
|
||||
></CheckBoxPreference>
|
||||
-->
|
||||
</PreferenceScreen>
|
@ -4,6 +4,7 @@
|
||||
*/
|
||||
package org.envaya.kalsms;
|
||||
|
||||
import android.app.AlarmManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
@ -11,17 +12,27 @@ import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.os.SystemClock;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.telephony.SmsManager;
|
||||
import android.util.Log;
|
||||
import java.text.DateFormat;
|
||||
import java.util.Date;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.impl.client.DefaultHttpClient;
|
||||
import org.apache.http.params.BasicHttpParams;
|
||||
import org.apache.http.params.HttpConnectionParams;
|
||||
import org.apache.http.params.HttpParams;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Jesse
|
||||
*/
|
||||
public class App {
|
||||
|
||||
public static final int OUTGOING_POLL_SECONDS = 30;
|
||||
public static final String ACTION_OUTGOING = "outgoing";
|
||||
public static final String ACTION_INCOMING = "incoming";
|
||||
public static final String ACTION_SEND_STATUS = "send_status";
|
||||
|
||||
public static final int STATUS_QUEUED = 1;
|
||||
public static final int STATUS_FAILED = 2;
|
||||
public static final int STATUS_SENT = 3;
|
||||
|
||||
public static final String LOG_NAME = "KALSMS";
|
||||
public static final String LOG_INTENT = "org.envaya.kalsms.LOG";
|
||||
@ -30,12 +41,23 @@ public class App {
|
||||
public Context context;
|
||||
public SharedPreferences settings;
|
||||
|
||||
public App(Context context)
|
||||
protected App(Context context)
|
||||
{
|
||||
this.context = context;
|
||||
this.settings = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
}
|
||||
|
||||
private static App app;
|
||||
|
||||
public static App getInstance(Context context)
|
||||
{
|
||||
if (app == null)
|
||||
{
|
||||
app = new App(context);
|
||||
}
|
||||
return app;
|
||||
}
|
||||
|
||||
static void debug(String msg)
|
||||
{
|
||||
Log.d(LOG_NAME, msg);
|
||||
@ -50,6 +72,34 @@ public class App {
|
||||
context.sendBroadcast(broadcast);
|
||||
}
|
||||
|
||||
public void setOutgoingMessageAlarm()
|
||||
{
|
||||
AlarmManager alarm = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
|
||||
|
||||
PendingIntent pendingIntent = PendingIntent.getBroadcast(context,
|
||||
0,
|
||||
new Intent(context, OutgoingMessagePoller.class),
|
||||
0);
|
||||
|
||||
alarm.cancel(pendingIntent);
|
||||
|
||||
int pollSeconds = getOutgoingPollSeconds();
|
||||
|
||||
if (pollSeconds > 0)
|
||||
{
|
||||
alarm.setRepeating(
|
||||
AlarmManager.ELAPSED_REALTIME_WAKEUP,
|
||||
SystemClock.elapsedRealtime(),
|
||||
pollSeconds * 1000,
|
||||
pendingIntent);
|
||||
log("Checking for outgoing messages every " + pollSeconds + " sec");
|
||||
}
|
||||
else
|
||||
{
|
||||
log("Not checking for outgoing messages.");
|
||||
}
|
||||
}
|
||||
|
||||
public void logError(Throwable ex)
|
||||
{
|
||||
logError("ERROR", ex);
|
||||
@ -78,19 +128,16 @@ public class App {
|
||||
}
|
||||
}
|
||||
|
||||
public String getIncomingUrl()
|
||||
public String getDisplayString(String str)
|
||||
{
|
||||
return getServerUrl() + "/pg/receive_sms";
|
||||
if (str.length() == 0)
|
||||
{
|
||||
return "(not set)";
|
||||
}
|
||||
|
||||
public String getOutgoingUrl()
|
||||
else
|
||||
{
|
||||
return getServerUrl() + "/pg/dequeue_sms";
|
||||
return str;
|
||||
}
|
||||
|
||||
public String getSendStatusUrl()
|
||||
{
|
||||
return getServerUrl() + "/pg/sms_sent";
|
||||
}
|
||||
|
||||
public String getServerUrl()
|
||||
@ -103,6 +150,11 @@ public class App {
|
||||
return settings.getString("phone_number", "");
|
||||
}
|
||||
|
||||
public int getOutgoingPollSeconds()
|
||||
{
|
||||
return Integer.parseInt(settings.getString("outgoing_interval", "0"));
|
||||
}
|
||||
|
||||
public String getPassword()
|
||||
{
|
||||
return settings.getString("password", "");
|
||||
@ -111,11 +163,15 @@ public class App {
|
||||
private SQLiteDatabase db;
|
||||
public SQLiteDatabase getWritableDatabase()
|
||||
{
|
||||
if (db == null)
|
||||
{
|
||||
db = new DBHelper(context).getWritableDatabase();
|
||||
return new DBHelper(context).getWritableDatabase();
|
||||
}
|
||||
return db;
|
||||
|
||||
public HttpClient getHttpClient()
|
||||
{
|
||||
HttpParams httpParameters = new BasicHttpParams();
|
||||
HttpConnectionParams.setConnectionTimeout(httpParameters, 8000);
|
||||
HttpConnectionParams.setSoTimeout(httpParameters, 8000);
|
||||
return new DefaultHttpClient(httpParameters);
|
||||
}
|
||||
|
||||
public void sendSMS(OutgoingSmsMessage sms)
|
||||
@ -126,7 +182,7 @@ public class App {
|
||||
{
|
||||
SQLiteDatabase db = this.getWritableDatabase();
|
||||
Cursor cursor =
|
||||
db.rawQuery("select 1 from sent_sms where server_id=?", new String[] { serverId });
|
||||
db.rawQuery("select 1 from sms_status where server_id=?", new String[] { serverId });
|
||||
|
||||
boolean exists = (cursor.getCount() > 0);
|
||||
cursor.close();
|
||||
@ -138,7 +194,10 @@ public class App {
|
||||
|
||||
ContentValues values = new ContentValues();
|
||||
values.put("server_id", serverId);
|
||||
db.insert("sent_sms", null, values);
|
||||
values.put("status", App.STATUS_QUEUED);
|
||||
db.insert("sms_status", null, values);
|
||||
|
||||
db.close();
|
||||
}
|
||||
|
||||
SmsManager smgr = SmsManager.getDefault();
|
||||
|
@ -14,11 +14,14 @@ import android.database.sqlite.SQLiteOpenHelper;
|
||||
*/
|
||||
public class DBHelper extends SQLiteOpenHelper {
|
||||
|
||||
private static final int DATABASE_VERSION = 1;
|
||||
private static final int DATABASE_VERSION = 2;
|
||||
private static final String DATABASE_NAME = "org.envaya.kalsms.db";
|
||||
|
||||
private static final String SENT_SMS_TABLE_CREATE =
|
||||
"CREATE TABLE sent_sms (server_id text);"
|
||||
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) {
|
||||
@ -27,11 +30,14 @@ public class DBHelper extends SQLiteOpenHelper {
|
||||
|
||||
@Override
|
||||
public void onCreate(SQLiteDatabase db) {
|
||||
db.execSQL(SENT_SMS_TABLE_CREATE);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
181
src/org/envaya/kalsms/HttpTask.java
Executable file
181
src/org/envaya/kalsms/HttpTask.java
Executable file
@ -0,0 +1,181 @@
|
||||
/*
|
||||
* To change this template, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package org.envaya.kalsms;
|
||||
|
||||
import android.os.AsyncTask;
|
||||
import android.util.Base64;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.security.MessageDigest;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.entity.UrlEncodedFormEntity;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.message.BasicNameValuePair;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
public class HttpTask extends AsyncTask<BasicNameValuePair, Void, HttpResponse> {
|
||||
|
||||
private App app;
|
||||
|
||||
public HttpTask(App app)
|
||||
{
|
||||
super();
|
||||
this.app = app;
|
||||
}
|
||||
|
||||
private String getSignature(String url, BasicNameValuePair... params)
|
||||
{
|
||||
try {
|
||||
Arrays.sort(params, new Comparator() {
|
||||
public int compare(Object o1, Object o2)
|
||||
{
|
||||
return ((BasicNameValuePair)o1).getName().compareTo(((BasicNameValuePair)o2).getName());
|
||||
}
|
||||
});
|
||||
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append(url);
|
||||
for (BasicNameValuePair param : params)
|
||||
{
|
||||
builder.append(",");
|
||||
builder.append(param.getName());
|
||||
builder.append("=");
|
||||
builder.append(param.getValue());
|
||||
}
|
||||
builder.append(",");
|
||||
builder.append(app.getPassword());
|
||||
|
||||
String value = builder.toString();
|
||||
|
||||
MessageDigest md = MessageDigest.getInstance("SHA-1");
|
||||
|
||||
md.update(value.getBytes("utf-8"));
|
||||
|
||||
byte[] digest = md.digest();
|
||||
|
||||
return Base64.encodeToString(digest, Base64.NO_WRAP);
|
||||
|
||||
} catch (Exception ex) {
|
||||
app.logError("Error computing signature", ex);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
protected HttpResponse doInBackground(BasicNameValuePair... params) {
|
||||
try
|
||||
{
|
||||
String url = app.getServerUrl();
|
||||
HttpPost post = new HttpPost(url);
|
||||
|
||||
post.setEntity(new UrlEncodedFormEntity(Arrays.asList(params)));
|
||||
|
||||
String signature = this.getSignature(url, params);
|
||||
|
||||
post.setHeader("X-Kalsms-PhoneNumber", app.getPhoneNumber());
|
||||
post.setHeader("X-Kalsms-Signature", signature);
|
||||
|
||||
HttpClient client = app.getHttpClient();
|
||||
HttpResponse response = client.execute(post);
|
||||
|
||||
int statusCode = response.getStatusLine().getStatusCode();
|
||||
if (statusCode == 200)
|
||||
{
|
||||
return response;
|
||||
}
|
||||
else if (statusCode == 403)
|
||||
{
|
||||
app.log("Failed to authenticate to server");
|
||||
app.log("(Phone number or password may be incorrect)");
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
app.log("Received HTTP " + statusCode + " from server");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
catch (Throwable ex)
|
||||
{
|
||||
app.logError("Error while contacting server", ex);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
protected String getDefaultToAddress()
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
protected List<OutgoingSmsMessage> parseResponseXML(HttpResponse response)
|
||||
throws IOException, ParserConfigurationException, SAXException
|
||||
{
|
||||
List<OutgoingSmsMessage> messages = new ArrayList<OutgoingSmsMessage>();
|
||||
InputStream responseStream = response.getEntity().getContent();
|
||||
DocumentBuilder xmlBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
|
||||
Document xml = xmlBuilder.parse(responseStream);
|
||||
|
||||
NodeList smsNodes = xml.getElementsByTagName("Sms");
|
||||
for (int i = 0; i < smsNodes.getLength(); i++) {
|
||||
Element smsElement = (Element) smsNodes.item(i);
|
||||
OutgoingSmsMessage sms = new OutgoingSmsMessage();
|
||||
|
||||
sms.setFrom(app.getPhoneNumber());
|
||||
|
||||
String to = smsElement.getAttribute("to");
|
||||
|
||||
sms.setTo(to.equals("") ? getDefaultToAddress() : to);
|
||||
|
||||
String serverId = smsElement.getAttribute("id");
|
||||
|
||||
sms.setServerId(serverId.equals("") ? null : serverId);
|
||||
|
||||
Node firstChild = smsElement.getFirstChild();
|
||||
sms.setMessage(firstChild != null ? firstChild.getNodeValue(): "");
|
||||
|
||||
messages.add(sms);
|
||||
}
|
||||
return messages;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(HttpResponse response) {
|
||||
if (response != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
handleResponse(response);
|
||||
}
|
||||
catch (Throwable ex)
|
||||
{
|
||||
app.logError("Error processing server response", ex);
|
||||
handleFailure();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
handleFailure();
|
||||
}
|
||||
}
|
||||
|
||||
protected void handleResponse(HttpResponse response) throws Exception
|
||||
{
|
||||
}
|
||||
|
||||
protected void handleFailure()
|
||||
{
|
||||
}
|
||||
}
|
@ -1,115 +1,91 @@
|
||||
package org.envaya.kalsms;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.PendingIntent;
|
||||
import java.util.ArrayList;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.telephony.SmsManager;
|
||||
import android.telephony.SmsMessage;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.NodeList;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import org.apache.http.NameValuePair;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.entity.UrlEncodedFormEntity;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.impl.client.DefaultHttpClient;
|
||||
import org.apache.http.message.BasicNameValuePair;
|
||||
|
||||
public class IncomingMessageForwarder extends BroadcastReceiver {
|
||||
|
||||
private App app;
|
||||
|
||||
public List<OutgoingSmsMessage> sendMessageToServer(SmsMessage sms) {
|
||||
private List<SmsStatus> retryList = new ArrayList<SmsStatus>();
|
||||
|
||||
String message = sms.getDisplayMessageBody();
|
||||
String sender = sms.getDisplayOriginatingAddress();
|
||||
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();
|
||||
String recipient = app.getPhoneNumber();
|
||||
|
||||
app.log("Received SMS from " + sender);
|
||||
|
||||
if (message == null || message.length() == 0) {
|
||||
return new ArrayList<OutgoingSmsMessage>();
|
||||
}
|
||||
|
||||
List<OutgoingSmsMessage> replies = new ArrayList<OutgoingSmsMessage>();
|
||||
|
||||
try {
|
||||
|
||||
List<NameValuePair> params = new ArrayList<NameValuePair>();
|
||||
params.add(new BasicNameValuePair("from", sender));
|
||||
params.add(new BasicNameValuePair("to", recipient));
|
||||
params.add(new BasicNameValuePair("message", message));
|
||||
params.add(new BasicNameValuePair("secret", app.getPassword()));
|
||||
|
||||
HttpClient client = new DefaultHttpClient();
|
||||
HttpPost post = new HttpPost(app.getIncomingUrl());
|
||||
post.setEntity(new UrlEncodedFormEntity(params));
|
||||
|
||||
if (serverUrl.length() == 0) {
|
||||
app.log("Can't forward SMS to server; Server URL not set");
|
||||
} else {
|
||||
app.log("Forwarding incoming SMS to server");
|
||||
|
||||
HttpResponse response = client.execute(post);
|
||||
|
||||
InputStream responseStream = response.getEntity().getContent();
|
||||
DocumentBuilder xmlBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
|
||||
Document xml = xmlBuilder.parse(responseStream);
|
||||
|
||||
NodeList smsNodes = xml.getElementsByTagName("Sms");
|
||||
for (int i = 0; i < smsNodes.getLength(); i++) {
|
||||
Element smsElement = (Element) smsNodes.item(i);
|
||||
|
||||
OutgoingSmsMessage reply = new OutgoingSmsMessage();
|
||||
|
||||
reply.setFrom(recipient);
|
||||
reply.setTo(sender);
|
||||
reply.setMessage(smsElement.getFirstChild().getNodeValue());
|
||||
|
||||
replies.add(reply);
|
||||
new ForwarderTask(sms).execute(
|
||||
new BasicNameValuePair("from", sender),
|
||||
new BasicNameValuePair("to", recipient),
|
||||
new BasicNameValuePair("message", message),
|
||||
new BasicNameValuePair("action", App.ACTION_INCOMING)
|
||||
);
|
||||
}
|
||||
} catch (SAXException ex) {
|
||||
app.logError("Error parsing response from server while forwarding incoming message", ex);
|
||||
} catch (IOException ex) {
|
||||
app.logError("Error forwarding incoming message to server", ex);
|
||||
} catch (ParserConfigurationException ex) {
|
||||
app.logError("Error configuring XML parser", ex);
|
||||
}
|
||||
|
||||
return replies;
|
||||
}
|
||||
|
||||
public void smsReceived(Intent intent) {
|
||||
|
||||
for (SmsMessage sms : getMessagesFromIntent(intent)) {
|
||||
List<OutgoingSmsMessage> replies = sendMessageToServer(sms);
|
||||
|
||||
for (OutgoingSmsMessage reply : replies)
|
||||
{
|
||||
app.sendSMS(reply);
|
||||
}
|
||||
sendMessageToServer(sms);
|
||||
|
||||
//DeleteSMSFromInbox(context, mesg);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
// source: http://www.devx.com/wireless/Article/39495/1954
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
try {
|
||||
this.app = new App(context);
|
||||
this.app = App.getInstance(context);
|
||||
|
||||
String action = intent.getAction();
|
||||
|
||||
@ -143,10 +119,8 @@ 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();
|
||||
|
@ -1,19 +1,20 @@
|
||||
package org.envaya.kalsms;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlarmManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.os.Bundle;
|
||||
import android.os.SystemClock;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.text.Html;
|
||||
import android.text.method.ScrollingMovementMethod;
|
||||
import android.view.Menu;
|
||||
import android.view.View;
|
||||
import android.widget.ScrollView;
|
||||
import android.widget.TextView;
|
||||
import java.text.DateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
public class Main extends Activity {
|
||||
|
||||
@ -24,15 +25,54 @@ public class Main extends Activity {
|
||||
}
|
||||
};
|
||||
|
||||
private long lastLogTime = 0;
|
||||
|
||||
public void showLogMessage(String message)
|
||||
{
|
||||
TextView info = (TextView) Main.this.findViewById(R.id.info);
|
||||
if (message != null)
|
||||
{
|
||||
int length = info.length();
|
||||
int maxLength = 20000;
|
||||
if (length > maxLength)
|
||||
{
|
||||
CharSequence text = info.getText();
|
||||
|
||||
int startPos = length - maxLength / 2;
|
||||
|
||||
for (int cur = startPos; cur < startPos + 100 && cur < length; cur++)
|
||||
{
|
||||
if (text.charAt(cur) == '\n')
|
||||
{
|
||||
startPos = cur;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
CharSequence endSequence = text.subSequence(startPos, length);
|
||||
|
||||
info.setText("[Older log messages not shown]");
|
||||
info.append(endSequence);
|
||||
}
|
||||
|
||||
long logTime = System.currentTimeMillis();
|
||||
if (logTime - lastLogTime > 60000)
|
||||
{
|
||||
Date date = new Date(logTime);
|
||||
info.append("[" + DateFormat.getTimeInstance().format(date) + "]\n");
|
||||
lastLogTime = logTime;
|
||||
}
|
||||
|
||||
info.append(message + "\n");
|
||||
|
||||
final ScrollView scrollView = (ScrollView) this.findViewById(R.id.info_scroll);
|
||||
scrollView.post(new Runnable() { public void run() {
|
||||
scrollView.fullScroll(View.FOCUS_DOWN);
|
||||
} });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void onResume() {
|
||||
App.debug("RESUME");
|
||||
super.onResume();
|
||||
@ -45,40 +85,31 @@ public class Main extends Activity {
|
||||
|
||||
App.debug("STARTED");
|
||||
|
||||
App app = App.getInstance(this.getApplication());
|
||||
|
||||
setContentView(R.layout.main);
|
||||
PreferenceManager.setDefaultValues(this, R.xml.prefs, false);
|
||||
|
||||
AlarmManager alarm = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
|
||||
|
||||
PendingIntent pendingIntent = PendingIntent.getBroadcast(this,
|
||||
0,
|
||||
new Intent(this, OutgoingMessagePoller.class),
|
||||
0);
|
||||
|
||||
alarm.setRepeating(
|
||||
AlarmManager.ELAPSED_REALTIME_WAKEUP,
|
||||
SystemClock.elapsedRealtime(),
|
||||
App.OUTGOING_POLL_SECONDS * 1000,
|
||||
pendingIntent);
|
||||
|
||||
App app = new App(this.getApplication());
|
||||
|
||||
TextView info = (TextView) this.findViewById(R.id.info);
|
||||
|
||||
info.setText(Html.fromHtml("<b>SMS Gateway running.</b><br />"));
|
||||
|
||||
showLogMessage("Server URL is: " + app.getServerUrl());
|
||||
showLogMessage("Your phone number is: " + app.getPhoneNumber());
|
||||
showLogMessage("Checking for outgoing messages every " + App.OUTGOING_POLL_SECONDS + " sec");
|
||||
|
||||
info.append(Html.fromHtml("<b>Press Menu to edit settings.</b><br />"));
|
||||
|
||||
showLogMessage("Server URL is: " + app.getDisplayString(app.getServerUrl()));
|
||||
showLogMessage("Your phone number is: " + app.getDisplayString(app.getPhoneNumber()));
|
||||
|
||||
info.setMovementMethod(new ScrollingMovementMethod());
|
||||
|
||||
IntentFilter logReceiverFilter = new IntentFilter();
|
||||
|
||||
logReceiverFilter.addAction(App.LOG_INTENT);
|
||||
registerReceiver(logReceiver, logReceiverFilter);
|
||||
|
||||
app.setOutgoingMessageAlarm();
|
||||
|
||||
for (int i = 0; i < 30; i++)
|
||||
{
|
||||
showLogMessage(" " + i);
|
||||
}
|
||||
}
|
||||
|
||||
// first time the Menu key is pressed
|
||||
|
@ -9,73 +9,71 @@ import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.telephony.SmsManager;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.NameValuePair;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.entity.UrlEncodedFormEntity;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.impl.client.DefaultHttpClient;
|
||||
import org.apache.http.message.BasicNameValuePair;
|
||||
|
||||
public class MessageStatusNotifier extends BroadcastReceiver {
|
||||
|
||||
private App app;
|
||||
|
||||
public void notifySuccess(String serverId)
|
||||
public void notifyStatus(String serverId, int status, String errorMessage)
|
||||
{
|
||||
String logMessage;
|
||||
switch (status)
|
||||
{
|
||||
case App.STATUS_SENT:
|
||||
logMessage = "sent successfully";
|
||||
break;
|
||||
case App.STATUS_FAILED:
|
||||
logMessage = "could not be sent (" + errorMessage + ")";
|
||||
break;
|
||||
default:
|
||||
logMessage = "queued";
|
||||
break;
|
||||
}
|
||||
String smsDesc = serverId == null ? "SMS reply" : ("SMS id=" + serverId);
|
||||
|
||||
if (serverId != null)
|
||||
{
|
||||
try {
|
||||
app.log("Notifying server of sent SMS id=" + serverId);
|
||||
List<NameValuePair> params = new ArrayList<NameValuePair>();
|
||||
params.add(new BasicNameValuePair("from", app.getPhoneNumber()));
|
||||
params.add(new BasicNameValuePair("secret", app.getPassword()));
|
||||
params.add(new BasicNameValuePair("id", serverId));
|
||||
app.log("Notifying server " + smsDesc + " " + logMessage);
|
||||
|
||||
HttpClient client = new DefaultHttpClient();
|
||||
HttpPost post = new HttpPost(app.getSendStatusUrl());
|
||||
post.setEntity(new UrlEncodedFormEntity(params));
|
||||
|
||||
client.execute(post);
|
||||
new HttpTask(app).execute(
|
||||
new BasicNameValuePair("from", app.getPhoneNumber()),
|
||||
new BasicNameValuePair("id", serverId),
|
||||
new BasicNameValuePair("status", "" + status),
|
||||
new BasicNameValuePair("error", errorMessage),
|
||||
new BasicNameValuePair("action", App.ACTION_SEND_STATUS)
|
||||
);
|
||||
}
|
||||
catch (IOException ex)
|
||||
else
|
||||
{
|
||||
app.logError("Error while notifying server of outgoing message", ex);
|
||||
}
|
||||
app.log(smsDesc + " " + logMessage);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
app = new App(context);
|
||||
app = App.getInstance(context);
|
||||
|
||||
String serverId = intent.getExtras().getString("serverId");
|
||||
|
||||
String desc = serverId == null ? "SMS reply" : ("SMS id=" + serverId);
|
||||
|
||||
switch (getResultCode()) {
|
||||
case Activity.RESULT_OK:
|
||||
app.log(desc + " sent successfully");
|
||||
this.notifySuccess(serverId);
|
||||
this.notifyStatus(serverId, App.STATUS_SENT, "");
|
||||
break;
|
||||
case SmsManager.RESULT_ERROR_GENERIC_FAILURE:
|
||||
app.log(desc + " could not be sent (generic failure)");
|
||||
this.notifyStatus(serverId, App.STATUS_FAILED, "generic failure");
|
||||
break;
|
||||
case SmsManager.RESULT_ERROR_RADIO_OFF:
|
||||
app.log(desc + " could not be sent (radio off)");
|
||||
this.notifyStatus(serverId, App.STATUS_FAILED, "radio off");
|
||||
break;
|
||||
case SmsManager.RESULT_ERROR_NO_SERVICE:
|
||||
app.log(desc + " could not be sent (no service)");
|
||||
this.notifyStatus(serverId, App.STATUS_FAILED, "no service");
|
||||
break;
|
||||
case SmsManager.RESULT_ERROR_NULL_PDU:
|
||||
app.log(desc + " could not be sent (null PDU");
|
||||
this.notifyStatus(serverId, App.STATUS_FAILED, "null PDU");
|
||||
break;
|
||||
default:
|
||||
app.log("SMS could not be sent (unknown error)");
|
||||
this.notifyStatus(serverId, App.STATUS_FAILED, "unknown error");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1,89 +1,42 @@
|
||||
package org.envaya.kalsms;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.NameValuePair;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.entity.UrlEncodedFormEntity;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.impl.client.DefaultHttpClient;
|
||||
import org.apache.http.message.BasicNameValuePair;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.NodeList;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
public class OutgoingMessagePoller extends BroadcastReceiver {
|
||||
|
||||
private App app;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
try
|
||||
{
|
||||
app = new App(context);
|
||||
app = App.getInstance(context);
|
||||
|
||||
String serverUrl = app.getServerUrl();
|
||||
if (serverUrl.length() > 0)
|
||||
{
|
||||
app.log("Checking for outgoing messages");
|
||||
|
||||
for (OutgoingSmsMessage sms : getOutgoingMessages())
|
||||
{
|
||||
app.sendSMS(sms);
|
||||
new PollerTask().execute(
|
||||
new BasicNameValuePair("from", app.getPhoneNumber()),
|
||||
new BasicNameValuePair("action", App.ACTION_OUTGOING)
|
||||
);
|
||||
}
|
||||
}
|
||||
catch (Throwable ex)
|
||||
{
|
||||
app.logError("Unexpected error in OutgoingMessagePoller", ex, true);
|
||||
}
|
||||
}
|
||||
|
||||
public List<OutgoingSmsMessage> getOutgoingMessages() {
|
||||
List<OutgoingSmsMessage> messages = new ArrayList<OutgoingSmsMessage>();
|
||||
|
||||
try {
|
||||
List<NameValuePair> params = new ArrayList<NameValuePair>();
|
||||
params.add(new BasicNameValuePair("from", app.getPhoneNumber()));
|
||||
params.add(new BasicNameValuePair("secret", app.getPassword()));
|
||||
|
||||
HttpClient client = new DefaultHttpClient();
|
||||
HttpPost post = new HttpPost(app.getOutgoingUrl());
|
||||
post.setEntity(new UrlEncodedFormEntity(params));
|
||||
|
||||
HttpResponse response = client.execute(post);
|
||||
|
||||
InputStream responseStream = response.getEntity().getContent();
|
||||
DocumentBuilder xmlBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
|
||||
Document xml = xmlBuilder.parse(responseStream);
|
||||
|
||||
NodeList smsNodes = xml.getElementsByTagName("Sms");
|
||||
for (int i = 0; i < smsNodes.getLength(); i++) {
|
||||
Element smsElement = (Element) smsNodes.item(i);
|
||||
OutgoingSmsMessage sms = new OutgoingSmsMessage();
|
||||
|
||||
sms.setFrom(app.getPhoneNumber());
|
||||
sms.setTo(smsElement.getAttribute("to"));
|
||||
sms.setMessage(smsElement.getFirstChild().getNodeValue());
|
||||
sms.setServerId(smsElement.getAttribute("id"));
|
||||
|
||||
messages.add(sms);
|
||||
}
|
||||
} catch (SAXException ex) {
|
||||
app.logError("Error parsing response from server while retreiving outgoing messages", ex);
|
||||
} catch (IOException ex) {
|
||||
app.logError("Error retreiving outgoing messages from server", ex);
|
||||
} catch (ParserConfigurationException ex) {
|
||||
app.logError("Error configuring XML parser", ex);
|
||||
}
|
||||
|
||||
return messages;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -4,7 +4,11 @@ import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
|
||||
import android.os.Bundle;
|
||||
import android.preference.EditTextPreference;
|
||||
import android.preference.ListPreference;
|
||||
import android.preference.Preference;
|
||||
import android.preference.PreferenceActivity;
|
||||
import android.preference.PreferenceScreen;
|
||||
import android.view.Menu;
|
||||
|
||||
public class Prefs extends PreferenceActivity implements OnSharedPreferenceChangeListener {
|
||||
@ -13,6 +17,14 @@ public class Prefs extends PreferenceActivity implements OnSharedPreferenceChang
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
addPreferencesFromResource(R.xml.prefs);
|
||||
|
||||
PreferenceScreen screen = this.getPreferenceScreen();
|
||||
int numPrefs = screen.getPreferenceCount();
|
||||
|
||||
for(int i=0; i < numPrefs;i++)
|
||||
{
|
||||
updatePrefSummary(screen.getPreference(i));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -30,29 +42,50 @@ public class Prefs extends PreferenceActivity implements OnSharedPreferenceChang
|
||||
}
|
||||
|
||||
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
|
||||
/*
|
||||
Preference pref = findPreference(key);
|
||||
if (pref instanceof EditTextPreference) {
|
||||
EditTextPreference textPref = (EditTextPreference) pref;
|
||||
pref.setSummary(textPref.getSummary());
|
||||
Log.d("KALSMS", "textPref.getSummary(): " + textPref.getSummary());
|
||||
|
||||
App app = App.getInstance(this.getApplication());
|
||||
if (key.equals("outgoing_interval"))
|
||||
{
|
||||
app.setOutgoingMessageAlarm();
|
||||
}
|
||||
if(pref instanceof CheckBoxPreference) {
|
||||
CheckBoxPreference checkbox = (CheckBoxPreference) pref;
|
||||
AlarmManager alarm = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
|
||||
Intent pintent = new Intent(this, SMSSender.class);
|
||||
PendingIntent pIntent = PendingIntent.getBroadcast(this,0,pintent, 0);
|
||||
if(checkbox.isChecked()) {
|
||||
alarm.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
|
||||
SystemClock.elapsedRealtime(),
|
||||
AlarmManager.INTERVAL_FIFTEEN_MINUTES, pIntent);
|
||||
Log.d("KALSMS", "alarm manager turned on");
|
||||
} else {
|
||||
alarm.cancel(pIntent);
|
||||
Log.d("SMS_GATEWAY", "alarm manager turned off");
|
||||
else if (key.equals("server_url"))
|
||||
{
|
||||
app.log("Server URL changed to: " + app.getDisplayString(app.getServerUrl()));
|
||||
}
|
||||
else if (key.equals("phone_number"))
|
||||
{
|
||||
app.log("Phone number changed to: " + app.getDisplayString(app.getPhoneNumber()));
|
||||
}
|
||||
else if (key.equals("password"))
|
||||
{
|
||||
app.log("Password changed");
|
||||
}
|
||||
|
||||
updatePrefSummary(findPreference(key));
|
||||
}
|
||||
|
||||
private void updatePrefSummary(Preference p)
|
||||
{
|
||||
if (p instanceof ListPreference) {
|
||||
p.setSummary(((ListPreference)p).getEntry());
|
||||
}
|
||||
else if (p instanceof EditTextPreference) {
|
||||
|
||||
EditTextPreference textPref = (EditTextPreference)p;
|
||||
String text = textPref.getText();
|
||||
if (text.equals(""))
|
||||
{
|
||||
p.setSummary("(not set)");
|
||||
}
|
||||
else if (p.getKey().equals("password"))
|
||||
{
|
||||
p.setSummary("********");
|
||||
}
|
||||
else
|
||||
{
|
||||
p.setSummary(text);
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
// first time the Menu key is pressed
|
||||
|
Loading…
Reference in New Issue
Block a user