package com.realtrackandroid.backend.activities; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.graphics.Bitmap; import android.os.Environment; import com.realtrackandroid.backend.GlobalDatabaseHelper; import com.realtrackandroid.models.activities.Participant; /* * DAO object to update/delete/add participation */ public class ParticipantDAO { private GlobalDatabaseHelper opener; private SQLiteDatabase readDatabase; private SQLiteDatabase writeDatabase; private Context context; public ParticipantDAO(Context context) { this.opener = GlobalDatabaseHelper.getInstance(context); this.readDatabase = opener.getReadableDatabase(); this.writeDatabase = opener.getWritableDatabase(); this.context = context; closeDB(); } private void openDB() { if (!readDatabase.isOpen()) { readDatabase = opener.getReadableDatabase(); } if (!writeDatabase.isOpen()) { writeDatabase = opener.getWritableDatabase(); } } private void closeDB() { if (readDatabase.isOpen()) { readDatabase.close(); } if (writeDatabase.isOpen()) { writeDatabase.close(); } } /** * Add multiple participants at once. * <p> * <b>WARNING</b>: Before you call this method, you must set the participation id in every * Participant object being written using * {@link com.realtrackandroid.models.activities.Participant#setParticipationId(int)} * * @param participantList */ public void addParticipants(List<Participant> participantList) { openDB(); for (Participant p : participantList) { writeNewParticipantData(p); } closeDB(); } /** * Add a single participant. * <p> * <b>WARNING</b>: Before you call this method, you must set the participation id in every * Participant object being written using * {@link com.realtrackandroid.models.activities.Participant#setParticipationId(int)} * * @param participantList */ public void addParticipant(Participant participant) { openDB(); writeNewParticipantData(participant); closeDB(); } /** * We create a new method since this code is shared between addParticipants and addParticipant. We * could have left this code in addParticipant and simply called that method from addParticipants * for each participant. In that case,the db would be opened and closed for EACH participant. This * can negatively impact performance. On the other hand, removing openDB and closeDB from from * addParticipant is not safe because someone may decide to call it on its own. Hence, we extract * this logic into a new method that can be called from addParticipants (with an openDB and a * closeDB for all the participants at once) as well as addParticipant (with an openDB and a * closeDB for just that participant). * * @param participant * object to write to the database. */ private void writeNewParticipantData(Participant participant) { ContentValues newValue = new ContentValues(7); participant.setSignaturePath(saveSignatureBitmap(participant)); newValue.put(Participant.COLUMN_PARTICIPATIONID, participant.getParticipationId()); newValue.put(Participant.COLUMN_NAME, participant.getName()); newValue.put(Participant.COLUMN_PHONENUMBER, participant.getPhoneNumber()); newValue.put(Participant.COLUMN_VILLAGE, participant.getVillage()); newValue.put(Participant.COLUMN_AGE, participant.getAge()); newValue.put(Participant.COLUMN_GENDER, participant.getGender()); newValue.put(Participant.COLUMN_SIGNATUREPATH, participant.getSignaturePath()); // Insert the item into the database writeDatabase.insert(Participant.PARTICIPANT_TABLE, null, newValue); } /** * Saves the signature image to external storage if available or falls back to internal storage if * not. Returns the URI of the image just saved * * @param signatureBitmap * @return URI of image just saved */ private String saveSignatureBitmap(Participant participant) { Bitmap signatureBitmapToSave = participant.getSignatureBitmap(); String timeStamp = new SimpleDateFormat("MM_dd_yyyy_HH_mm_ss_").format(new Date()); String signatureFileName = timeStamp + participant.getParticipationId() + "_" + participant.getName() + ".png"; File signatureOutputFile = getOutputSignatureFileOnExternalOrInternalStorage(signatureFileName); try { FileOutputStream fos = new FileOutputStream(signatureOutputFile); signatureBitmapToSave.compress(Bitmap.CompressFormat.PNG, 90, fos); fos.close(); } catch (FileNotFoundException e) { } catch (IOException e) { } return signatureOutputFile.getAbsolutePath(); } /** * Returns a file that we can write the signature to. Will either be on external storage if * available or on internal storage, if not. * * @param signatureFileName * file name to create * @return File object that we can write to */ private File getOutputSignatureFileOnExternalOrInternalStorage(String signatureFileName) { File signaturesDir = new File(context.getFilesDir(), "signatures"); // fallback onto internal // storage if (isExternalStorageWritable()) signaturesDir = new File(context.getExternalFilesDir(null), "signatures"); if (!signaturesDir.isDirectory()) signaturesDir.mkdirs(); File signatureFile = new File(signaturesDir.getPath() + File.separator + signatureFileName); return signatureFile; } public boolean isExternalStorageWritable() { String state = Environment.getExternalStorageState(); if (Environment.MEDIA_MOUNTED.equals(state)) { return true; } return false; } /** * @return true if any participants were recorded for any activity */ public boolean areAnyParticipantsPresent() { openDB(); Cursor returnData = readDatabase.query(Participant.PARTICIPANT_TABLE, new String[] {}, null, null, null, null, null); boolean areAnyParticipantsPresent = returnData.getCount() > 0; closeDB(); return areAnyParticipantsPresent; } public ArrayList<Participant> getAllParticipantsForParticipationId(int participationid) { openDB(); ArrayList<Participant> output = null; String[] columnsToRead = new String[8]; columnsToRead[0] = Participant.COLUMN_ID; columnsToRead[1] = Participant.COLUMN_NAME; columnsToRead[2] = Participant.COLUMN_PHONENUMBER; columnsToRead[3] = Participant.COLUMN_VILLAGE; columnsToRead[4] = Participant.COLUMN_AGE; columnsToRead[5] = Participant.COLUMN_GENDER; columnsToRead[6] = Participant.COLUMN_PARTICIPATIONID; columnsToRead[7] = Participant.COLUMN_SIGNATUREPATH; String whereClause = Participant.COLUMN_PARTICIPATIONID + '=' + participationid; Cursor returnData = readDatabase.query(Participant.PARTICIPANT_TABLE, columnsToRead, whereClause, null, null, null, null); output = extractParticipant(returnData); closeDB(); return output; } private ArrayList<Participant> extractParticipant(Cursor returnData) { // The output ArrayList is initialized ArrayList<Participant> output = new ArrayList<Participant>(); // Move the counter to the first item in the return data returnData.moveToFirst(); int count = 0; // While there are still values in the return data while (!returnData.isAfterLast()) { // Add the new Participation to the ArrayList Participant p = new Participant(); p.setId(returnData.getInt(0)); p.setName(returnData.getString(1)); p.setPhoneNumber(returnData.getString(2)); p.setVillage(returnData.getString(3)); p.setAge(returnData.getInt(4)); p.setGender(returnData.getInt(5)); p.setParticipationId(returnData.getInt(6)); p.setSignaturePath(returnData.getString(7)); output.add(count, p); // Advance the Cursor returnData.moveToNext(); // Advance the counter count++; } // Return the ArrayList return output; } }