package org.commcare.models.database; import android.content.ContentValues; import android.content.Context; import android.util.Log; import android.util.Pair; import net.sqlcipher.database.SQLiteDatabase; import org.commcare.CommCareApplication; import org.commcare.modern.database.DatabaseHelper; import org.commcare.modern.models.EncryptedModel; import org.commcare.modern.models.RecordTooLargeException; import org.javarosa.core.services.storage.Persistable; import org.javarosa.core.util.externalizable.Externalizable; import org.javarosa.core.util.externalizable.PrototypeFactory; import java.util.HashMap; import java.util.Map; /** * Essentially a wrapper around the Java-generic DatabaseHelper * class that allows us to use those function i Android idiomatic classes * (IE ResultSet -> ContentValues, Android Pair instead of generic Pair, etc. * * @author ctsims * @author wspride */ public abstract class AndroidDbHelper extends DatabaseHelper { private final static String TAG = AndroidDbHelper.class.getSimpleName(); protected final Context c; public AndroidDbHelper(Context c) { this.c = c; } public abstract SQLiteDatabase getHandle(); public ContentValues getContentValues(Externalizable e) { ContentValues contentValues = new ContentValues(); HashMap<String, Object> metaFieldsAndValues = DatabaseHelper.getMetaFieldsAndValues(e); copyMetadataIntoContentValues(metaFieldsAndValues, contentValues); return contentValues; } public ContentValues getContentValuesWithCustomData(Externalizable e, byte[] customData) { ContentValues contentValues = new ContentValues(); HashMap<String, Object> metaFieldsAndValues = DatabaseHelper.getNonDataMetaEntries(e); copyMetadataIntoContentValues(metaFieldsAndValues, contentValues); contentValues.put(DATA_COL, customData); return contentValues; } public ContentValues getNonDataContentValues(Externalizable e) { ContentValues contentValues = new ContentValues(); HashMap<String, Object> metaFieldsAndValues = DatabaseHelper.getNonDataMetaEntries(e); copyMetadataIntoContentValues(metaFieldsAndValues, contentValues); return contentValues; } private void copyMetadataIntoContentValues(HashMap<String, Object> metaFieldsAndValues, ContentValues contentValues) { for (Map.Entry<String, Object> entry : metaFieldsAndValues.entrySet()) { String key = entry.getKey(); Object obj = entry.getValue(); if (obj instanceof String) { contentValues.put(key, (String)obj); } else if (obj instanceof Integer) { contentValues.put(key, (Integer)obj); } else if (obj instanceof Long) { contentValues.put(key, (Long)obj); } else if (obj instanceof byte[]) { checkBlobSize((byte[]) obj); contentValues.put(key, (byte[])obj); } else { Log.w(TAG, "Couldn't determine type of object: " + obj); } } } private static void checkBlobSize(byte[] blob) { int blobSize = blob.length; if (blobSize > HybridFileBackedSqlStorage.ONE_MB_DB_SIZE_LIMIT) { throw new RecordTooLargeException(blobSize); } } public Pair<String, String[]> createWhereAndroid(String[] fieldNames, Object[] values, EncryptedModel em, Persistable p) { org.commcare.modern.util.Pair<String, String[]> mPair = DatabaseHelper.createWhere(fieldNames, values, em, p); return new Pair<>(mPair.first, mPair.second); } public PrototypeFactory getPrototypeFactory() { return CommCareApplication.instance().getPrototypeFactory(c); } }