package com.evancharlton.mileage;
import java.io.File;
import java.util.Calendar;
import java.util.HashMap;
import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import android.text.TextUtils;
import com.evancharlton.mileage.models.FillUp;
import com.evancharlton.mileage.models.ServiceInterval;
import com.evancharlton.mileage.models.Vehicle;
/**
* Note that this app does not currently (as of version > 1.8.4) use a
* ContentProvider for data access (this should all be done through the
* appropriate data Model subclasses). As a result, this class might be updated,
* but its use is highly discouraged (at least until this class is officially
* supported).
*
*/
public class FillUpsProvider extends ContentProvider {
public static final String DATABASE_NAME = "mileage.db";
public static final int DATABASE_VERSION = 4;
public static final String FILLUPS_TABLE_NAME = "fillups";
public static final String VEHICLES_TABLE_NAME = "vehicles";
public static final String MAINTENANCE_TABLE_NAME = "maintenance_intervals";
public static final String VERSION_TABLE_NAME = "version";
public static final String VERSION = "version";
private static HashMap<String, String> s_fillUpsProjectionMap;
private static HashMap<String, String> s_vehiclesProjectionMap;
private static HashMap<String, String> s_maintenanceIntervalsProjectionMap;
private static final int FILLUPS = 1;
private static final int FILLUP_ID = 2;
private static final int VEHICLES = 3;
private static final int VEHICLE_ID = 4;
private static final int MAINTENANCE_INTERVALS = 5;
private static final int MAINTENANCE_INTERVAL_ID = 6;
private static final UriMatcher s_uriMatcher;
static {
s_uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
s_uriMatcher.addURI(FillUp.AUTHORITY, "fillups", FILLUPS);
s_uriMatcher.addURI(FillUp.AUTHORITY, "fillups/#", FILLUP_ID);
s_uriMatcher.addURI(Vehicle.AUTHORITY, "vehicles", VEHICLES);
s_uriMatcher.addURI(Vehicle.AUTHORITY, "vehicles/#", VEHICLE_ID);
s_uriMatcher.addURI(ServiceInterval.AUTHORITY, "intervals", MAINTENANCE_INTERVALS);
s_uriMatcher.addURI(ServiceInterval.AUTHORITY, "intervals/#", MAINTENANCE_INTERVAL_ID);
s_fillUpsProjectionMap = new HashMap<String, String>();
s_fillUpsProjectionMap.put(FillUp._ID, FillUp._ID);
s_fillUpsProjectionMap.put(FillUp.PRICE, FillUp.PRICE);
s_fillUpsProjectionMap.put(FillUp.AMOUNT, FillUp.AMOUNT);
s_fillUpsProjectionMap.put(FillUp.ODOMETER, FillUp.ODOMETER);
s_fillUpsProjectionMap.put(FillUp.VEHICLE_ID, FillUp.VEHICLE_ID);
s_fillUpsProjectionMap.put(FillUp.DATE, FillUp.DATE);
s_fillUpsProjectionMap.put(FillUp.LATITUDE, FillUp.LATITUDE);
s_fillUpsProjectionMap.put(FillUp.LONGITUDE, FillUp.LONGITUDE);
s_fillUpsProjectionMap.put(FillUp.COMMENT, FillUp.COMMENT);
s_fillUpsProjectionMap.put(FillUp.PARTIAL, FillUp.PARTIAL);
s_fillUpsProjectionMap.put(FillUp.RESTART, FillUp.RESTART);
s_vehiclesProjectionMap = new HashMap<String, String>();
s_vehiclesProjectionMap.put(Vehicle._ID, Vehicle._ID);
s_vehiclesProjectionMap.put(Vehicle.MAKE, Vehicle.MAKE);
s_vehiclesProjectionMap.put(Vehicle.MODEL, Vehicle.MODEL);
s_vehiclesProjectionMap.put(Vehicle.TITLE, Vehicle.TITLE);
s_vehiclesProjectionMap.put(Vehicle.YEAR, Vehicle.YEAR);
s_vehiclesProjectionMap.put(Vehicle.DEFAULT, Vehicle.DEFAULT);
s_vehiclesProjectionMap.put(Vehicle.DISTANCE_UNITS, Vehicle.DISTANCE_UNITS);
s_vehiclesProjectionMap.put(Vehicle.VOLUME_UNITS, Vehicle.VOLUME_UNITS);
s_maintenanceIntervalsProjectionMap = new HashMap<String, String>();
s_maintenanceIntervalsProjectionMap.put(ServiceInterval._ID, ServiceInterval._ID);
s_maintenanceIntervalsProjectionMap.put(ServiceInterval.CREATE_DATE, ServiceInterval.CREATE_DATE);
s_maintenanceIntervalsProjectionMap.put(ServiceInterval.CREATE_ODOMETER, ServiceInterval.CREATE_ODOMETER);
s_maintenanceIntervalsProjectionMap.put(ServiceInterval.DESCRIPTION, ServiceInterval.DESCRIPTION);
s_maintenanceIntervalsProjectionMap.put(ServiceInterval.DISTANCE, ServiceInterval.DISTANCE);
s_maintenanceIntervalsProjectionMap.put(ServiceInterval.DURATION, ServiceInterval.DURATION);
s_maintenanceIntervalsProjectionMap.put(ServiceInterval.VEHICLE_ID, ServiceInterval.VEHICLE_ID);
s_maintenanceIntervalsProjectionMap.put(ServiceInterval.REPEATING, ServiceInterval.REPEATING);
}
private static class DatabaseHelper extends SQLiteOpenHelper {
DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
createDatabase(db);
}
@Override
public void onUpgrade(SQLiteDatabase db, final int oldVersion, final int newVersion) {
upgradeDatabase(db, oldVersion, newVersion);
}
}
public static void initTables(SQLiteDatabase db) {
StringBuilder sql = new StringBuilder();
sql.append("INSERT INTO ").append(VEHICLES_TABLE_NAME).append(" (");
sql.append(Vehicle.MAKE).append(", ").append(Vehicle.MODEL).append(", ");
sql.append(Vehicle.YEAR).append(", ").append(Vehicle.TITLE).append(", ");
sql.append(Vehicle.DEFAULT);
sql.append(") VALUES ('Make', 'Model', '");
sql.append(Calendar.getInstance().get(Calendar.YEAR));
sql.append("', 'Default Vehicle', '").append(System.currentTimeMillis()).append("');");
db.execSQL(sql.toString());
sql = new StringBuilder();
sql.append("INSERT INTO ").append(VERSION_TABLE_NAME).append(" (").append(VERSION).append(") VALUES (?)");
db.execSQL(sql.toString(), new String[] {
String.valueOf(DATABASE_VERSION)
});
}
private DatabaseHelper m_helper;
@Override
public boolean onCreate() {
m_helper = new DatabaseHelper(getContext());
return true;
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
SQLiteDatabase db = m_helper.getWritableDatabase();
int count;
switch (s_uriMatcher.match(uri)) {
case FILLUPS:
count = db.delete(FILLUPS_TABLE_NAME, selection, selectionArgs);
break;
case FILLUP_ID:
String fillUpId = uri.getPathSegments().get(1);
count = db.delete(FILLUPS_TABLE_NAME, FillUp._ID + " = " + fillUpId + (!TextUtils.isEmpty(selection) ? " AND (" + selection + ")" : ""), selectionArgs);
break;
case VEHICLES:
count = db.delete(VEHICLES_TABLE_NAME, selection, selectionArgs);
break;
case VEHICLE_ID:
String vehicleId = uri.getPathSegments().get(1);
count = db.delete(VEHICLES_TABLE_NAME, Vehicle._ID + " = " + vehicleId + (!TextUtils.isEmpty(selection) ? " AND (" + selection + ")" : ""), selectionArgs);
break;
case MAINTENANCE_INTERVALS:
count = db.delete(MAINTENANCE_TABLE_NAME, selection, selectionArgs);
break;
case MAINTENANCE_INTERVAL_ID:
String intervalId = uri.getPathSegments().get(1);
count = db.delete(MAINTENANCE_TABLE_NAME, ServiceInterval._ID + " = " + intervalId + (!TextUtils.isEmpty(selection) ? " AND (" + selection + ")" : ""), selectionArgs);
break;
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return count;
}
@Override
public String getType(Uri uri) {
switch (s_uriMatcher.match(uri)) {
case FILLUPS:
return FillUp.CONTENT_TYPE;
case FILLUP_ID:
return FillUp.CONTENT_ITEM_TYPE;
case VEHICLES:
return Vehicle.CONTENT_TYPE;
case VEHICLE_ID:
return Vehicle.CONTENT_ITEM_TYPE;
case MAINTENANCE_INTERVALS:
return ServiceInterval.CONTENT_TYPE;
case MAINTENANCE_INTERVAL_ID:
return ServiceInterval.CONTENT_ITEM_TYPE;
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
}
@Override
public Uri insert(Uri uri, ContentValues initialValues) {
int match = s_uriMatcher.match(uri);
switch (match) {
case FILLUPS:
return insertFillup(uri, initialValues);
case VEHICLES:
return insertVehicle(uri, initialValues);
case MAINTENANCE_INTERVALS:
return insertInterval(uri, initialValues);
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
}
private Uri insertInterval(Uri uri, ContentValues initialValues) {
ServiceInterval interval = new ServiceInterval(initialValues);
if (interval.validate() <= 0) {
long id = interval.save();
Uri contentUri = ContentUris.withAppendedId(ServiceInterval.CONTENT_URI, id);
getContext().getContentResolver().notifyChange(contentUri, null);
return contentUri;
}
throw new SQLException("Failed to insert row into " + uri);
}
private Uri insertFillup(Uri uri, ContentValues initialValues) {
FillUp fillup = new FillUp(initialValues);
if (fillup.validate() <= 0) {
long id = fillup.save();
Uri contentUri = ContentUris.withAppendedId(FillUp.CONTENT_URI, id);
getContext().getContentResolver().notifyChange(contentUri, null);
return contentUri;
}
throw new SQLException("Failed to insert row into " + uri);
}
private Uri insertVehicle(Uri uri, ContentValues initialValues) {
Vehicle vehicle = new Vehicle(initialValues);
if (vehicle.validate() <= 0) {
long id = vehicle.save();
Uri contentUri = ContentUris.withAppendedId(Vehicle.CONTENT_URI, id);
getContext().getContentResolver().notifyChange(contentUri, null);
return contentUri;
}
throw new SQLException("Failed to insert row into " + uri);
}
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
switch (s_uriMatcher.match(uri)) {
case FILLUPS:
qb.setTables(FILLUPS_TABLE_NAME);
qb.setProjectionMap(s_fillUpsProjectionMap);
break;
case FILLUP_ID:
qb.setTables(FILLUPS_TABLE_NAME);
qb.setProjectionMap(s_fillUpsProjectionMap);
qb.appendWhere(FillUp._ID + " = " + uri.getPathSegments().get(1));
break;
case VEHICLES:
qb.setTables(VEHICLES_TABLE_NAME);
qb.setProjectionMap(s_vehiclesProjectionMap);
break;
case VEHICLE_ID:
qb.setTables(VEHICLES_TABLE_NAME);
qb.setProjectionMap(s_vehiclesProjectionMap);
qb.appendWhere(Vehicle._ID + " = " + uri.getPathSegments().get(1));
break;
case MAINTENANCE_INTERVALS:
qb.setTables(MAINTENANCE_TABLE_NAME);
qb.setProjectionMap(s_maintenanceIntervalsProjectionMap);
break;
case MAINTENANCE_INTERVAL_ID:
qb.setTables(MAINTENANCE_TABLE_NAME);
qb.setProjectionMap(s_maintenanceIntervalsProjectionMap);
qb.appendWhere(ServiceInterval._ID + " = " + uri.getPathSegments().get(1));
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
String orderBy = null;
if (TextUtils.isEmpty(sortOrder)) {
if (qb.getTables() == FILLUPS_TABLE_NAME) {
orderBy = FillUp.DEFAULT_SORT_ORDER;
} else {
orderBy = Vehicle.DEFAULT_SORT_ORDER;
}
} else {
orderBy = sortOrder;
}
SQLiteDatabase db;
try {
db = m_helper.getReadableDatabase();
} catch (SQLiteException e) {
e.printStackTrace();
db = m_helper.getWritableDatabase();
}
Cursor c = qb.query(db, projection, selection, selectionArgs, null, null, orderBy);
c.setNotificationUri(getContext().getContentResolver(), uri);
return c;
}
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
SQLiteDatabase db = m_helper.getWritableDatabase();
int count;
String clause;
switch (s_uriMatcher.match(uri)) {
case FILLUPS:
count = db.update(FILLUPS_TABLE_NAME, values, selection, selectionArgs);
break;
case FILLUP_ID:
String fillUpId = uri.getPathSegments().get(1);
clause = FillUp._ID + " = " + fillUpId + (!TextUtils.isEmpty(selection) ? " AND (" + selection + ")" : "");
count = db.update(FILLUPS_TABLE_NAME, values, clause, selectionArgs);
break;
case VEHICLES:
count = db.update(VEHICLES_TABLE_NAME, values, selection, selectionArgs);
break;
case VEHICLE_ID:
String vehicleId = uri.getPathSegments().get(1);
clause = Vehicle._ID + " = " + vehicleId + (!TextUtils.isEmpty(selection) ? " AND (" + selection + ")" : "");
count = db.update(VEHICLES_TABLE_NAME, values, clause, selectionArgs);
break;
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return count;
}
public static HashMap<String, String> getFillUpsProjection() {
return s_fillUpsProjectionMap;
}
public static HashMap<String, String> getVehiclesProjection() {
return s_vehiclesProjectionMap;
}
public static boolean upgradeDatabase() {
SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(new File("/data/data/" + Mileage.PACKAGE + "/databases/" + FillUpsProvider.DATABASE_NAME), null);
boolean result = upgradeDatabase(db);
db.close();
return result;
}
public static boolean upgradeDatabase(SQLiteDatabase db) {
// see if we can determine what version we have
int oldVersion = -1;
Cursor c = db.rawQuery("PRAGMA table_info(" + VERSION_TABLE_NAME + ");", null);
if (c.getCount() == 0) {
oldVersion = 3;
} else {
Cursor versionQuery = db.query(VERSION_TABLE_NAME, new String[] {
VERSION
}, null, null, null, null, null);
if (versionQuery.getCount() == 1) {
versionQuery.moveToFirst();
oldVersion = versionQuery.getInt(versionQuery.getColumnIndex(VERSION));
}
versionQuery.close();
}
c.close();
if (oldVersion > 0 && oldVersion != DATABASE_VERSION) {
// Let's do this shit!
upgradeDatabase(db, oldVersion, oldVersion + 1);
return true;
}
return false;
}
private static void upgradeDatabase(SQLiteDatabase db, final int oldVersion, final int newVersion) {
try {
if (oldVersion == 3) {
StringBuilder sb = new StringBuilder();
sb.append("ALTER TABLE ").append(FILLUPS_TABLE_NAME).append(" ADD COLUMN ").append(FillUp.PARTIAL).append(" INTEGER;");
db.execSQL(sb.toString());
sb = new StringBuilder();
sb.append("ALTER TABLE ").append(FILLUPS_TABLE_NAME).append(" ADD COLUMN ").append(FillUp.RESTART).append(" INTEGER;");
db.execSQL(sb.toString());
sb = new StringBuilder();
sb.append("ALTER TABLE ").append(VEHICLES_TABLE_NAME).append(" ADD COLUMN ").append(Vehicle.DISTANCE_UNITS).append(" INTEGER DEFAULT -1;");
db.execSQL(sb.toString());
sb = new StringBuilder();
sb.append("ALTER TABLE ").append(VEHICLES_TABLE_NAME).append(" ADD COLUMN ").append(Vehicle.VOLUME_UNITS).append(" INTEGER DEFAULT -1;");
db.execSQL(sb.toString());
sb = new StringBuilder();
sb.append("CREATE TABLE ").append(MAINTENANCE_TABLE_NAME).append(" (");
sb.append(ServiceInterval._ID).append(" INTEGER PRIMARY KEY AUTOINCREMENT,");
sb.append(ServiceInterval.CREATE_DATE).append(" INTEGER,");
sb.append(ServiceInterval.CREATE_ODOMETER).append(" DOUBLE,");
sb.append(ServiceInterval.DESCRIPTION).append(" TEXT,");
sb.append(ServiceInterval.DISTANCE).append(" DOUBLE,");
sb.append(ServiceInterval.DURATION).append(" INTEGER,");
sb.append(ServiceInterval.VEHICLE_ID).append(" INTEGER,");
sb.append(ServiceInterval.REPEATING).append(" INTEGER");
sb.append(");");
db.execSQL(sb.toString());
sb = new StringBuilder();
sb.append("CREATE TABLE ").append(VERSION_TABLE_NAME).append(" (");
sb.append(VERSION).append(" INTEGER");
sb.append(");");
db.execSQL(sb.toString());
return;
} else if (oldVersion == 2) {
StringBuilder sb = new StringBuilder();
sb.append("ALTER TABLE ").append(FILLUPS_TABLE_NAME).append(" ADD COLUMN ").append(FillUp.COMMENT).append(" TEXT;");
db.execSQL(sb.toString());
sb = new StringBuilder();
sb.append("ALTER TABLE ").append(VEHICLES_TABLE_NAME).append(" ADD COLUMN ").append(Vehicle.DEFAULT).append(" INTEGER;");
db.execSQL(sb.toString());
return;
}
StringBuilder sb = new StringBuilder();
sb.append("DROP TABLE IF EXISTS ").append(FILLUPS_TABLE_NAME).append(";");
db.execSQL(sb.toString());
sb = new StringBuilder();
sb.append("DROP TABLE IF EXISTS ").append(VEHICLES_TABLE_NAME).append(";");
db.execSQL(sb.toString());
sb = new StringBuilder();
sb.append("DROP TABLE IF EXISTS ").append(MAINTENANCE_TABLE_NAME).append(";");
db.execSQL(sb.toString());
createDatabase(db);
} catch (SQLiteException e) {
e.printStackTrace();
}
}
private static void createDatabase(SQLiteDatabase db) {
StringBuilder sql = new StringBuilder();
sql.append("CREATE TABLE ").append(FILLUPS_TABLE_NAME).append(" (");
sql.append(FillUp._ID).append(" INTEGER PRIMARY KEY AUTOINCREMENT,");
sql.append(FillUp.PRICE).append(" DOUBLE,");
sql.append(FillUp.AMOUNT).append(" DOUBLE,");
sql.append(FillUp.ODOMETER).append(" DOUBLE,");
sql.append(FillUp.VEHICLE_ID).append(" INTEGER,");
sql.append(FillUp.DATE).append(" INTEGER,");
sql.append(FillUp.LATITUDE).append(" DOUBLE,");
sql.append(FillUp.LONGITUDE).append(" DOUBLE,");
sql.append(FillUp.COMMENT).append(" TEXT,");
sql.append(FillUp.PARTIAL).append(" INTEGER,");
sql.append(FillUp.RESTART).append(" INTEGER");
sql.append(");");
db.execSQL(sql.toString());
sql = new StringBuilder();
sql.append("CREATE TABLE ").append(VEHICLES_TABLE_NAME).append(" (");
sql.append(Vehicle._ID).append(" INTEGER PRIMARY KEY AUTOINCREMENT,");
sql.append(Vehicle.MAKE).append(" TEXT,");
sql.append(Vehicle.MODEL).append(" TEXT,");
sql.append(Vehicle.TITLE).append(" TEXT,");
sql.append(Vehicle.YEAR).append(" TEXT,");
sql.append(Vehicle.DEFAULT).append(" INTEGER,");
sql.append(Vehicle.DISTANCE_UNITS).append(" INTEGER DEFAULT -1,");
sql.append(Vehicle.VOLUME_UNITS).append(" INTEGER DEFAULT -1");
sql.append(");");
db.execSQL(sql.toString());
sql = new StringBuilder();
sql.append("CREATE TABLE ").append(MAINTENANCE_TABLE_NAME).append(" (");
sql.append(ServiceInterval._ID).append(" INTEGER PRIMARY KEY AUTOINCREMENT,");
sql.append(ServiceInterval.CREATE_DATE).append(" INTEGER,");
sql.append(ServiceInterval.CREATE_ODOMETER).append(" DOUBLE,");
sql.append(ServiceInterval.DESCRIPTION).append(" TEXT,");
sql.append(ServiceInterval.DISTANCE).append(" DOUBLE,");
sql.append(ServiceInterval.DURATION).append(" INTEGER,");
sql.append(ServiceInterval.VEHICLE_ID).append(" INTEGER,");
sql.append(ServiceInterval.REPEATING).append(" INTEGER");
sql.append(");");
db.execSQL(sql.toString());
sql = new StringBuilder();
sql.append("CREATE TABLE ").append(VERSION_TABLE_NAME).append(" (");
sql.append(VERSION).append(" INTEGER");
sql.append(");");
db.execSQL(sql.toString());
initTables(db);
}
}