package org.sana.android.procedure; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import org.sana.android.db.SanaDB.SoundSQLFormat; import org.w3c.dom.Node; import android.content.ContentValues; import android.content.Context; import android.media.MediaPlayer; import android.media.MediaRecorder; import android.net.Uri; import android.os.Environment; import android.util.Log; import android.view.Gravity; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.Gallery; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; import android.widget.LinearLayout.LayoutParams; /** * SoundElement is a ProcedureElement that asks a question and allows a user to * record a response. This sound is saved to a temp file on the phone's SD card * and then sent to a database on the phone. Once a recording is made, the user * has the option of re-recording. * <p/> * <ul type="none"> * <li><b>Clinical Use</b> This element is useful in several clinical scenarios * such as recording extra notes or recording the patient cough, etc.</li> * <li><b>Collects</b></li>An audio recording to a file represented as a string * file name.</li> * </ul> * * @author Sana Development Team */ public class SoundElement extends ProcedureElement implements OnClickListener { private Button startRecButt; private Button endRecButt; private TextView textViewSound; private ImageView imageViewSound; private MediaRecorder recorder; private String path; private File tempSoundFile; /** {@inheritDoc} */ @Override public ElementType getType() { return ElementType.SOUND; } /** {@inheritDoc} */ @Override protected View createView(Context c) { LinearLayout soundContainer = new LinearLayout(c); soundContainer.setOrientation(LinearLayout.VERTICAL); path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/testRecording.3gp"; if(question == null) { question = "Record audio:"; } //Set display question textViewSound = new TextView(c); textViewSound.setText(question); textViewSound.setGravity(Gravity.CENTER); textViewSound.setTextAppearance(c, android.R.style.TextAppearance_Medium); //Set accompanying figure imageViewSound = new ImageView(c); if(!figure.equals("")){ try{ String imagePath = c.getPackageName() + ":" + figure; int resID = c.getResources().getIdentifier(imagePath, null, null); imageViewSound.setImageResource(resID); imageViewSound.setAdjustViewBounds(true); // set the ImageView bounds to match the Drawable's dimensions imageViewSound.setLayoutParams(new Gallery.LayoutParams( LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); imageViewSound.setPadding(10,10,10,10); } catch(Exception e){ Log.e(TAG, "Couldn't find resource figure " + e.toString()); } } //Add to page soundContainer.addView(textViewSound, new LinearLayout.LayoutParams(-1, -1, 0.1f)); soundContainer.addView(imageViewSound, new LinearLayout.LayoutParams(-1, -1, 0.1f)); //Initialize audio control buttons //Start Record Button startRecButt = new Button(c); startRecButt.setText("Start Recording"); startRecButt.setOnClickListener(this); //End Record Button (disabled initially) endRecButt = new Button(c); endRecButt.setText("Stop Recording"); endRecButt.setEnabled(false); endRecButt.setOnClickListener(this); //Add to page soundContainer.addView(startRecButt, new LinearLayout.LayoutParams(-1, -1, 0.1f)); soundContainer.addView(endRecButt, new LinearLayout.LayoutParams(-1, -1, 0.1f)); return soundContainer; } /** {@inheritDoc} */ @Override public void onClick(View v) { //Start Record button clicked if (v == startRecButt) { textViewSound.setText(question); //toggle record buttons startRecButt.setEnabled(false); endRecButt.setEnabled(true); String state = android.os.Environment.getExternalStorageState(); if(!state.equals(android.os.Environment.MEDIA_MOUNTED)) { Log.e(TAG, "SD Card is not mounted. It is " + state + "build/intermediates/exploded-aar/com.android.support/support-v4/21.0.3/res"); } // make sure the directory we plan to store the recording in exists File directory = new File(path).getParentFile(); if (!directory.exists() && !directory.mkdirs()) { Log.e(TAG, "Path to file could not be created."); } //create new recorder recorder = new MediaRecorder(); recorder.setAudioSource(MediaRecorder.AudioSource.MIC); recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP); recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); recorder.setOutputFile(path); //start recording try { recorder.prepare(); recorder.start(); endRecButt.setText("Stop Recording"); } catch (Exception e) { endRecButt.setText("Recording Error"); Log.e(TAG, "Couldn't setup audio recorder: " + e); } } //End Record button clicked else if (v == endRecButt) { startRecButt.setEnabled(true); // if we are still in the recording state // then allow the user to stop recording if (!(endRecButt.getText().equals("Play Back Recording"))) { // stop recording textViewSound.setText("Recording Complete!"); recorder.stop(); recorder.release(); endRecButt.setText("Play Back Recording"); Thread t = new Thread() { public void run() { // now write the file to the database ContentValues values = new ContentValues(); String procedureId = getProcedure().getInstanceUri() .getPathSegments().get(1); values.put(SoundSQLFormat.ENCOUNTER_ID, procedureId); values.put(SoundSQLFormat.ELEMENT_ID, getId()); Uri recording = getContext().getContentResolver().insert( SoundSQLFormat.CONTENT_URI, values); // Make this the answer we return setAnswer(recording.getPathSegments().get(1)); try { byte[] buffer = new byte[1024]; OutputStream os = getContext().getContentResolver() .openOutputStream(recording); InputStream is = new FileInputStream(path); os = getContext().getContentResolver() .openOutputStream(recording); int bytesRemaining = is.available(); while(bytesRemaining > 0) { int read = is.read(buffer); os.write(buffer, 0, read); bytesRemaining -= read; } is.close(); os.flush(); os.close(); Log.i(TAG, "Successfully saved audio"); } catch (FileNotFoundException e) { Log.e(TAG, "While storing the audio, got an " + "exception: " + e.toString()); } catch (IOException e) { Log.e(TAG, "While storing the audio, got an " +"exception: " + e.toString()); Log.i(TAG, e.getStackTrace().toString()); } } }; t.start(); // // InputStream is = null; // OutputStream os = null; // try { // byte[] buffer = new byte[1024]; // // //new stuff // tempSoundFile = new File(Environment.getExternalStorageDirectory(), "testRecording.3gp"); // Uri tempSoundUri = Uri.fromFile(tempSoundFile); // is = new FileInputStream(path); // os = getContext().getContentResolver().openOutputStream(recording); // // int bytesRemaining = is.available(); // while(bytesRemaining > 0) { // int read = is.read(buffer); // os.write(buffer, 0, read); // bytesRemaining -= read; // } // // is.close(); // os.close(); // } catch (FileNotFoundException e) { // Log.i(TAG, "could not find audio temp file"); // } catch (IOException e) { // Log.i(TAG, "IO exception in writing audio to database " + e.toString()); // Log.i(TAG, e.getStackTrace().toString()); // } finally { // try { // if (os != null) // os.close(); // } catch (IOException e) { // // } // try { // if (is != null) // is.close(); // } catch (IOException e) { // // } // // } // if we are in a completed state // then allow audio playback } else { MediaPlayer mp = new MediaPlayer(); try { mp.setDataSource(path); mp.prepare(); mp.start(); } catch (Exception e) { return; } startRecButt.setText("Rerecord"); } } } /** {@inheritDoc} */ @Override public void setAnswer(String answer) { this.answer = answer; } /** {@inheritDoc} */ @Override public String getAnswer() { return answer; } /** {@inheritDoc} */ @Override public void buildXML(StringBuilder sb) { sb.append("<Element type=\"" + getType().name() + "\" id=\"" + id); sb.append("\" answer=\"" + getAnswer()); sb.append("\" concept=\"" + getConcept()); sb.append("\"/>\n"); } /** Default constructor */ private SoundElement(String id, String question, String answer, String concept, String figure, String audio) { super(id,question,answer, concept, figure, audio); } /** @see ProcedureElement#fromXML(String, String, String, String, String, String, Node) */ public static SoundElement fromXML(String id, String question, String answer, String concept, String figure, String audio, Node node) throws ProcedureParseException { return new SoundElement(id, question, answer, concept, figure, audio); } }