4
0
mirror of https://github.com/cwinfo/envayasms.git synced 2025-07-03 05:37:44 +00:00

send new log messages to server on each HTTP request; notify server of changes in device status (currently power/battery state)

This commit is contained in:
Jesse Young
2011-10-10 16:19:38 -07:00
parent f253f54704
commit 2889bf9b4b
11 changed files with 259 additions and 31 deletions

View File

@ -26,8 +26,10 @@ import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import org.apache.http.client.HttpClient;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
@ -41,6 +43,7 @@ import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.envaya.sms.receiver.OutgoingMessagePoller;
import org.envaya.sms.receiver.ReenableWifiReceiver;
import org.envaya.sms.task.HttpTask;
import org.envaya.sms.task.PollerTask;
import org.json.JSONArray;
import org.json.JSONException;
@ -50,12 +53,18 @@ public final class App extends Application {
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 String ACTION_DEVICE_STATUS = "device_status";
public static final String ACTION_TEST = "test";
public static final String STATUS_QUEUED = "queued";
public static final String STATUS_FAILED = "failed";
public static final String STATUS_SENT = "sent";
public static final String DEVICE_STATUS_POWER_CONNECTED = "power_connected";
public static final String DEVICE_STATUS_POWER_DISCONNECTED = "power_disconnected";
public static final String DEVICE_STATUS_BATTERY_LOW = "battery_low";
public static final String DEVICE_STATUS_BATTERY_OKAY = "battery_okay";
public static final String MESSAGE_TYPE_MMS = "mms";
public static final String MESSAGE_TYPE_SMS = "sms";
@ -114,6 +123,8 @@ public final class App extends Application {
public final Inbox inbox = new Inbox(this);
public final Outbox outbox = new Outbox(this);
public final Queue<HttpTask> queuedTasks = new LinkedList<HttpTask>();
private SharedPreferences settings;
private MmsObserver mmsObserver;
private SpannableStringBuilder displayedLog = new SpannableStringBuilder();
@ -427,10 +438,11 @@ public final class App extends Application {
public synchronized void retryStuckMessages() {
outbox.retryAll();
inbox.retryAll();
retryQueuedTasks();
}
public synchronized int getPendingMessageCount() {
return outbox.size() + inbox.size();
public synchronized int getPendingTaskCount() {
return outbox.size() + inbox.size() + queuedTasks.size();
}
public void debug(String msg) {
@ -439,8 +451,24 @@ public final class App extends Application {
private int logEpoch = 0;
public synchronized void log(CharSequence msg)
private StringBuilder newLogBuffer = new StringBuilder();
public synchronized String getNewLogEntries()
{
String res = newLogBuffer.toString();
newLogBuffer.setLength(0);
return res;
}
// clients may sometimes unget log entries out of order,
// but most of the time this will be the right order
public synchronized void ungetNewLogEntries(String logEntries)
{
newLogBuffer.insert(0, logEntries);
}
public synchronized void log(CharSequence msg)
{
Log.d(LOG_NAME, msg.toString());
// prevent displayed log from growing too big
@ -462,6 +490,8 @@ public final class App extends Application {
logEpoch++;
}
int prevLength = displayedLog.length();
// display a timestamp in the log occasionally
long logTime = SystemClock.elapsedRealtime();
if (logTime - lastLogTime > LOG_TIMESTAMP_INTERVAL)
@ -472,8 +502,10 @@ public final class App extends Application {
}
displayedLog.append(msg);
displayedLog.append("\n");
displayedLog.append("\n");
newLogBuffer.append(displayedLog, prevLength, displayedLog.length());
sendBroadcast(new Intent(App.LOG_CHANGED_INTENT));
}
@ -670,12 +702,23 @@ public final class App extends Application {
if (activeNetwork == null || !activeNetwork.isConnected())
{
WifiManager wmgr = (WifiManager)getSystemService(Context.WIFI_SERVICE);
WifiManager wmgr = (WifiManager)getSystemService(Context.WIFI_SERVICE);
if (activeNetwork != null)
{
log(activeNetwork.getTypeName() + "=" + activeNetwork.getState());
}
else
{
log("Not connected to any network.");
}
if (!wmgr.isWifiEnabled() && isNetworkFailoverEnabled())
{
log("Enabling WIFI...");
wmgr.setWifiEnabled(true);
}
return;
}
@ -799,7 +842,28 @@ public final class App extends Application {
if (getOutgoingPollSeconds() > 0)
{
checkOutgoingMessages();
}
// failed outgoing message status notifications are dropped...
}
retryQueuedTasks();
}
public synchronized void retryQueuedTasks()
{
while (true)
{
HttpTask task = queuedTasks.poll();
if (task == null)
{
break;
}
task.execute();
}
}
public synchronized void addQueuedTask(HttpTask task)
{
queuedTasks.add(task);
}
}

View File

@ -57,8 +57,8 @@ public class Outbox {
this.app = app;
}
private void notifyMessageStatus(OutgoingMessage sms, String status, String errorMessage) {
String serverId = sms.getServerId();
private void notifyMessageStatus(OutgoingMessage sms, final String status, final String errorMessage) {
final String serverId = sms.getServerId();
String logMessage;
if (status.equals(App.STATUS_SENT)) {
@ -73,12 +73,15 @@ public class Outbox {
if (serverId != null) {
app.log("Notifying server " + smsDesc + " " + logMessage);
new HttpTask(app,
HttpTask task = new HttpTask(app,
new BasicNameValuePair("id", serverId),
new BasicNameValuePair("status", status),
new BasicNameValuePair("error", errorMessage),
new BasicNameValuePair("action", App.ACTION_SEND_STATUS)
).execute();
);
task.setRetryOnConnectivityError(true);
task.execute();
} else {
app.log(smsDesc + " " + logMessage);
}

View File

@ -0,0 +1,53 @@
package org.envaya.sms.receiver;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import org.apache.http.message.BasicNameValuePair;
import org.envaya.sms.App;
import org.envaya.sms.task.HttpTask;
public class DeviceStatusReceiver extends BroadcastReceiver
{
@Override
public void onReceive(Context context, Intent intent)
{
App app = (App) context.getApplicationContext();
if (!app.isEnabled())
{
return;
}
String action = intent.getAction();
String status = "";
if (Intent.ACTION_POWER_CONNECTED.equals(action))
{
status = App.DEVICE_STATUS_POWER_CONNECTED;
app.log("Power connected");
}
else if (Intent.ACTION_POWER_DISCONNECTED.equals(action))
{
status = App.DEVICE_STATUS_POWER_DISCONNECTED;
app.log("Power disconnected");
}
else if (Intent.ACTION_BATTERY_LOW.equals(action))
{
status = App.DEVICE_STATUS_BATTERY_LOW;
app.log("Battery low");
}
else if (Intent.ACTION_BATTERY_OKAY.equals(action))
{
status = App.DEVICE_STATUS_BATTERY_OKAY;
app.log("Battery okay");
}
HttpTask task = new HttpTask(app,
new BasicNameValuePair("action", App.ACTION_DEVICE_STATUS),
new BasicNameValuePair("status", status)
);
task.setRetryOnConnectivityError(true);
task.execute();
}
}

View File

@ -43,27 +43,40 @@ public class HttpTask extends AsyncTask<String, Void, HttpResponse> {
protected String url;
protected List<BasicNameValuePair> params = new ArrayList<BasicNameValuePair>();
protected BasicNameValuePair[] paramsArr;
private List<FormBodyPart> formParts;
private boolean useMultipartPost = false;
private HttpPost post;
private String logEntries;
private boolean retryOnConnectivityError;
public HttpTask(App app, BasicNameValuePair... paramsArr)
{
super();
this.app = app;
this.url = app.getServerUrl();
params = new ArrayList<BasicNameValuePair>(Arrays.asList(paramsArr));
params.add(new BasicNameValuePair("version", "" + app.getPackageInfo().versionCode));
params.add(new BasicNameValuePair("phone_number", app.getPhoneNumber()));
this.app = app;
this.paramsArr = paramsArr;
params = new ArrayList<BasicNameValuePair>(Arrays.asList(paramsArr));
}
public void setRetryOnConnectivityError(boolean retry)
{
this.retryOnConnectivityError = retry;
}
protected HttpTask getCopy()
{
return new HttpTask(app, paramsArr);
}
public void setFormParts(List<FormBodyPart> formParts)
{
useMultipartPost = true;
this.formParts = formParts;
}
}
private String getSignature()
throws NoSuchAlgorithmException, UnsupportedEncodingException
@ -97,12 +110,20 @@ public class HttpTask extends AsyncTask<String, Void, HttpResponse> {
return new String(Base64Coder.encode(digest));
}
protected HttpResponse doInBackground(String... ignored) {
protected HttpResponse doInBackground(String... ignored) {
url = app.getServerUrl();
if (url.length() == 0) {
app.log("Can't contact server; Server URL not set");
return null;
}
logEntries = app.getNewLogEntries();
params.add(new BasicNameValuePair("version", "" + app.getPackageInfo().versionCode));
params.add(new BasicNameValuePair("phone_number", app.getPhoneNumber()));
params.add(new BasicNameValuePair("log", logEntries));
post = new HttpPost(url);
try
@ -145,6 +166,7 @@ public class HttpTask extends AsyncTask<String, Void, HttpResponse> {
else if (statusCode == 403)
{
response.getEntity().consumeContent();
app.ungetNewLogEntries(logEntries);
app.log("Failed to authenticate to server");
app.log("(Phone number or password may be incorrect)");
return null;
@ -152,17 +174,24 @@ public class HttpTask extends AsyncTask<String, Void, HttpResponse> {
else
{
response.getEntity().consumeContent();
app.ungetNewLogEntries(logEntries);
app.log("Received HTTP " + statusCode + " from server");
return null;
}
}
}
catch (IOException ex)
{
post.abort();
app.ungetNewLogEntries(logEntries);
app.logError("Error while contacting server", ex);
if (ex instanceof UnknownHostException || ex instanceof SocketTimeoutException)
{
{
if (retryOnConnectivityError)
{
app.addQueuedTask(getCopy());
}
app.asyncCheckConnectivity();
}
return null;
@ -170,6 +199,7 @@ public class HttpTask extends AsyncTask<String, Void, HttpResponse> {
catch (Throwable ex)
{
post.abort();
app.ungetNewLogEntries(logEntries);
app.logError("Unexpected error while contacting server", ex, true);
return null;
}

View File

@ -100,6 +100,13 @@ public class Main extends Activity {
registerReceiver(logReceiver, logReceiverFilter);
}
@Override
public void onDestroy()
{
this.unregisterReceiver(logReceiver);
super.onDestroy();
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle item selection
@ -140,9 +147,9 @@ public class Main extends Activity {
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
MenuItem retryItem = menu.findItem(R.id.retry_now);
int pendingMessages = app.getPendingMessageCount();
retryItem.setEnabled(pendingMessages > 0);
retryItem.setTitle("Retry All (" + pendingMessages + ")");
int pendingTasks = app.getPendingTaskCount();
retryItem.setEnabled(pendingTasks > 0);
retryItem.setTitle("Retry All (" + pendingTasks + ")");
return true;
}

View File

@ -93,6 +93,13 @@ public class PendingMessages extends ListActivity {
refreshMessages();
}
@Override
public void onDestroy()
{
this.unregisterReceiver(refreshReceiver);
super.onDestroy();
}
public void refreshMessages()
{