package me.guillaumin.android.osmtracker.db;
import java.io.File;
import java.io.FilenameFilter;
import me.guillaumin.android.osmtracker.OSMTracker;
import me.guillaumin.android.osmtracker.db.TrackContentProvider.Schema;
import me.guillaumin.android.osmtracker.db.model.Track.OSMVisibility;
import me.guillaumin.android.osmtracker.util.FileSystemUtils;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
/**
* Helper for managing database.
*
* @author Nicolas Guillaumin
*
*/
public class DatabaseHelper extends SQLiteOpenHelper {
private static final String TAG = DatabaseHelper.class.getSimpleName();
/**
* SQL for creating table TRACKPOINT
*/
private static final String SQL_CREATE_TABLE_TRACKPOINT = ""
+ "create table " + Schema.TBL_TRACKPOINT + " ("
+ Schema.COL_ID + " integer primary key autoincrement,"
+ Schema.COL_TRACK_ID + " integer not null,"
+ Schema.COL_LATITUDE + " double not null,"
+ Schema.COL_LONGITUDE + " double not null,"
+ Schema.COL_SPEED + " double null,"
+ Schema.COL_ELEVATION + " double null,"
+ Schema.COL_ACCURACY + " double null,"
+ Schema.COL_TIMESTAMP + " long not null,"
+ Schema.COL_COMPASS + " double null,"
+ Schema.COL_COMPASS_ACCURACY + " integer null"+ ")";
/**
* SQL for creating index TRACKPOINT_idx (track id)
* @since 12
*/
private static final String SQL_CREATE_IDX_TRACKPOINT_TRACK
= "create index if not exists "
+ Schema.TBL_TRACKPOINT
+ "_idx ON " + Schema.TBL_TRACKPOINT + "(" + Schema.COL_TRACK_ID + ")";
/**
* SQL for creating table WAYPOINT
*/
private static final String SQL_CREATE_TABLE_WAYPOINT = ""
+ "create table " + Schema.TBL_WAYPOINT + " ("
+ Schema.COL_ID + " integer primary key autoincrement,"
+ Schema.COL_TRACK_ID + " integer not null,"
+ Schema.COL_UUID + " text,"
+ Schema.COL_LATITUDE + " double not null,"
+ Schema.COL_LONGITUDE + " double not null,"
+ Schema.COL_ELEVATION + " double null,"
+ Schema.COL_ACCURACY + " double null,"
+ Schema.COL_TIMESTAMP + " long not null,"
+ Schema.COL_NAME + " text,"
+ Schema.COL_LINK + " text,"
+ Schema.COL_NBSATELLITES + " integer not null,"
+ Schema.COL_COMPASS + " double null,"
+ Schema.COL_COMPASS_ACCURACY + " integer null"+ ")";
/**
* SQL for creating index WAYPOINT_idx (track id)
* @since 12
*/
private static final String SQL_CREATE_IDX_WAYPOINT_TRACK
= "create index if not exists "
+ Schema.TBL_WAYPOINT
+ "_idx ON " + Schema.TBL_WAYPOINT + "(" + Schema.COL_TRACK_ID + ")";
/**
* SQL for creating table TRACK
* @since 5
*/
@SuppressWarnings("deprecation")
private static final String SQL_CREATE_TABLE_TRACK = ""
+ "create table " + Schema.TBL_TRACK + " ("
+ Schema.COL_ID + " integer primary key autoincrement,"
+ Schema.COL_NAME + " text,"
+ Schema.COL_DESCRIPTION + " text,"
+ Schema.COL_TAGS + " text,"
+ Schema.COL_OSM_VISIBILITY + " text default '"+OSMVisibility.Private+"',"
+ Schema.COL_START_DATE + " long not null,"
+ Schema.COL_DIR + " text," // unused since DB_VERSION 13, since SQLite doesn't support to remove a column it will stay for now
+ Schema.COL_ACTIVE + " integer not null default 0,"
+ Schema.COL_EXPORT_DATE + " long," // null indicates not yet exported
+ Schema.COL_OSM_UPLOAD_DATE + " long" // null indicates not yet uploaded
+ ")";
/**
* Database name.
*/
public static final String DB_NAME = OSMTracker.class.getSimpleName();
/**
* Database version.
* If you change the version, be sure that {@link #onUpgrade(SQLiteDatabase, int, int)} can handle it.
* Only required for versions after v0.5.0 as before the DB was fully erased and recreated from scratch
* for each new track.
*<pre>
* v1: (r117) v0.4.0, v0.4.1
* v2: add TBL_CONFIG; that table's been dropped since then (r163) v0.4.2
* v3: add TBL_WAYPOINT.COL_UUID (r187) v0.4.3
* v5: add TBL_TRACK; TRACKPOINT, WAYPOINT +COL_TRACK_ID (r198)
* v7: add TBL_TRACK.COL_DIR; drop TBL_CONFIG (r201)
* v9: add TBL_TRACK.COL_ACTIVE (r206)
* v12: add TBL_TRACK.COL_EXPORT_DATE, IDX_TRACKPOINT_TRACK, IDX_WAYPOINT_TRACK (r207) v0.5.0
* v13: TBL_TRACK.COL_DIR is now deprecated (rxxx) v0.5.3 TODO: fill in correct revision and version
* v14: add TBL_TRACK.COL_OSM_UPLOAD_DATE, TBL_TRACK.COL_DESCRIPTION,
* TBL_TRACK.COL_TAGS and TBL_TRACK.COL_OSM_VISIBILITY for OSM upload - v0.6.0
* v15: add TBL_TRACKPOINT.COL_SPEED
* v16: add TBL_TRACKPOINT.COL_COMPASS, TBL_TRACKPOINT.COL_COMPASS_ACCURACY,
* TBL_WAYPOINT.COL_COMPASS and TBL_WAYPOINT.COL_COMPASS_ACCURACY
*</pre>
*/
private static final int DB_VERSION = 16;
public DatabaseHelper(Context context) {
super(context, DB_NAME, null, DB_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("drop table if exists " + Schema.TBL_TRACKPOINT);
db.execSQL(SQL_CREATE_TABLE_TRACKPOINT);
db.execSQL(SQL_CREATE_IDX_TRACKPOINT_TRACK);
db.execSQL("drop table if exists " + Schema.TBL_WAYPOINT);
db.execSQL(SQL_CREATE_TABLE_WAYPOINT);
db.execSQL(SQL_CREATE_IDX_WAYPOINT_TRACK);
db.execSQL("drop table if exists " + Schema.TBL_TRACK);
db.execSQL(SQL_CREATE_TABLE_TRACK);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
switch(oldVersion){
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
case 8:
case 9:
case 10:
case 11: //pre v0.5.0 (completely create a new database)
onCreate(db);
break;
case 12:
manageNewStoragePath(db);
case 13:
// Create 'osm_upload_date', 'description', 'tags' and 'visibility'
db.execSQL("alter table " + Schema.TBL_TRACK + " add column " + Schema.COL_OSM_UPLOAD_DATE+ " long");
db.execSQL("alter table " + Schema.TBL_TRACK + " add column " + Schema.COL_DESCRIPTION + " text");
db.execSQL("alter table " + Schema.TBL_TRACK + " add column " + Schema.COL_TAGS + " text");
db.execSQL("alter table " + Schema.TBL_TRACK + " add column " + Schema.COL_OSM_VISIBILITY
+ " text default '"+OSMVisibility.Private+"'");
case 14:
db.execSQL("alter table " + Schema.TBL_TRACKPOINT + " add column " + Schema.COL_SPEED + " double null");
case 15:
db.execSQL("alter table " + Schema.TBL_TRACKPOINT + " add column " + Schema.COL_COMPASS + " double null");
db.execSQL("alter table " + Schema.TBL_TRACKPOINT + " add column " + Schema.COL_COMPASS_ACCURACY + " integer null");
db.execSQL("alter table " + Schema.TBL_WAYPOINT + " add column " + Schema.COL_COMPASS + " double null");
db.execSQL("alter table " + Schema.TBL_WAYPOINT + " add column " + Schema.COL_COMPASS_ACCURACY + " integer null");
}
}
/**
* copies files from the tracks to our new storage directory and removes the path reference in COL_DIR
* @param db the database to work on
*/
@SuppressWarnings("deprecation")
private void manageNewStoragePath(SQLiteDatabase db){
Log.d(TAG,"manageNewStoragePath");
// we'll need this FilenameFitler to clean up our track directory
FilenameFilter gpxFilenameFilter = new FilenameFilter() {
@Override
public boolean accept(File dir, String filename) {
if(filename.toLowerCase().endsWith(".gpx"))
return true;
return false;
}
};
// query all tracks
String[] columns = new String[]{Schema.COL_ID, Schema.COL_DIR};
Cursor cursor = db.query(Schema.TBL_TRACK, columns, null, null, null, null, null);
// if we have a valid cursor and can write to the sdcard, we'll go on and try to copy the files
if(cursor != null && cursor.moveToFirst()){
Log.d(TAG, "manageNewStoragePath (found " + cursor.getCount() + " tracks to be processed)");
do{
long trackId = cursor.getLong(cursor.getColumnIndex(Schema.COL_ID));
Log.d(TAG,"manageNewStoragePath (" + trackId + ")");
String oldDirName = cursor.getString(cursor.getColumnIndex(Schema.COL_DIR));
File newDir = DataHelper.getTrackDirectory(trackId);
File oldDir = new File(oldDirName);
if(oldDir.exists() && oldDir.canRead()){
// if our new directory doesn't exist, we'll create it
if(!newDir.exists())
newDir.mkdirs();
if(newDir.exists() && newDir.canWrite()){
Log.d(TAG,"manageNewStoragePath (" + trackId + "): copy directory");
// we'll first copy all files to our new storage area... we'll clean up later
FileSystemUtils.copyDirectoryContents(newDir, oldDir);
// cleaning up new storage area
// find gpx files we accidentally copied to our new storage area and delete them
for(File gpxFile:newDir.listFiles(gpxFilenameFilter)){
Log.d(TAG,"manageNewStoragePath (" + trackId + "): deleting gpx file ["+gpxFile+"]");
gpxFile.delete();
}
}else{
Log.e(TAG, "manageNewStoragePath (" + trackId + "): directory ["+newDir+"] is not writable or could not be created");
}
}
}while(cursor.moveToNext());
}
//close cursor
if(cursor !=null && !cursor.isClosed()){
cursor.close();
}
ContentValues vals = new ContentValues();
vals.putNull(Schema.COL_DIR);
db.update(Schema.TBL_TRACK, vals, null, null);
}
}