/* @file DeviceHelper.java * * @author marco corvi * @date nov 2011 * * @brief TopoDroid SQLite "device" database manager * -------------------------------------------------------- * Copyright This sowftare is distributed under GPL-3.0 or later * See the file COPYING. * -------------------------------------------------------- */ package com.topodroid.DistoX; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.FileReader; import java.io.BufferedReader; import java.io.FileWriter; import java.io.PrintWriter; import android.content.Context; import android.content.ContentValues; import android.database.Cursor; import android.database.SQLException; import android.database.DataSetObservable; import android.database.DatabaseUtils.InsertHelper; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import android.database.sqlite.SQLiteStatement; import android.database.sqlite.SQLiteException; import android.database.sqlite.SQLiteDiskIOException; import android.widget.Toast; import android.util.Log; import java.util.ArrayList; import java.util.List; import java.util.Locale; import java.util.HashMap; public class DeviceHelper extends DataSetObservable { static final String DB_VERSION = "26"; static final int DATABASE_VERSION = 26; static final int DATABASE_VERSION_MIN = 21; private static final String CONFIG_TABLE = "configs"; private static final String CALIB_TABLE = "calibs"; private static final String GM_TABLE = "gms"; private static final String DEVICE_TABLE = "devices"; private SQLiteDatabase myDB = null; private long myNextId; // id of next shot private long myNextCId; // id of next calib-data private SQLiteStatement updateConfig; private SQLiteStatement updateGMGroupStmt = null; private SQLiteStatement updateGMErrorStmt = null; private SQLiteStatement deleteGMStmt = null; private SQLiteStatement updateCalibStmt = null; private SQLiteStatement updateCalibAlgoStmt = null; private SQLiteStatement updateCalibCoeffStmt = null; private SQLiteStatement updateCalibErrorStmt = null; private SQLiteStatement resetAllGMStmt = null; //these are real database "delete" private SQLiteStatement doDeleteGMStmt = null; private SQLiteStatement doDeleteCalibStmt = null; private SQLiteStatement updateDeviceHeadTailStmt = null; private SQLiteStatement updateDeviceModelStmt = null; private SQLiteStatement updateDeviceNicknameStmt = null; private ArrayList<DataListener> mListeners; // ---------------------------------------------------------------------- // DATABASE private Context mContext; public SQLiteDatabase getDb() { return myDB; } public DeviceHelper( Context context, ArrayList<DataListener> listeners ) { mContext = context; mListeners = listeners; openDatabase(); } public void closeDatabase() { if ( myDB == null ) return; myDB.close(); myDB = null; } public void openDatabase() { String database_name = TDPath.getDeviceDatabase(); DistoXOpenHelper openHelper = new DistoXOpenHelper( mContext, database_name ); try { myDB = openHelper.getWritableDatabase(); if ( myDB == null ) { TDLog.Error( "failed get writable database " + database_name ); return; } while ( myDB.isDbLockedByOtherThreads() ) { try { Thread.sleep( 200 ); } catch ( InterruptedException e ) {} } updateConfig = myDB.compileStatement( "UPDATE configs SET value=? WHERE key=?" ); } catch ( SQLiteException e ) { myDB = null; TDLog.Error( "DeviceHelper cstr failed to get DB " + e.getMessage() ); } } private void logError( String msg, SQLiteException e ) { TDLog.Error("DB " + msg + ": " + e.getMessage() ); } private void handleDiskIOError( SQLiteDiskIOException e ) { Log.e("DistoX", "DB disk error " + e.getMessage() ); TopoDroidApp.mActivity.runOnUiThread( new Runnable() { public void run() { Toast toast = Toast.makeText( mContext, "Critical failure: Disk i/o error", Toast.LENGTH_LONG ); toast.getView().setBackgroundColor( 0xff993333 ); toast.show(); } } ); } // ---------------------------------------------------------------------- // CALIBRATION DATA void deleteGM( long cid, long id, boolean delete ) { // if ( myDB == null ) return; if ( deleteGMStmt == null ) deleteGMStmt = myDB.compileStatement( "UPDATE gms set status=? WHERE calibID=? AND id=?" ); deleteGMStmt.bindLong( 1, delete? 1 : 0 ); deleteGMStmt.bindLong( 2, cid ); deleteGMStmt.bindLong( 3, id ); try { deleteGMStmt.execute(); } catch ( SQLiteDiskIOException e ) { handleDiskIOError( e ); } catch (SQLiteException e ) { logError( "delete GM " + cid + "/" + id, e ); } } public void doDeleteCalib( long cid ) { // if ( myDB == null ) return; if ( doDeleteGMStmt == null ) doDeleteGMStmt = myDB.compileStatement( "DELETE FROM gms where calibId=?" ); if ( doDeleteCalibStmt == null ) doDeleteCalibStmt = myDB.compileStatement( "DELETE FROM calibs where id=?" ); doDeleteGMStmt.bindLong( 1, cid ); doDeleteCalibStmt.bindLong( 1, cid ); try { doDeleteGMStmt.execute(); doDeleteCalibStmt.execute(); } catch ( SQLiteDiskIOException e ) { handleDiskIOError( e ); } catch (SQLiteException e ) { logError( "delete calib", e ); } } public long updateGMName( long gid, long cid, String grp ) { // if ( myDB == null ) return -1; if ( updateGMGroupStmt == null ) updateGMGroupStmt = myDB.compileStatement( "UPDATE gms SET grp=? WHERE calibId=? AND id=?" ); updateGMGroupStmt.bindString( 1, grp ); updateGMGroupStmt.bindLong( 2, cid ); updateGMGroupStmt.bindLong( 3, gid ); try { updateGMGroupStmt.execute(); } catch ( SQLiteDiskIOException e ) { handleDiskIOError( e ); } catch (SQLiteException e ) { logError( "update GM " + cid + "/" + gid + " group " + grp, e ); } return 0; } public long updateGMError( long id, long cid, double error ) { // if ( myDB == null ) return -1; if ( updateGMErrorStmt == null ) updateGMErrorStmt = myDB.compileStatement( "UPDATE gms SET error=? WHERE calibId=? AND id=?" ); updateGMErrorStmt.bindDouble( 1, error ); updateGMErrorStmt.bindLong( 2, cid ); updateGMErrorStmt.bindLong( 3, id ); try { updateGMErrorStmt.execute(); } catch ( SQLiteDiskIOException e ) { handleDiskIOError( e ); } catch (SQLiteException e ) { logError( "update GM error", e ); } return 0; } public long insertGM( long cid, long gx, long gy, long gz, long mx, long my, long mz ) { // if ( myDB == null ) return -1; ++ myNextCId; ContentValues cv = new ContentValues(); cv.put( "calibId", cid ); cv.put( "id", myNextCId ); cv.put( "gx", gx ); cv.put( "gy", gy ); cv.put( "gz", gz ); cv.put( "mx", mx ); cv.put( "my", my ); cv.put( "mz", mz ); cv.put( "grp", 0 ); cv.put( "error", 0.0 ); cv.put( "status", 0 ); try { // this method returns the GM-data ID /* long ret = */ myDB.insert( GM_TABLE, null, cv ); // insert returns the nr. of records in the table } catch ( SQLiteDiskIOException e ) { handleDiskIOError( e ); } catch (SQLiteException e ) { logError( "insert GM", e ); } return myNextCId; } // ---------------------------------------------------------------------- // SELECT STATEMENTS public void resetAllGMs( long cid, long start_id ) { if ( resetAllGMStmt == null ) resetAllGMStmt = myDB.compileStatement( "UPDATE gms SET grp=0, error=0 WHERE calibId=? AND id>? AND status=0" ); // resetAllGMStmt = myDB.compileStatement( "UPDATE gms SET grp=0, error=0 WHERE calibId=? AND id>?" ); resetAllGMStmt.bindLong( 1, cid ); resetAllGMStmt.bindLong( 2, start_id ); try { resetAllGMStmt.execute(); } catch ( SQLiteDiskIOException e ) { handleDiskIOError( e ); } catch (SQLiteException e ) { logError( "reset GM " + cid + "/" + start_id, e ); } } public List<CalibCBlock> selectAllGMs( long cid, int status ) { List< CalibCBlock > list = new ArrayList< CalibCBlock >(); // if ( myDB == null ) return list; Cursor cursor = myDB.query(GM_TABLE, new String[] { "id", "gx", "gy", "gz", "mx", "my", "mz", "grp", "error", "status" }, // columns "calibId=?", new String[] { Long.toString(cid) }, null, // groupBy null, // having "id" ); // order by if (cursor.moveToFirst()) { do { if ( status >= (int)cursor.getLong(9) ) { // status == 0 --> only good shots // status == 1 --> all shots CalibCBlock block = new CalibCBlock(); block.setId( cursor.getLong(0), cid ); block.setData( cursor.getLong(1), cursor.getLong(2), cursor.getLong(3), cursor.getLong(4), cursor.getLong(5), cursor.getLong(6) ); block.setGroup( cursor.getLong(7) ); block.setError( (float)( cursor.getDouble(8) ) ); block.setStatus( cursor.getLong(9) ); list.add( block ); } } while (cursor.moveToNext()); } if (cursor != null && !cursor.isClosed()) cursor.close(); return list; } public CalibCBlock selectGM( long id, long cid ) { CalibCBlock block = null; // if ( myDB == null ) return null; Cursor cursor = myDB.query(GM_TABLE, new String[] { "id", "gx", "gy", "gz", "mx", "my", "mz", "grp", "error", "status" }, // columns "calibId=? and id=?", new String[] { Long.toString(cid), Long.toString(id) }, null, // groupBy null, // having null ); // order by if (cursor.moveToFirst()) { block = new CalibCBlock(); block.setId( cursor.getLong(0), cid ); block.setData( cursor.getLong(1), cursor.getLong(2), cursor.getLong(3), cursor.getLong(4), cursor.getLong(5), cursor.getLong(6) ); block.setGroup( cursor.getLong(7) ); block.setError( (float)( cursor.getDouble(8) ) ); block.setStatus( cursor.getLong(9) ); } if (cursor != null && !cursor.isClosed()) { cursor.close(); } return block; } public int selectCalibAlgo( long cid ) { int algo = CalibInfo.ALGO_AUTO; // default // if ( myDB == null ) return 0; Cursor cursor = myDB.query( CALIB_TABLE, new String[] { "algo" }, // columns "id=?", new String[] { Long.toString(cid) }, null, // groupBy null, // having null ); // order by if (cursor.moveToFirst()) { algo = (int)cursor.getLong( 0 ); } if (cursor != null && !cursor.isClosed()) { cursor.close(); } return algo; } public long getCalibCID( String name, String device ) { long id = -1L; Cursor cursor = myDB.query( CALIB_TABLE, new String[] { "id" }, // columns "name=? and device=?", new String[] { name, device }, null, // groupBy null, // having null ); // order by if (cursor.moveToFirst()) { id = cursor.getLong( 0 ); } if (cursor != null && !cursor.isClosed()) { cursor.close(); } return id; } public CalibInfo selectCalibInfo( long cid ) { CalibInfo info = null; // if ( myDB == null ) return null; Cursor cursor = myDB.query( CALIB_TABLE, new String[] { "name", "day", "device", "comment", "algo" }, // columns "id=?", new String[] { Long.toString(cid) }, null, // groupBy null, // having null ); // order by if (cursor.moveToFirst()) { info = new CalibInfo( cid, cursor.getString( 0 ), cursor.getString( 1 ), cursor.getString( 2 ), cursor.getString( 3 ), (int)cursor.getLong( 4 ) ); } if (cursor != null && !cursor.isClosed()) { cursor.close(); } return info; } public void selectCalibError( long cid, CalibResult res ) { // if ( myDB == null ) return; Cursor cursor = myDB.query( CALIB_TABLE, new String[] { "error", "max_error", "iterations", "stddev" }, // columns "id=?", new String[] { Long.toString(cid) }, null, // groupBy null, // having null ); // order by if (cursor.moveToFirst()) { // Log.v( "DistoX", "select calib error " + cursor.getString(0) + " " + cursor.getString(1) + " " + cursor.getString(2) ); try { String str = cursor.getString(0); if ( str != null ) res.error = Float.parseFloat( str ); str = cursor.getString(1); if ( str != null ) res.max_error = Float.parseFloat( str ); str = cursor.getString(2); if ( str != null ) res.iterations = Integer.parseInt( str ); str = cursor.getString(3); if ( str != null ) res.stddev = Float.parseFloat( str ); } catch ( NumberFormatException e ) { TDLog.Error( "selectCalibError parse Float error: calib ID " + cid ); } } if (cursor != null && !cursor.isClosed()) { cursor.close(); } } public String selectCalibCoeff( long cid ) { String coeff = null; // if ( myDB == null ) return null; Cursor cursor = myDB.query( CALIB_TABLE, new String[] { "coeff" }, // columns "id=?", new String[] { Long.toString(cid) }, null, // groupBy null, // having null ); // order by if (cursor.moveToFirst()) { coeff = cursor.getString( 0 ); } if (cursor != null && !cursor.isClosed()) { cursor.close(); } return coeff; } // ---------------------------------------------------------------------- // SELECT: LIST SURVEY / CABIL NAMES private List<String> selectAllNames( String table ) { TDLog.Log( TDLog.LOG_DB, "selectAllNames table " + table ); List< String > list = new ArrayList< String >(); // if ( myDB == null ) return list; Cursor cursor = myDB.query( table, new String[] { "name" }, // columns null, null, null, null, "name" ); if (cursor.moveToFirst()) { do { list.add( cursor.getString(0) ); } while (cursor.moveToNext()); } if (cursor != null && !cursor.isClosed()) { cursor.close(); } TDLog.Log( TDLog.LOG_DB, "found " + list.size() + " names " ); return list; } public List<String> selectAllCalibs() { return selectAllNames( CALIB_TABLE ); } public List<String> selectDeviceCalibs( String device ) { List<String> ret = new ArrayList<String>(); Cursor cursor = myDB.query( CALIB_TABLE, new String[] { "name" }, // columns "device=?", new String[] { device }, null, // groupBy null, // having null ); if (cursor != null ) { if ( cursor.moveToFirst() ) { do { ret.add( new String(cursor.getString(0)) ); } while (cursor.moveToNext()); } if ( !cursor.isClosed()) cursor.close(); } return ret; } public List<CalibInfo> selectDeviceCalibsInfo( String device ) { List<CalibInfo> ret = new ArrayList<CalibInfo>(); Cursor cursor = myDB.query( CALIB_TABLE, new String[] { "id", "name", "day", "comment", "algo" }, // columns "device=?", new String[] { device }, null, // groupBy null, // having null ); if (cursor != null ) { if ( cursor.moveToFirst() ) { do { ret.add( new CalibInfo( cursor.getLong(0), cursor.getString(1), cursor.getString(2), device, cursor.getString(3), (int)cursor.getLong(4) ) ); } while (cursor.moveToNext()); } if ( !cursor.isClosed()) cursor.close(); } return ret; } // ---------------------------------------------------------------------- // CONFIG DATA public String getValue( String key ) { if ( myDB == null ) { TDLog.Error( "DeviceHelper::getValue null DB"); return null; } if ( key == null || key.length() == 0 ) { TDLog.Error( "DeviceHelper::getValue null key"); return null; } String value = null; Cursor cursor = myDB.query( CONFIG_TABLE, new String[] { "value" }, // columns "key = ?", new String[] { key }, null, null, null ); if ( cursor != null ) { if (cursor.moveToFirst()) { value = cursor.getString( 0 ); } if ( ! cursor.isClosed()) cursor.close(); } return value; } public void setValue( String key, String value ) { if ( myDB == null ) { TDLog.Error( "DeviceHelper::setValue null DB"); return; } if ( key == null || key.length() == 0 ) { TDLog.Error( "DeviceHelper::setValue null key"); return; } if ( value == null || value.length() == 0 ) { TDLog.Error( "DeviceHelper::setValue null value"); return; } Cursor cursor = myDB.query( CONFIG_TABLE, new String[] { "value" }, // columns "key = ?", new String[] { key }, null, null, null ); if ( cursor != null ) { if (cursor.moveToFirst()) { updateConfig.bindString( 1, value ); updateConfig.bindString( 2, key ); try { updateConfig.execute(); } catch ( SQLiteDiskIOException e ) { handleDiskIOError( e ); } catch (SQLiteException e ) { logError( "update config " + key + "=" + value, e ); } } else { ContentValues cv = new ContentValues(); cv.put( "key", key ); cv.put( "value", value ); myDB.insert( CONFIG_TABLE, null, cv ); } if ( ! cursor.isClosed()) cursor.close(); } } // ---------------------------------------------------------------------- // symbols void setSymbolEnabled( String name, boolean enabled ) { setValue( name, enabled? "1" : "0" ); } boolean isSymbolEnabled( String name ) { String enabled = getValue( name ); if ( enabled != null ) { return enabled.equals("1"); } if ( myDB != null ) { ContentValues cv = new ContentValues(); cv.put( "key", name ); cv.put( "value", "1" ); // symbols are enabled by default try { myDB.insert( CONFIG_TABLE, null, cv ); } catch ( SQLiteDiskIOException e ) { handleDiskIOError( e ); } catch (SQLiteException e ) { logError( "symbol enable " + name, e ); } } return true; } // ---------------------------------------------------------------------- /* Set the current survey/calib name. * If the survey/calib name does not exists a new record is inserted in the table */ private String getNameFromId( String table, long id ) { String ret = null; // if ( myDB == null ) return null; Cursor cursor = myDB.query( table, new String[] { "name" }, "id=?", new String[] { Long.toString(id) }, null, null, null ); if (cursor != null ) { if (cursor.moveToFirst() ) { ret = cursor.getString(0); } if ( ! cursor.isClosed()) cursor.close(); } return ret; } private long getIdFromName( String table, String name ) { long id = -1; // if ( myDB == null ) { return -2; } Cursor cursor = myDB.query( table, new String[] { "id" }, "name = ?", new String[] { name }, null, null, null ); if (cursor != null ) { if (cursor.moveToFirst() ) { id = cursor.getLong(0); } if ( ! cursor.isClosed()) cursor.close(); } return id; } // this must be called when the calib name is not yet in the db long insertCalibInfo( String name, String date, String device, String comment, long algo ) { if ( hasCalibName( name ) ) return -1L; long id = 1; Cursor cursor = myDB.query( "calibs", new String[] { "max(id)" }, null, null, null, null, null ); if (cursor.moveToFirst() ) { id = 1 + cursor.getLong(0); } if ( ! cursor.isClosed()) cursor.close(); ContentValues cv = new ContentValues(); cv.put( "id", id ); cv.put( "name", name ); cv.put( "day", date ); cv.put( "device", device ); cv.put( "comment", comment ); cv.put( "algo", algo ); try { myDB.insert( "calibs", null, cv ); } catch ( SQLiteDiskIOException e ) { handleDiskIOError( e ); } catch (SQLiteException e ) { logError( "insert calib info", e ); } myNextCId = 0; return id; } // used only by setCalib private long setCalibName( String name ) { long id = -1; // if ( myDB == null ) { return 0; } // TDLog.Log( TDLog.LOG_DB, "set Calib Name >" + name + "< table " + table ); Cursor cursor = myDB.query( CALIB_TABLE, new String[] { "id" }, "name = ?", new String[] { name }, null, null, null ); if (cursor.moveToFirst() ) { id = cursor.getLong(0); if (cursor != null && !cursor.isClosed()) { cursor.close(); } } else { if (cursor != null && !cursor.isClosed()) { cursor.close(); } // SELECT max(id) FROM table cursor = myDB.query( CALIB_TABLE, new String[] { "max(id)" }, null, null, null, null, null ); if (cursor.moveToFirst() ) { id = 1 + cursor.getLong(0); } else { id = 1; } if (cursor != null && !cursor.isClosed()) { cursor.close(); } // INSERT INTO table VALUES( id, name, "", "" ) ContentValues cv = new ContentValues(); cv.put( "id", id ); cv.put( "name", name ); cv.put( "day", "" ); cv.put( "comment", "" ); try { myDB.insert( CALIB_TABLE, null, cv ); } catch ( SQLiteDiskIOException e ) { handleDiskIOError( e ); } catch (SQLiteException e ) { logError( "set calib name" + name, e ); } } return id; } private long maxId( String table, long sid ) { long id = 1; // if ( myDB == null ) return 1L; Cursor cursor = myDB.query( table, new String[] { "max(id)" }, "surveyId=?", new String[] { Long.toString(sid) }, null, null, null ); if (cursor != null ) { if (cursor.moveToFirst() ) { id = 1 + cursor.getLong(0); } if (!cursor.isClosed()) cursor.close(); } return id; } public ArrayList< Device > getDevices( ) { ArrayList<Device> ret = new ArrayList<Device>(); // if ( myDB == null ) return ret; Cursor cursor = myDB.query( DEVICE_TABLE, new String[] { "address", "model", "head", "tail", "name", "nickname" }, null, null, null, null, null ); if (cursor != null ) { if ( cursor.moveToFirst() ) { do { ret.add( new Device( cursor.getString(0), cursor.getString(1), (int)cursor.getLong(2), (int)cursor.getLong(3), cursor.getString(4), cursor.getString(5) ) ); } while (cursor.moveToNext()); } if ( !cursor.isClosed()) cursor.close(); } return ret; } // get device by address or by nickname public Device getDevice( String addr ) { // if ( myDB == null ) return null; Device ret = getDeviceByAddress( addr ); if ( ret == null ) { ret = getDeviceByNickname( addr ); } return ret; } private Device getDeviceByNickname( String nickname ) { if ( myDB == null ) return null; Device ret = null; Cursor cursor = myDB.query( DEVICE_TABLE, new String[] { "address", "model", "head", "tail", "name", "nickname" }, "nickname=?", new String[] { nickname }, null, null, null ); if (cursor != null ) { if ( cursor.moveToFirst() ) { ret = new Device( cursor.getString(0), cursor.getString(1), (int)cursor.getLong(2), (int)cursor.getLong(3), cursor.getString(4), cursor.getString(5) ); } if (!cursor.isClosed()) cursor.close(); } return ret; } private Device getDeviceByAddress( String addr ) { if ( myDB == null ) return null; Device ret = null; Cursor cursor = myDB.query( DEVICE_TABLE, new String[] { "address", "model", "head", "tail", "name", "nickname" }, "address=?", new String[] { addr }, null, null, null ); if (cursor != null ) { if ( cursor.moveToFirst() ) { ret = new Device( cursor.getString(0), cursor.getString(1), (int)cursor.getLong(2), (int)cursor.getLong(3), cursor.getString(4), cursor.getString(5) ); } if (!cursor.isClosed()) cursor.close(); } return ret; } public int getDeviceTail( String address ) { int ret = 0; // if ( myDB == null ) return 0; Cursor cursor = myDB.query( DEVICE_TABLE, new String[] { "tail" }, "address=?", new String[] { address }, null, null, null ); if (cursor != null ) { if (cursor.moveToFirst() ) { ret = (int)( cursor.getLong(0) ); } if (!cursor.isClosed()) cursor.close(); } return ret; } public boolean getDeviceHeadTail( String address, int[] head_tail ) { boolean ret = false; // if ( myDB == null ) return false; Cursor cursor = myDB.query( DEVICE_TABLE, new String[] { "head", "tail" }, "address=?", new String[] { address }, null, null, null ); if (cursor != null ) { if (cursor.moveToFirst() ) { head_tail[0] = (int)( cursor.getLong(0) ); head_tail[1] = (int)( cursor.getLong(1) ); ret = true; } if (!cursor.isClosed()) cursor.close(); } return ret; } boolean insertDevice( String address, String model, String name ) { boolean ret = true; // if ( myDB == null ) return false; Cursor cursor = myDB.query( DEVICE_TABLE, new String[] { "model" }, "address=?", new String[] { address }, null, null, null ); if ( cursor != null ) { if (cursor.moveToFirst() ) { // TODO address already in the database: check model ret = false; } else { ContentValues cv = new ContentValues(); cv.put( "address", address ); cv.put( "model", model ); cv.put( "head", 0 ); cv.put( "tail", 0 ); cv.put( "name", name ); cv.put( "nickname", "" ); // FIXME empty nickname try { myDB.insert( DEVICE_TABLE, null, cv ); } catch ( SQLiteDiskIOException e ) { handleDiskIOError( e ); } catch (SQLiteException e ) { logError( "insert device", e ); } } if (!cursor.isClosed()) cursor.close(); } return ret; } private void insertDeviceHeadTail( String address, String model, int[] head_tail, String name ) { // if ( myDB == null ) return; ContentValues cv = new ContentValues(); cv.put( "address", address ); cv.put( "model", model ); cv.put( "head", head_tail[0] ); cv.put( "tail", head_tail[1] ); cv.put( "name", name ); cv.put( "nickname", "" ); // FIXME empty nickname try { myDB.insert( DEVICE_TABLE, null, cv ); } catch ( SQLiteDiskIOException e ) { handleDiskIOError( e ); } catch (SQLiteException e ) { logError( "insert device H-T", e ); } } public void updateDeviceModel( String address, String model ) { if ( updateDeviceModelStmt == null ) updateDeviceModelStmt = myDB.compileStatement( "UPDATE devices set model=? WHERE address=?" ); updateDeviceModelStmt.bindString( 1, model ); updateDeviceModelStmt.bindString( 2, address ); try { updateDeviceModelStmt.execute(); } catch ( SQLiteDiskIOException e ) { handleDiskIOError( e ); } catch (SQLiteException e ) { logError( "update device", e ); } } public void updateDeviceNickname( String address, String nickname ) { if ( updateDeviceNicknameStmt == null ) updateDeviceNicknameStmt = myDB.compileStatement( "UPDATE devices set nickname=? WHERE address=?" ); updateDeviceNicknameStmt.bindString( 1, nickname ); updateDeviceNicknameStmt.bindString( 2, address ); try { updateDeviceNicknameStmt.execute(); } catch ( SQLiteDiskIOException e ) { handleDiskIOError( e ); } catch (SQLiteException e ) { logError( "update device nickname", e ); } } public boolean updateDeviceHeadTail( String address, int[] head_tail ) { // if ( myDB == null ) return false; boolean ret = false; if ( updateDeviceHeadTailStmt == null ) updateDeviceHeadTailStmt = myDB.compileStatement( "UPDATE devices set head=?, tail=? WHERE address=?" ); Cursor cursor = myDB.query( DEVICE_TABLE, new String[] { "head" }, "address=?", new String[] { address }, null, null, null ); if (cursor != null ) { if (cursor.moveToFirst() ) { // Log.v(TopoDroidApp.TAG, "update Head Tail " + address + " " + head_tail[0] + " " + head_tail[1] ); long head = head_tail[0]; long tail = head_tail[1]; updateDeviceHeadTailStmt.bindLong( 1, head ); updateDeviceHeadTailStmt.bindLong( 2, tail ); updateDeviceHeadTailStmt.bindString( 3, address ); try { updateDeviceHeadTailStmt.execute(); } catch ( SQLiteDiskIOException e ) { handleDiskIOError( e ); } catch (SQLiteException e ) { logError( "update device H-T", e ); } ret = true; } else { // insertDeviceHeadTail( address, "DistoX", head_tail, name ); // FIXME name ? } if (!cursor.isClosed()) cursor.close(); } return ret; } public boolean hasCalibName( String name ) { return hasName( name, CALIB_TABLE ); } private boolean hasName( String name, String table ) { boolean ret = false; // if ( myDB == null ) return ret; Cursor cursor = myDB.query( table, new String[] { "id" }, "name=?", new String[] { name }, null, null, null ); if (cursor != null) { if (cursor.moveToFirst() ) { ret = true; } if (!cursor.isClosed()) cursor.close(); } return ret; } public boolean updateCalibInfo( long id, String date, String device, String comment ) { // TDLog.Log( TDLog.LOG_DB, "updateCalibInfo id " + id + " day " + date + " comm. " + comment ); if ( date == null ) return false; if ( updateCalibStmt == null ) updateCalibStmt = myDB.compileStatement( "UPDATE calibs SET day=?, device=?, comment=? WHERE id=?" ); String dev = (device != null)? device : ""; String cmt = (comment != null)? comment : ""; updateCalibStmt.bindString( 1, date ); updateCalibStmt.bindString( 2, dev ); updateCalibStmt.bindString( 3, cmt ); updateCalibStmt.bindLong( 4, id ); try { updateCalibStmt.execute(); } catch ( SQLiteDiskIOException e ) { handleDiskIOError( e ); } catch (SQLiteException e ) { logError( "update calib", e ); } return true; } public boolean updateCalibAlgo( long id, long algo ) { // TDLog.Log( TDLog.LOG_DB, "updateCalibAlgo id " + id + " algo " + algo ); if ( updateCalibAlgoStmt == null ) updateCalibAlgoStmt = myDB.compileStatement( "UPDATE calibs SET algo=? WHERE id=?" ); updateCalibAlgoStmt.bindLong( 1, algo ); updateCalibAlgoStmt.bindLong( 2, id ); try { updateCalibAlgoStmt.execute(); } catch ( SQLiteDiskIOException e ) { handleDiskIOError( e ); } catch (SQLiteException e ) { logError( "update calib algo", e ); } return true; } public boolean updateCalibCoeff( long id, String coeff ) { // TDLog.Log( TDLog.LOG_DB, "updateCalibCoeff id " + id + " coeff. " + coeff ); if ( coeff == null ) return false; if ( updateCalibCoeffStmt == null ) updateCalibCoeffStmt = myDB.compileStatement( "UPDATE calibs SET coeff=? WHERE id=?" ); updateCalibCoeffStmt.bindString( 1, coeff ); updateCalibCoeffStmt.bindLong( 2, id ); try { updateCalibCoeffStmt.execute(); } catch ( SQLiteDiskIOException e ) { handleDiskIOError( e ); } catch (SQLiteException e ) { logError( "update calib coeff", e ); } return true; } public boolean updateCalibError( long id, double error, double stddev, double max_error, int iterations ) { // TDLog.Log( TDLog.LOG_DB, "updateCalibCoeff id " + id + " coeff. " + coeff ); if ( updateCalibErrorStmt == null ) updateCalibErrorStmt = myDB.compileStatement( "UPDATE calibs SET error=?, stddev=?, max_error=?, iterations=? WHERE id=?" ); updateCalibErrorStmt.bindDouble( 1, error ); updateCalibErrorStmt.bindDouble( 2, stddev ); updateCalibErrorStmt.bindDouble( 3, max_error ); updateCalibErrorStmt.bindLong( 4, iterations ); updateCalibErrorStmt.bindLong( 5, id ); try { updateCalibErrorStmt.execute(); } catch ( SQLiteDiskIOException e ) { handleDiskIOError( e ); } catch (SQLiteException e ) { logError( "update calib error", e ); } return true; } public long setCalib( String calib ) { myNextCId = 0; // if ( myDB == null ) return 0L; long cid = setCalibName( calib ); Cursor cursor = myDB.query( GM_TABLE, new String[] { "max(id)" }, "calibId=?", new String[] { Long.toString(cid) }, null, null, null ); if (cursor.moveToFirst() ) { myNextCId = cursor.getLong(0); } if (cursor != null && !cursor.isClosed()) { cursor.close(); } return cid; } public String getCalibFromId( long cid ) { return getNameFromId( CALIB_TABLE, cid ); } // ---------------------------------------------------------------------- // SERIALIZATION of surveys TO FILE // the following tables are serialized (besides the survey recond) // public void dumpToFile( String filename, long sid ) // { // // TDLog.Log( TDLog.LOG_DB, "dumpToFile " + filename ); // if ( myDB == null ) return; // try { // TDPath.checkPath( filename ); // FileWriter fw = new FileWriter( filename ); // PrintWriter pw = new PrintWriter( fw ); // // Cursor cursor = myDB.query( TABLE, // // new String[] { "id", "shotId", "status", "title", "date", "comment", "type", "value" }, // // "surveyId=?", new String[] { Long.toString( sid ) }, // // null, null, null ); // // if (cursor.moveToFirst()) { // // do { // // pw.format(Locale.US, // // "INSERT into %s values( %d, %d, %d, %d, \"%s\", \"%s\", \"%s\", \"%s\", \"%s\" );\n", // // FIXED_TABLE, // // sid, // // cursor.getLong(0), // // cursor.getLong(1), // // cursor.getLong(2), // // cursor.getString(3), // // cursor.getString(4), // // cursor.getString(5), // // cursor.getString(6), // // cursor.getString(7) // // ); // // } while (cursor.moveToNext()); // // } // // if (cursor != null && !cursor.isClosed()) { // // cursor.close(); // // } // fw.flush(); // fw.close(); // } catch ( FileNotFoundException e ) { // // FIXME // } catch ( IOException e ) { // // FIXME // } // } /** load survey data from a sql file * @param filename name of the sql file */ // long loadFromFile( String filename, int db_version ) // { // long sid = -1; // long id, status, shotid; // String station, title, date, name, comment; // String line; // try { // FileReader fr = new FileReader( filename ); // BufferedReader br = new BufferedReader( fr ); // // first line is survey // line = br.readLine(); // // TDLog.Log( TDLog.LOG_DB, "loadFromFile: " + line ); // String[] vals = line.split(" ", 4); // // if ( vals.length != 4 ) { TODO } // FIXME // String table = vals[2]; // String v = vals[3]; // pos = v.indexOf( '(' ) + 1; // len = v.lastIndexOf( ')' ); // skipSpaces( v ); // // ... // fr.close(); // } catch ( FileNotFoundException e ) { // } catch ( IOException e ) { // } // return sid; // } // ---------------------------------------------------------------------- // DATABASE TABLES private static class DistoXOpenHelper extends SQLiteOpenHelper { private static final String create_table = "CREATE TABLE IF NOT EXISTS "; DistoXOpenHelper(Context context, String database_name ) { super(context, database_name, null, DATABASE_VERSION); // Log.v("DistoX", "DB NAME " + database_name ); // TDLog.Log( TDLog.LOG_DB, "createTables ... " + database_name + " version " + DATABASE_VERSION ); } @Override public void onCreate(SQLiteDatabase db) { createTables( db ); // TDLog.Log( TDLog.LOG_DB, "DistoXOpenHelper onCreate done db " + db ); } private void createTables( SQLiteDatabase db ) { db.setLockingEnabled( false ); db.beginTransaction(); try { db.execSQL( create_table + CONFIG_TABLE + " ( key TEXT NOT NULL," + " value TEXT )" ); // db.execSQL( "insert into " + CONFIG_TABLE + " values ( \"sketch\", \"on\" )" ); db.execSQL( create_table + CALIB_TABLE + " ( id INTEGER, " // PRIMARY KEY AUTOINCREMENT, " + " name TEXT, " + " day TEXT, " + " device TEXT, " + " comment TEXT, " + " error REAL default 0, " + " max_error REAL default 0, " + " iterations INTEGER default 0, " + " coeff BLOB, " + " algo INTEGER default 0, " + " stddev REAL default 0 " + ")" ); db.execSQL( create_table + GM_TABLE + " ( calibId INTEGER, " + " id INTEGER, " // PRIMARY KEY AUTOINCREMENT, " + " gx INTEGER, " + " gy INTEGER, " + " gz INTEGER, " + " mx INTEGER, " + " my INTEGER, " + " mz INTEGER, " + " grp INTEGER, " + " error REAL default 0, " + " status INTEGER default 0" // + " calibId REFERENCES " + CALIB_TABLE + "(id)" // + " ON DELETE CASCADE " + ")" ); db.execSQL( create_table + DEVICE_TABLE + " ( address TEXT, " + " model TEXT, " + " head INTEGER, " + " tail INTEGER, " + " name TEXT, " + " nickname TEXT " + ")" ); db.setTransactionSuccessful(); } catch ( SQLException e ) { TDLog.Error( "createTables exception " + e.toString() ); } finally { db.endTransaction(); db.setLockingEnabled( true ); } } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { // FIXME this is called at each start when the database file exists TDLog.Log( TDLog.LOG_DB, "onUpgrade old " + oldVersion + " new " + newVersion ); switch ( oldVersion ) { case 16: db.execSQL( "ALTER TABLE calibs ADD COLUMN coeff BLOB" ); case 17: db.execSQL( "ALTER TABLE calibs ADD COLUMN error REAL default 0" ); db.execSQL( "ALTER TABLE calibs ADD COLUMN max_error REAL default 0" ); db.execSQL( "ALTER TABLE calibs ADD COLUMN iterations INTEGER default 0" ); case 18: db.execSQL( "ALTER TABLE calibs ADD COLUMN algo INTEGER default 1" ); case 23: db.execSQL( "ALTER TABLE devices ADD COLUMN nickname TEXT default \"\"" ); case 24: db.execSQL( "ALTER TABLE calibs ADD COLUMN stddev REAL default 0" ); case 25: case 26: /* current version */ default: break; } } } }