Back to project page sana.
The source code is released under:
Copyright (c) 2010, Moca All rights reserved. The source code for Moca is licensed under the BSD license as follows: Redistribution and use in source and binary forms, with or without modification, ...
If you think the Android project sana listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.
package org.moca.net; // w w w .ja v a 2 s . c o m import java.util.regex.Matcher; import java.util.regex.Pattern; import org.moca.R; import org.moca.db.NotificationMessage; import org.moca.db.MocaDB.NotificationSQLFormat; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.content.BroadcastReceiver; import android.content.ContentUris; import android.content.ContentValues; import android.content.Context; import android.content.Intent; import android.database.Cursor; import android.net.Uri; import android.os.Bundle; import android.telephony.gsm.SmsMessage; import android.util.Log; import android.widget.Toast; import com.google.gson.Gson; import com.google.gson.JsonParseException; /** * SMSReceive handles the doctor->healthworker diagnosis exchange. * * The diagnosis from the physician comes to the phone via SMS. The body of the * SMS has a Moca header that tells Moca, which listens for SMS messages, that * the SMS is destined for it. Moca grabs the SMS and creates a custom Android * notification from it. In addition, the diagnosis is filed in the phone's * database of received notifications. */ public class SMSReceive extends BroadcastReceiver { private static final String TAG = SMSReceive.class.toString(); private static final String ACTION = "android.provider.Telephony.SMS_RECEIVED"; /** * Automatically called when an SMS message is received. This method does * four things: 1) It reads the incoming SMS to make sure it is well formed * (it came from the dispatch server) 2) It stores the diagnosis * notification in the notification database 3) It pops up a temporary * message saying a diagnosis has been received 4) It inserts an alert into * the status bar, clearing all previous alerts in the status bar * * A well-formed SMS message looks like this: <patient=422>Prescribe him * antibiotics. */ public void onReceive(Context context, Intent intent) { if (!intent.getAction().equals(ACTION)) return; Bundle bundle = intent.getExtras(); if (bundle == null) return; Object[] pdus = (Object[]) bundle.get("pdus"); if (pdus == null) return; for (int i = 0; i < pdus.length; ++i) { SmsMessage m = SmsMessage.createFromPdu((byte[]) pdus[i]); Log.i(TAG, "Got message from" + m.getOriginatingAddress()); Log.i(TAG, m.toString()); processMessage(context, m); } } private void processNotificationMessage(Context context, MDSNotification notificationHeader, String message) { Gson g = new Gson(); if (notificationHeader.n == null) { Log.e(TAG, "Received mal-formed notification GUID -- none provided."); } Cursor c = context.getContentResolver().query(NotificationSQLFormat.CONTENT_URI, new String[] { NotificationSQLFormat._ID, NotificationSQLFormat.PATIENT_ID, NotificationSQLFormat.PROCEDURE_ID, NotificationSQLFormat.MESSAGE }, NotificationSQLFormat.NOTIFICATION_GUID+"=?", new String[] { notificationHeader.n }, null); ContentValues cv = new ContentValues(); String patientId = null; if (notificationHeader.p != null) { patientId = notificationHeader.p; cv.put(NotificationSQLFormat.PATIENT_ID, notificationHeader.p); } if (notificationHeader.c != null) { cv.put(NotificationSQLFormat.PROCEDURE_ID, notificationHeader.c); } Uri notificationUri; boolean complete = false; String fullMessage = ""; Pattern pattern = Pattern.compile("^(\\d+)/(\\d+)$"); if (c.moveToFirst()) { // Notification already exists int notificationId = c.getInt(c.getColumnIndex(NotificationSQLFormat._ID)); String storedMessage = c.getString(c.getColumnIndexOrThrow(NotificationSQLFormat.MESSAGE)); NotificationMessage m = g.fromJson(storedMessage, NotificationMessage.class); if (patientId == null) { patientId = c.getString(c.getColumnIndex(NotificationSQLFormat.PATIENT_ID)); } if (notificationHeader.d != null) { Matcher matcher = pattern.matcher(notificationHeader.d); if (matcher.matches()) { Integer current = Integer.parseInt(matcher.group(1)); Integer total = Integer.parseInt(matcher.group(2)); m.receivedMessages++; assert(m.totalMessages == total); m.messages.put(current, message); if (m.totalMessages == m.receivedMessages) { complete = true; StringBuilder sbFullMessage = new StringBuilder(); for (int i = 1; i <= m.totalMessages; i++) { sbFullMessage.append(m.messages.get(i)); } fullMessage = sbFullMessage.toString(); cv.put(NotificationSQLFormat.FULL_MESSAGE, fullMessage); cv.put(NotificationSQLFormat.DOWNLOADED, 1); } } } else { Log.e(TAG, "Received mal-formed Notification Message length: " + notificationHeader.d); } c.close(); storedMessage = g.toJson(m); cv.put(NotificationSQLFormat.MESSAGE, storedMessage); notificationUri = ContentUris.withAppendedId(NotificationSQLFormat.CONTENT_URI, notificationId); int rowsUpdated = context.getContentResolver().update(notificationUri, cv, null, null); if (rowsUpdated != 1) { Log.e(TAG, "Failed updating notification URI: " + notificationUri); } } else { // Notification is new, create one. NotificationMessage m = new NotificationMessage(); if (notificationHeader.d != null) { // This is a multipart message Log.i(TAG, "Received multi-part SMS"); String parts = notificationHeader.d; Matcher matcher = pattern.matcher(notificationHeader.d); if (matcher.matches()) { Integer current = Integer.parseInt(matcher.group(1)); Integer total = Integer.parseInt(matcher.group(2)); m.totalMessages = total; m.receivedMessages = 1; m.messages.put(current, message); if (m.totalMessages == m.receivedMessages) { complete = true; StringBuilder sbFullMessage = new StringBuilder(); for (int i = 1; i <= m.totalMessages; i++) { sbFullMessage.append(m.messages.get(i)); } fullMessage = sbFullMessage.toString(); cv.put(NotificationSQLFormat.FULL_MESSAGE, fullMessage); cv.put(NotificationSQLFormat.DOWNLOADED, 1); } } else { Log.e(TAG, "Received mal-formed Notification Message length: " + notificationHeader.d); } } else { // This is a single message. Log.i(TAG, "Received single-part SMS"); m.totalMessages = 1; m.receivedMessages = 1; m.messages.put(1, message); cv.put(NotificationSQLFormat.FULL_MESSAGE, message); cv.put(NotificationSQLFormat.DOWNLOADED, 1); complete = true; } String storedMessage = g.toJson(m); cv.put(NotificationSQLFormat.MESSAGE, storedMessage); cv.put(NotificationSQLFormat.NOTIFICATION_GUID, notificationHeader.n); notificationUri = context.getContentResolver().insert(NotificationSQLFormat.CONTENT_URI, cv); } if (complete) { // Show Toast that a notification was received String notifHdr = "DIAGNOSIS RECEIVED\nPatient ID# " + patientId + "\n"; Toast.makeText(context, notifHdr, Toast.LENGTH_LONG).show(); Intent viewIntent = new Intent(Intent.ACTION_VIEW, notificationUri); showNotification(context, "Patient ID# " + patientId, fullMessage, viewIntent); } } private void processMessage(Context context, SmsMessage m) { String msg = m.getDisplayMessageBody(); // check if this is a patient diagnosis SMS Log.i(TAG, "Got SMS message " + msg); String leftCurly = new String(new byte[] { 0x1B, 0x28 }); String rightCurly = new String(new byte[] { 0x1b, 0x29 }); // Decode escapes msg = msg.replace(leftCurly, "{").replace(rightCurly, "}"); Log.i(TAG, "Decode1: " + msg); msg = msg.replace("?(", "{").replace("?)", "}"); Log.i(TAG, "Decode2: " + msg); int lastRightBrace = msg.lastIndexOf('}'); if (lastRightBrace == -1) { Log.i(TAG, "SMS not destined for Moca. Wrong header."); return; } Gson gson = new Gson(); try { String header = msg.substring(0, lastRightBrace+1); String message = msg.substring(lastRightBrace+1); MDSNotification notificationHeader = gson.fromJson(header, MDSNotification.class); processNotificationMessage(context, notificationHeader, message); } catch (JsonParseException e) { Log.i(TAG, "Could not parse Moca header in SMS: " + e.toString()); return; } catch (Exception e) { Log.e(TAG, e.toString()); return; } } /** * Creates a notification used when a patient diagnosis is received. * * @param c * current context * @param title * the patient's ID number should be the title * @param textMessage * the message text sent from the doctor * @param viewIntent */ private void showNotification(Context c, String title, String textMessage, Intent viewIntent) { // Look up the notification manager service NotificationManager nm = (NotificationManager) c .getSystemService(Context.NOTIFICATION_SERVICE); // The PendingIntent launches the Notification Viewer for the particular // alert PendingIntent contentIntent = PendingIntent.getActivity(c, 0, viewIntent, 0); // The ticker text String tickerText = "PATIENT DIAGNOSIS RECEIVED"; // Construct the Notification object. Notification notif = new Notification(R.drawable.icon2, tickerText, System.currentTimeMillis()); // Set the info for the views that show in the notification panel notif.setLatestEventInfo(c, title, textMessage, contentIntent); // After a 100ms delay, vibrate for 200ms, pause for 100 ms and // then vibrate for 300ms. notif.vibrate = new long[] { 100, 200, 100, 300 }; // Use this line if you want a new persistent notification each time: // nm.notify((int)Math.round((Math.random() * 32000)), notif); // Or use this to overwrite the last notification each time: nm.cancelAll(); nm.notify(1, notif); } }