Android Open Source - sana Procedure Runner






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.activity;
//w  ww .java2s. c om
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.xml.parsers.ParserConfigurationException;

import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONTokener;
import org.moca.R;
import org.moca.db.EncounterDAO;
import org.moca.db.EventDAO;
import org.moca.db.PatientInfo;
import org.moca.db.ProcedureDAO;
import org.moca.db.MocaDB.ProcedureSQLFormat;
import org.moca.db.MocaDB.SavedProcedureSQLFormat;
import org.moca.db.MocaDB.EventSQLFormat.EventType;
import org.moca.net.MDSInterface;
import org.moca.procedure.PatientIdElement;
import org.moca.procedure.PictureElement;
import org.moca.procedure.Procedure;
import org.moca.procedure.ProcedureElement;
import org.moca.procedure.ProcedurePage;
import org.moca.procedure.ProcedureParseException;
import org.moca.procedure.ValidationError;
import org.moca.service.BackgroundUploader;
import org.moca.service.ServiceConnector;
import org.moca.service.ServiceListener;
import org.moca.task.ImageProcessingTask;
import org.moca.task.ImageProcessingTaskRequest;
import org.moca.task.PatientLookupListener;
import org.moca.task.PatientLookupTask;
import org.moca.util.MocaUtil;
import org.xml.sax.SAXException;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Typeface;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.Window;
import android.view.animation.AnimationUtils;
import android.view.inputmethod.InputMethodManager;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.ViewAnimator;
import android.graphics.Typeface;
import android.inputmethodservice.KeyboardView;
public class ProcedureRunner extends Activity implements View.OnClickListener, ServiceListener<BackgroundUploader>, PatientLookupListener {
  public static final String TAG = ProcedureRunner.class.toString();
  public static final String INTENT_KEY_STRING = "intentKey";
  
  // Intent
  private static final int CAMERA_INTENT_REQUEST_CODE = 1;
  private static final int BARCODE_INTENT_REQUEST_CODE = 2;

  // Dialog
  private static final int DIALOG_ALREADY_UPLOADED = 7;
  private static final int DIALOG_LOOKUP_PROGRESS = 1;
  private static final int DIALOG_LOAD_PROGRESS = 2;
  private ProgressDialog lookupProgress = null;
  private ProgressDialog loadProgressDialog = null;

  // State
  private Procedure p = null;
  private Uri thisSavedProcedure;
  private boolean wasOnDonePage = false;
  private int startPage = 0;
  private boolean onDonePage = false;
  private static String[] params;

  // Views
  private Button next, prev;
  private ViewAnimator baseViews;
  
  // Service
  private ServiceConnector mConnector = new ServiceConnector();
    private BackgroundUploader mUploadService = null;
    
    private void logException(Throwable t) {
      String stackTrace = EventDAO.getStackTrace(t);
      EventType et = EventType.EXCEPTION;
      if (t instanceof OutOfMemoryError) {
        et = EventType.OUT_OF_MEMORY;
      }
      logEvent(et, stackTrace);
    }
    
    private void logEvent(EventType type, String value) {
      String savedProcedureGuid = "";
      String patientId = "";
      String userId = "";
      
      if (thisSavedProcedure != null) {
        savedProcedureGuid = EncounterDAO.getEncounterGuid(this, thisSavedProcedure);
      }
      
      if (p != null) {
        PatientInfo pi = p.getPatientInfo();
        if (pi != null) {
          patientId = pi.getPatientIdentifier();
        } else {
          // TODO find the patient ID in the form and look at its answer
        }
      }
      
      // TODO lookup current user
      
      EventDAO.registerEvent(this, type, value, savedProcedureGuid, patientId, userId);
    }

  
  
  public void onConnect(BackgroundUploader uploadService) {
    Log.i(TAG, "onServiceConnected");
    mUploadService = uploadService;
  }

  public void onDisconnect(BackgroundUploader uploadService) {
    Log.i(TAG, "onServiceDisconnected");
    mUploadService = null;
  }
  
  public void onPatientLookupFailure(final String patientIdentifier) {
    logEvent(EventType.ENCOUNTER_LOOKUP_PATIENT_FAILED, patientIdentifier);
    
    Log.e(TAG, "Couldn't lookup patient. They might exist, but we don't have their details.");
    if (lookupProgress != null) {
      lookupProgress.dismiss();
      lookupProgress = null;
    }
    
    StringBuilder message = new StringBuilder();
    message.append("Could not find patient record for ");
    message.append(patientIdentifier);
    message.append(". Entering a new patient. Continue?");
    
    AlertDialog.Builder builder = new AlertDialog.Builder(this);
    builder.setMessage(message).setCancelable(false).setPositiveButton(
        getResources().getString(R.string.general_yes),
        new DialogInterface.OnClickListener() {
          @Override
          public void onClick(DialogInterface dialog, int id) {
            dialog.cancel();
            PatientInfo pi = new PatientInfo();
            pi.setPatientIdentifier(patientIdentifier);
            p.setPatientInfo(pi);
            nextPage();
          }
        }).setNegativeButton(
        getResources().getString(R.string.general_no),
        new DialogInterface.OnClickListener() {
          @Override
          public void onClick(DialogInterface dialog, int which) {
            dialog.cancel();
          }
        });
    AlertDialog alert = builder.create();
    alert.show();
  }
  
  public void onPatientLookupSuccess(final PatientInfo patientInfo) {
    logEvent(EventType.ENCOUNTER_LOOKUP_PATIENT_SUCCESS, patientInfo.getPatientIdentifier());

    if (lookupProgress != null) {
      lookupProgress.dismiss();
      lookupProgress = null;
    }
    
    StringBuilder message = new StringBuilder();
    message.append("Found patient record for ID ");
    message.append(patientInfo.getPatientIdentifier());
    message.append("\n");
    
    message.append("First Name: ");
    message.append(patientInfo.getPatientFirstName());
    message.append("\n");
    
    message.append("Last Name: ");
    message.append(patientInfo.getPatientLastName());
    message.append("\n");
    
    message.append("Gender: ");
    message.append(patientInfo.getPatientGender());
    message.append("\n");
    
    message.append("Is this the correct patient?");
    
    AlertDialog.Builder builder = new AlertDialog.Builder(this);
    builder.setMessage(message).setCancelable(false).setPositiveButton(
        getResources().getString(R.string.general_yes),
        new DialogInterface.OnClickListener() {
          @Override
          public void onClick(DialogInterface dialog, int id) {
            dialog.cancel();
            p.setPatientInfo(patientInfo);
            nextPage();
          }
        }).setNegativeButton(
        getResources().getString(R.string.general_no),
        new DialogInterface.OnClickListener() {
          @Override
          public void onClick(DialogInterface dialog, int which) {
            dialog.cancel();
            p.current().getPatientIdElement().setAndRefreshAnswer("");
          }
        });
    AlertDialog alert = builder.create();
    alert.show();
  }
  
  
  private void lookupPatient(String patientId) {
    logEvent(EventType.ENCOUNTER_LOOKUP_PATIENT_START, patientId);
    if (lookupProgress == null) {
      lookupProgress = new ProgressDialog(this);
      lookupProgress.setMessage("Looking up patient \"" + patientId + "\""); // TODO i18n
        lookupProgress.setProgressStyle(ProgressDialog.STYLE_SPINNER);
        lookupProgress.show();
          
      PatientLookupTask task = new PatientLookupTask(this);
      task.setPatientLookupListener(this);
      task.execute(patientId);
    }
  }

  private boolean nextPage() {
    boolean succeed = true;

    try {
      p.current().validate();
    } catch (ValidationError e) {
      String message = e.getMessage();
      logEvent(EventType.ENCOUNTER_PAGE_VALIDATION_FAILED, message);
      MocaUtil.createAlertMessage(this, message);
      return false;
    }
    
    ProcedureElement patientId = p.current().getElementByType("patientId");
    if (patientId != null && p.getPatientInfo() == null) {
      // The patient ID question is on this page. Look up the ID in an AsyncTask
      lookupPatient(patientId.getAnswer());
      return false;
    }

    // Save answers 
    storeCurrentProcedure(false);
    
    if(!p.hasNextShowable()) {
      if(!onDonePage) {
        baseViews.setInAnimation(this,R.anim.slide_from_right);
        baseViews.setOutAnimation(this,R.anim.slide_to_left);
        baseViews.showNext();
        onDonePage = true;
        setProgress(10000);
      } else {
        succeed = false;
      }
    } else {     
      p.advance();
      
      logEvent(EventType.ENCOUNTER_NEXT_PAGE, Integer.toString(p.getCurrentIndex()));

      // Hide the keyboard
      InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
      if (imm != null && p != null && p.getCachedView() != null)
        imm.hideSoftInputFromWindow(p.getCachedView().getWindowToken(), 0);
      
      Log.v(TAG, "In nextPage(), current page index is: " + Integer.toString(p.getCurrentIndex()));
      setProgress(currentProg());
      
      // Tell the current page to play its first audio prompt
      p.current().playFirstPrompt();
    }

    updateNextPrev();
    return succeed;
  }
  
  private boolean prevPage() {
    boolean succeed = true;
    
    if(onDonePage) {
      baseViews.setInAnimation(this,R.anim.slide_from_left);
      baseViews.setOutAnimation(this,R.anim.slide_to_right);
      baseViews.showPrevious();
      onDonePage = false;
      setProgress(currentProg());
      
      // Tell the current page to play its first audio prompt
      p.current().playFirstPrompt();
    }         
    //If was on start of procedures page
    //Back button will go back to procedures list page 
    else if(!p.hasPrevShowable()){   
      // This quits when you hit back and have nowhere else to go back to.
      setResult(RESULT_CANCELED, null);
      logEvent(EventType.ENCOUNTER_EXIT_NO_SAVE, "");
      finish();
      return succeed;
    }
    else if(p.hasPrevShowable()){
      p.back();
      Log.v("prev", Integer.toString(p.getCurrentIndex()));
      setProgress(currentProg());
      
      logEvent(EventType.ENCOUNTER_PREVIOUS_PAGE, Integer.toString(p.getCurrentIndex()));
      
      // Save answers 
      storeCurrentProcedure(false);
      
      // Hide the keyboard
      InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
      if (imm != null && p != null && p.getCachedView() != null)
        imm.hideSoftInputFromWindow(p.getCachedView().getWindowToken(), 0);
      
      // Tell the current page to play its first audio prompt
      p.current().playFirstPrompt();
    }

    updateNextPrev();
    return succeed;
  }

  private int currentProg() {
    int pageCount = p.getVisiblePageCount();
    if (pageCount == 0)
      return 10000;
    return (int) (10000 * (double)(p.getCurrentVisibleIndex())/pageCount);
  }

  @Override
  public boolean onKeyDown(int keycode, KeyEvent e) {
    switch(keycode) {
    case KeyEvent.KEYCODE_BACK:
      if (!this.wasOnDonePage)
        prevPage();
      setContentView(baseViews);
      wasOnDonePage = false;
      return true;
    default:
      return false;
    }   
  }

  public static final int OPTION_SAVE_EXIT = 0;
  public static final int OPTION_DISCARD_EXIT = 1;
  public static final int OPTION_VIEW_PAGES = 2;

  @Override
  public boolean onCreateOptionsMenu(Menu menu) {
    super.onCreateOptionsMenu(menu);
    menu.add(0, OPTION_SAVE_EXIT, 0, "Save & Exit");
    menu.add(0, OPTION_DISCARD_EXIT, 1, "Discard & Exit");
    menu.add(0, OPTION_VIEW_PAGES, 2, "View Pages");
    return true;
  }

  public boolean onOptionsItemSelected(MenuItem item){
    switch (item.getItemId()) {
    case OPTION_SAVE_EXIT:
      storeCurrentProcedure(false);
      setResult(RESULT_OK, null);
      logEvent(EventType.ENCOUNTER_SAVE_QUIT, "");
      finish();
      return true;
    case OPTION_DISCARD_EXIT:
      deleteCurrentProcedure();
      logEvent(EventType.ENCOUNTER_DISCARD, "");
      setResult(RESULT_CANCELED, null);
      finish();
      return true;
    case OPTION_VIEW_PAGES:
      this.wasOnDonePage = true;
      pageList();
      return true;
    } 
    return false;
  }

  @Override
  protected Dialog onCreateDialog(int id) {
    switch (id) {
    case DIALOG_ALREADY_UPLOADED:
      return new AlertDialog.Builder(this)
      .setTitle(getResources().getString(R.string.general_alert))
      .setMessage(getResources().getString(R.string.dialog_already_uploaded))
      .setNeutralButton(getResources().getString(R.string.general_ok), new DialogInterface.OnClickListener() {
        public void onClick(DialogInterface dialog, int whichButton) {
          // close without saving
          setResult(RESULT_OK, null);
        }
      })
      .setCancelable(false)
      .create();    
    default:
      break;
    }
    
    return null;
  }

  private void pageList() {
    ListView mList = new ListView(this);
    List<String> pList = p.toStringArray();

    //int currentPage = p.getCurrentIndex(); 

    mList.setAdapter(new ArrayAdapter<String>(this,
        R.layout.pageslist_item, pList));

    mList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
      public void onItemClick(AdapterView<?> parentView, View childView, int position, long id) {
        onDonePage = false;
        wasOnDonePage = false;

        logEvent(EventType.ENCOUNTER_JUMP_TO_QUESTION, Integer.toString(position));
        p.jumpToVisiblePage(position);
        baseViews.setDisplayedChild(0);
        setProgress(currentProg());
        updateNextPrev();
        setContentView(baseViews);
      }
    });

    setContentView(mList);

  }

  @Override
  public void onClick(View v) {
    if(v == next) {
      nextPage();
    } else if(v == prev) {
      prevPage();
    } else {
      switch(v.getId()) {
      case R.id.procedure_done_back:
        prevPage();
        break;
      case R.id.procedure_done_upload:
        uploadProcedureInBackground();
        break;
      default:
        Log.e(TAG, "Got onClick from unexpected id " + v.getId());
      }
    }

  }
  
  private static File getTemporaryImageFile() {
    return new File(Environment.getExternalStorageDirectory(), "sana.jpg");
  }

  // This gets an intent from PictureElement with info about the picture.
  // It then launches the native camera app, which stores an image at
  // the Uri specified in the intent.
  @Override
  protected void onNewIntent(Intent intent) {
    int description = intent.getExtras().getInt(INTENT_KEY_STRING);
    Log.i(TAG, "description = " + description);
    switch (description) {
    case 0: // intent comes from PictureElement to launch camera app
      try {
        params = intent.getStringArrayExtra(PictureElement.PARAMS_NAME);

        // For Android 1.1: 
        //Intent cameraIntent = new Intent("android.media.action.IMAGE_CAPTURE"); 
        
        // For Android >=1.5:
        Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);


        // EXTRA_OUTPUT is broken on a lot of phones. The HTC G1, Tattoo,
        // and Wildfire return a majorly downsampled version of the
        // image. In the HTC Sense UI, this is a bug with their camera.
        // With vanilla Android, it's a bug in 1.6. 

        Uri tempImageUri = Uri.fromFile(getTemporaryImageFile());
        // This extra tells the camera to return a larger image - only works in >=1.5
        cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, tempImageUri);
        
        startActivityForResult(cameraIntent, CAMERA_INTENT_REQUEST_CODE);
      }
      catch (Exception e) {
        Log.i("TAG", "Got an exception: " + e.toString());
        logException(e);
      }
    break;
    }
  }

  // Called when result returned from camera app.
  // Decodes image from the temp file where it was stored
  // by the camera. It then writes the bitmap to the database.
  @Override
  protected void onActivityResult(int requestCode, int resultCode,
      final Intent data) {
    switch (requestCode) {
    case (BARCODE_INTENT_REQUEST_CODE):
      if (resultCode==RESULT_OK) {
        String contents = data.getStringExtra("SCAN_RESULT");
        String format = data.getStringExtra("SCAN_RESULT_FORMAT");
        Log.i(TAG, "Got result from barcode intent: " + contents);
        
        try {
          ProcedurePage pp = p.current();
          PatientIdElement patientId = pp.getPatientIdElement();
          patientId.setAndRefreshAnswer(contents);
        } catch (Exception e) {
          Log.e(TAG, "Got exception while setting barcode answer: " + e.toString());
          e.printStackTrace();
          logException(e);
        }
      } else {
        Log.i(TAG, "problem getting barcode id");
      }
    break;
    case (CAMERA_INTENT_REQUEST_CODE):
      if (resultCode == RESULT_OK) {
        if (params == null) {
          Log.e(TAG, "params is null, cannot continue receiving picture.");
          return;
        }

        ImageProcessingTaskRequest request = new ImageProcessingTaskRequest();
        request.savedProcedureId = params[0];
        request.elementId = params[1];
        request.tempImageFile = getTemporaryImageFile();
        request.c = this;
        request.intent = data;
        
        Log.i(TAG, "savedProcedureId " + request.savedProcedureId + " and elementId " + request.elementId);

        // Handles making a thumbnail of the image and moving it from the temporary location.
        ImageProcessingTask imageTask = new ImageProcessingTask();
        imageTask.execute(request);
      }
      else {
        Log.i(TAG, "Problem returning image from native camera app.");
      }
    }  
  }
  
  public void uploadProcedureInBackground() {
    storeCurrentProcedure(true);
    //First check to make sure procedure has not already been uploaded
    if (MDSInterface.isProcedureAlreadyUploaded(thisSavedProcedure, getBaseContext())) {
      showDialog(DIALOG_ALREADY_UPLOADED);
    }
    else {
      Log.i(TAG, "Adding current procedure to background upload queue");
      if (mUploadService != null) {
        mUploadService.addProcedureToQueue(thisSavedProcedure);
      }
      logEvent(EventType.ENCOUNTER_SAVE_UPLOAD, "");
      finish();
    }
  }

  public void updateNextPrev() {
    prev.setEnabled(p.hasPrev());
    prev.setText(getResources().getString(R.string.procedurerunner_previous));

    if(p.hasNext()) {
      next.setText(getResources().getString(R.string.procedurerunner_next));
    } else {
      next.setText(getResources().getString(R.string.procedurerunner_done));
    }
  }

  class ProcedureLoadRequest {
    Bundle instance;
    Intent intent;
  }
  
  class ProcedureLoadResult {
    Uri procedureUri;
    Uri savedProcedureUri;
    Procedure p = null;;
    boolean success = false;
    String errorMessage = "";
  }
  
  class ProcedureLoaderTask extends AsyncTask<ProcedureLoadRequest, Void, ProcedureLoadResult> {

    @Override
    protected ProcedureLoadResult doInBackground(ProcedureLoadRequest... params) {
      ProcedureLoadRequest load = params[0];
      Bundle instance = load.instance;
      Intent intent = load.intent;

      ProcedureLoadResult result = new ProcedureLoadResult();
      if (instance == null && !intent.hasExtra("savedProcedureUri")) {
        Uri procedure = intent.getData();
        int procedureId = Integer.parseInt(procedure.getPathSegments().get(1));
        String procedureXml = ProcedureDAO.getXMLForProcedure(ProcedureRunner.this, procedure);

        // Record that we are starting a new encounter
        logEvent(EventType.ENCOUNTER_LOAD_NEW_ENCOUNTER, procedure.toString());
        
        ContentValues cv = new ContentValues();
        cv.put(SavedProcedureSQLFormat.PROCEDURE_ID, procedureId);
        cv.put(SavedProcedureSQLFormat.PROCEDURE_STATE, "");
        cv.put(SavedProcedureSQLFormat.FINISHED, true);
        cv.put(SavedProcedureSQLFormat.UPLOADED, false);     
        cv.put(SavedProcedureSQLFormat.UPLOAD_STATUS, 0);
        
        thisSavedProcedure = getContentResolver().insert(SavedProcedureSQLFormat.CONTENT_URI, cv);

        Log.i(TAG, "onCreate() : uri = " + procedure.toString() + " savedUri=" + thisSavedProcedure);

        Procedure p = null;
        try {
          p = Procedure.fromXMLString(procedureXml);
        } catch (IOException e) {
          Log.e(TAG, "Error loading procedure from XML: " + e.toString());
          e.printStackTrace();
          logException(e);
        } catch (ParserConfigurationException e) {
          Log.e(TAG, "Error loading procedure from XML: " + e.toString());
          e.printStackTrace();
          logException(e);
        } catch (SAXException e) {
          Log.e(TAG, "Error loading procedure from XML: " + e.toString());
          e.printStackTrace();
          logException(e);
        } catch (ProcedureParseException e) {
          Log.e(TAG, "Error loading procedure from XML: " + e.toString());
          e.printStackTrace();
          logException(e);
        } catch (OutOfMemoryError e) {
          Log.e(TAG, "Can't load procedure, out of memory.");
          result.errorMessage = "Out of Memory."; 
          e.printStackTrace();
          logException(e);
        }
        if (p != null) {
          p.setInstanceUri(thisSavedProcedure);
        }
        
        result.p = p;
        result.success = p != null;
        result.procedureUri = procedure;
        result.savedProcedureUri = thisSavedProcedure;
        
      } else {
        startPage = 0;
        PatientInfo pi = null;
        // This is a warm-boot. Restore the state from the saved state.
        if(instance == null) { 
          Log.v(TAG, "No instance on warm boot.");
          startPage = 0;
          onDonePage = false;
          String savedProcedureUri = intent.getStringExtra("savedProcedureUri");
          if (savedProcedureUri != null)
            thisSavedProcedure = Uri.parse(savedProcedureUri);
          
          // Record that we are restoring a saved encounter
          logEvent(EventType.ENCOUNTER_LOAD_SAVED, "");
          
          pi = new PatientInfo();
        } else {
          Log.v(TAG, "Instance present on warm boot.");
          
          startPage = instance.getInt("currentPage");
          onDonePage = instance.getBoolean("onDonePage");
          String savedProcedureUri = instance.getString("savedProcedureUri");

          pi = instance.getParcelable("patientInfo");
          if (pi == null) {
            Log.e(TAG, "Could not get the patient info from parcel.");
          } else {
            Log.v(TAG, "Restored patient info from parcel.");
          }
          
          if (savedProcedureUri != null)
            thisSavedProcedure = Uri.parse(savedProcedureUri);
          
          // Record that we are doing a hot-load
          logEvent(EventType.ENCOUNTER_LOAD_HOTLOAD, "");

        }

        if (thisSavedProcedure == null) {
          Log.e(TAG, "Couldn't determine the URI to warm boot with, bailing.");
          return result;
        }
        Log.i(TAG, "Warm boot occured for " + thisSavedProcedure + ", startPage:" + startPage + " onDonePage: " + onDonePage);

        Cursor c = null;
        int procedureId = -1;
        String answersJson = "";
        try {
          c = getContentResolver().query(thisSavedProcedure, new String [] { SavedProcedureSQLFormat.PROCEDURE_ID, SavedProcedureSQLFormat.PROCEDURE_STATE }, null, null, null);        
          c.moveToFirst();
          procedureId = c.getInt(0);
          answersJson = c.getString(1);
        } catch (Exception e) {
          Log.e(TAG, e.toString());
          e.printStackTrace();
        } finally {
          if (c != null) {
            c.deactivate();
          }
        }

        Map<String,String> answersMap = new HashMap<String,String>();
        try {
          JSONTokener tokener = new JSONTokener(answersJson);
          JSONObject answersDict = new JSONObject(tokener);
          Iterator it = answersDict.keys();
          while(it.hasNext()) {
            String key = (String)it.next();
            answersMap.put(key, answersDict.getString(key));
            Log.i(TAG, "ProcedureLoaderTask loaded answer '" + key + "' : '" + answersDict.getString(key) +"'");
          }
        } catch(JSONException e) {
          Log.e(TAG, "onCreate() -- JSONException " + e.toString());  
          e.printStackTrace();
        }
        
        Uri procedureUri = ContentUris.withAppendedId(ProcedureSQLFormat.CONTENT_URI, procedureId);
        String procedureXml = ProcedureDAO.getXMLForProcedure(ProcedureRunner.this, procedureUri);
        Procedure procedure = null;
        try {
          procedure = Procedure.fromXMLString(procedureXml);
          procedure.setInstanceUri(thisSavedProcedure);
          procedure.restoreAnswers(answersMap);
        } catch (IOException e) {
          Log.e(TAG, "onCreate() -- IOException " + e.toString());
          e.printStackTrace();
        } catch (ParserConfigurationException e) {
          Log.e(TAG, "onCreate() -- couldn't create parser");
          e.printStackTrace();
        } catch (SAXException e) {
          Log.e(TAG, "onCreate() -- Couldn't parse XML");
          e.printStackTrace();
        } catch (ProcedureParseException e) {
          Log.e(TAG, "Error in Procedure.fromXML() : " + e.toString());
          e.printStackTrace();
        } catch (OutOfMemoryError e) {
          Log.e(TAG, "Can't load procedure, out of memory.");
          result.errorMessage = "Out of Memory."; 
          e.printStackTrace();
          
        }
        Log.i(TAG, "onCreate() : warm-booted from uri =" + thisSavedProcedure);
        
        if (procedure != null && pi != null) {
          procedure.setPatientInfo(pi);
        }
        
        result.p = procedure;
        result.success = procedure != null;
        result.savedProcedureUri = thisSavedProcedure;
        result.procedureUri = procedureUri;
      }

      return result;
    }
    
    @Override
    protected void onPostExecute(ProcedureLoadResult result) {
      super.onPostExecute(result);
      if (loadProgressDialog != null) {
        loadProgressDialog.dismiss();
        loadProgressDialog = null;
      }
      if (result.success) {
        p = result.p;
        thisSavedProcedure = result.savedProcedureUri;
        logEvent(EventType.ENCOUNTER_LOAD_FINISHED, "");
        createView();
      } else {
        // Show error
        logEvent(EventType.ENCOUNTER_LOAD_FAILED, "");
        ProcedureRunner.this.finish();
      }
    }
    
  }
  
  public void createView() {
    if (p == null)
      return;
    
    setTitle(p.getTitle());
    TextView mytv;
    View procedureView = wrapViewWithInterface(p.toView(this));

    // Now that the view is active, go to the correct page.
    if(p.getCurrentIndex() != startPage) {
      p.jumpToPage(startPage);
      updateNextPrev();            
    }

    baseViews = new ViewAnimator(this);
    baseViews.setBackgroundResource(android.R.drawable.alert_dark_frame);
    baseViews.setInAnimation(AnimationUtils.loadAnimation(this,R.anim.slide_from_right));
    baseViews.setOutAnimation(AnimationUtils.loadAnimation(this,R.anim.slide_to_left));
    baseViews.addView(procedureView);

    // This should add it to baseViews, so don't add it manually.
    View procedureDonePage = getLayoutInflater().inflate(R.layout.procedure_runner_done, baseViews);
    ((TextView)procedureDonePage.findViewById(R.id.procedure_done_text)).setTextAppearance(this, android.R.style.TextAppearance_Large);
    procedureDonePage.findViewById(R.id.procedure_done_back).setOnClickListener(this);
    procedureDonePage.findViewById(R.id.procedure_done_upload).setOnClickListener(this);

    if(onDonePage) {
      baseViews.setInAnimation(null);
      baseViews.setOutAnimation(null);
      baseViews.showNext();
      //mytv = (TextView) baseViews.getCurrentView(); 
      //mytv.setTypeface(Typeface.createFromAsset(getAssets(), "fonts/mangal.ttf"));
      //baseViews.requestLayout();
    
      baseViews.setInAnimation(AnimationUtils.loadAnimation(this,R.anim.slide_from_right));
      baseViews.setOutAnimation(AnimationUtils.loadAnimation(this,R.anim.slide_to_left));
    }

    setContentView(baseViews);
    setProgressBarVisibility(true);
    setProgress(0);
  }
  
  public void onCreate(Bundle instance) {
    super.onCreate(instance);
    Log.v(TAG, "onCreate");

    try {
          mConnector.setServiceListener(this);
          mConnector.connect(this);
        }
        catch (Exception e) {
          Log.e(TAG, "Exception starting background upload service: " + e.toString());
          e.printStackTrace();
        }

    logEvent(EventType.ENCOUNTER_ACTIVITY_START_OR_RESUME, "");

    requestWindowFeature(Window.FEATURE_PROGRESS);
    
    if (p == null) {
      ProcedureLoadRequest request = new ProcedureLoadRequest();
      request.instance = instance;
      request.intent = getIntent();

      logEvent(EventType.ENCOUNTER_LOAD_STARTED, "");
      new ProcedureLoaderTask().execute(request);
      loadProgressDialog = new ProgressDialog(this);
        loadProgressDialog.setMessage("Loading procedure."); // TODO i18n
        loadProgressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
        loadProgressDialog.show();
    }
  }

  /**
   * Takes a view and wraps it with next/previous buttons for navigating.
   * 
   * @param sub - the view which is to be wrapped
   * @return - a new view which is <param>sub</param> wrapped with next/prev buttons.
   */
  public View wrapViewWithInterface(View sub) {
    //View sub = state.current().toView(this);
    //RelativeLayout rl = new RelativeLayout(this);
    //rl.setLayoutParams( new ViewGroup.LayoutParams( LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT ) );
    
    LinearLayout base = new LinearLayout(this);
    base.setOrientation(LinearLayout.VERTICAL);

    LinearLayout ll = new LinearLayout(this);
    ll.setOrientation(LinearLayout.HORIZONTAL);
    
              next = new Button(this);
    
    next.setOnClickListener(this);
    prev = new Button(this);
    
    
    prev.setOnClickListener(this);
       
    updateNextPrev();

    ll.addView(prev,new LinearLayout.LayoutParams(-2,-1, 0.5f));
    ll.addView(next,new LinearLayout.LayoutParams(-2,-1, 0.5f));
    ll.setWeightSum(1.0f);
         
      
    //RelativeLayout.LayoutParams ll_lp = new RelativeLayout.LayoutParams(-1,100);
    //ll_lp.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
    //rl.addView(ll, ll_lp);

    //RelativeLayout.LayoutParams sub_lp = new RelativeLayout.LayoutParams(-1,-1);
    //sub_lp.addRule(RelativeLayout.ABOVE, ll.getId());
    //rl.addView(sub, sub_lp);

    //ScrollView sv = new ScrollView(this);
    //sv.addView(sub, new ViewGroup.LayoutParams(-1,-1));
    //base.addView(sv, new LinearLayout.LayoutParams(-1,-2,0.99f));
    base.addView(sub, new LinearLayout.LayoutParams(-1,-2,0.99f));
    base.addView(ll, new LinearLayout.LayoutParams(-1,-2,0.01f));

    base.setWeightSum(1.0f);

    return base;
  }

  public void onResume() {
    super.onResume();
    Log.i(TAG, "onResume()");
  }

  /**
   * Serializes the current procedure to the database. Takes the answers map
   * from the procedure, serializes it to JSON, and stores it. If finished is
   * set, then it will set the procedure's row to finished. This will signal
   * to the upload service that it is ready for upload.
   * 
   * @param finished
   *            -- Whether to set the procedure as ready for upload.
   */
  public void storeCurrentProcedure(boolean finished) {
    if(p != null && thisSavedProcedure != null) {
      JSONObject answersMap = new JSONObject(p.toAnswers());
      String json = answersMap.toString();

      ContentValues cv = new ContentValues();
      cv.put(SavedProcedureSQLFormat.PROCEDURE_STATE, json);

      if(finished) 
        cv.put(SavedProcedureSQLFormat.FINISHED, finished);

      int updatedObjects = getContentResolver().update(thisSavedProcedure, cv, null, null);
      Log.i(TAG, "storeCurrentProcedure updated " + updatedObjects + " objects. (SHOULD ONLY BE 1)");
    }
  }

  public void deleteCurrentProcedure() {
    getContentResolver().delete(thisSavedProcedure, null, null);
  }

  public void onPause() {
    super.onPause();
    Log.i(TAG, "onPause");
    
    // This is the last method in which we are guaranteed not to be killed,
    // so save state here.
    storeCurrentProcedure(false);

    if (lookupProgress != null) {
      lookupProgress.dismiss();
      lookupProgress = null;
    }
    if (loadProgressDialog != null) {
      loadProgressDialog.dismiss();
      loadProgressDialog = null;
    }
  }

  public void onDestroy() {
    super.onDestroy();
    Log.i(TAG, "onDestroy");

    if (p != null) {
      p.clearCachedViews();
    }
  }
  
  @Override
  public void onStop() {
    super.onStop();
    Log.i(TAG,"onStop");
    if (mConnector != null) {
      try {
        mConnector.disconnect(this);
      } catch (IllegalArgumentException e) {
        Log.e(TAG, "While disconnecting service got exception: " + e.toString());
        e.printStackTrace();
      }
    }
  }

  /**
   * If we are warm booted, then we need to know that we saved our procedure
   * state at some URI. We also need to know where the user was in the process
   * of filling out the form, etc. So when the activity is closing, we store
   * the state in a bundle so that we can read it when we are created again.
   */
  @Override
  protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    
    Log.v(TAG, "onSaveInstanceState");
    
    if (thisSavedProcedure != null) 
      outState.putString("savedProcedureUri", thisSavedProcedure.toString());
    
    if (p != null) {
      outState.putInt("currentPage", p.getCurrentIndex());
      
      // In a future, backwards incompatible version, we could do this differently.
      PatientInfo pi = p.getPatientInfo();
      if (pi != null)
        outState.putParcelable("patientInfo", pi);
    }
    
    outState.putBoolean("onDonePage", onDonePage);
  }



}




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