Android Open Source - sana S M S Receive






From Project

Back to project page sana.

License

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.

Java Source Code

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);
  }
}




Java Source Code List

.Moca.java
org.moca.Constants.java
org.moca.ImagePreviewDialog.java
org.moca.ScalingImageAdapter.java
org.moca.SelectableImageView.java
org.moca.activity.NotificationList.java
org.moca.activity.NotificationViewer.java
org.moca.activity.PatientInfoDialog.java
org.moca.activity.ProcedureRunner.java
org.moca.activity.ProceduresList.java
org.moca.activity.SavedProcedureList.java
org.moca.activity.Settings.java
org.moca.db.EncounterDAO.java
org.moca.db.EventDAO.java
org.moca.db.EventProvider.java
org.moca.db.Event.java
org.moca.db.ImageProvider.java
org.moca.db.MocaDB.java
org.moca.db.NotificationMessage.java
org.moca.db.NotificationProvider.java
org.moca.db.PatientInfo.java
org.moca.db.PatientProvider.java
org.moca.db.PatientValidator.java
org.moca.db.ProcedureDAO.java
org.moca.db.ProcedureProvider.java
org.moca.db.SavedProcedureProvider.java
org.moca.db.SoundProvider.java
org.moca.media.AudioPlayer.java
org.moca.net.MDSCode.java
org.moca.net.MDSInterface.java
org.moca.net.MDSNotification.java
org.moca.net.MDSResult.java
org.moca.net.SMSReceive.java
org.moca.procedure.BinaryUploadElement.java
org.moca.procedure.DateElement.java
org.moca.procedure.GpsElement.java
org.moca.procedure.MultiSelectElement.java
org.moca.procedure.PatientIdElement.java
org.moca.procedure.PictureElement.java
org.moca.procedure.ProcedureElement.java
org.moca.procedure.ProcedurePage.java
org.moca.procedure.ProcedureParseException.java
org.moca.procedure.Procedure.java
org.moca.procedure.RadioElement.java
org.moca.procedure.SelectElement.java
org.moca.procedure.SoundElement.java
org.moca.procedure.TextElement.java
org.moca.procedure.TextEntryElement.java
org.moca.procedure.ValidationError.java
org.moca.procedure.branching.Criteria.java
org.moca.procedure.branching.Criterion.java
org.moca.procedure.branching.LogicAnd.java
org.moca.procedure.branching.LogicBase.java
org.moca.procedure.branching.LogicNot.java
org.moca.procedure.branching.LogicOr.java
org.moca.service.BackgroundUploader.java
org.moca.service.QueueManager.java
org.moca.service.ServiceConnector.java
org.moca.service.ServiceListener.java
org.moca.task.CheckCredentialsTask.java
org.moca.task.ImageProcessingTaskRequest.java
org.moca.task.ImageProcessingTask.java
org.moca.task.MDSSyncTask.java
org.moca.task.PatientLookupListener.java
org.moca.task.PatientLookupTask.java
org.moca.task.ResetDatabaseTask.java
org.moca.task.ValidationListener.java
org.moca.util.MocaUtil.java
org.moca.util.UserDatabase.java