2015-05-30 17:28:03 +02:00
package nodomain.freeyourgadget.gadgetbridge.database ;
import android.content.ContentValues ;
import android.content.Context ;
import android.database.Cursor ;
import android.database.sqlite.SQLiteDatabase ;
import android.database.sqlite.SQLiteOpenHelper ;
2015-10-23 15:11:21 +02:00
import android.database.sqlite.SQLiteStatement ;
2015-07-10 00:31:45 +02:00
import android.widget.Toast ;
import org.slf4j.Logger ;
import org.slf4j.LoggerFactory ;
2015-05-30 17:28:03 +02:00
import java.util.ArrayList ;
2015-08-03 01:17:02 +02:00
import nodomain.freeyourgadget.gadgetbridge.GBApplication ;
2015-07-10 00:31:45 +02:00
import nodomain.freeyourgadget.gadgetbridge.database.schema.ActivityDBCreationScript ;
2015-08-03 23:09:49 +02:00
import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider ;
2015-09-24 14:45:21 +02:00
import nodomain.freeyourgadget.gadgetbridge.impl.GBActivitySample ;
import nodomain.freeyourgadget.gadgetbridge.model.ActivityKind ;
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample ;
import nodomain.freeyourgadget.gadgetbridge.util.GB ;
2015-05-30 17:28:03 +02:00
2015-07-13 21:54:46 +02:00
import static nodomain.freeyourgadget.gadgetbridge.database.DBConstants.DATABASE_NAME ;
2016-02-29 20:54:39 +01:00
import static nodomain.freeyourgadget.gadgetbridge.database.DBConstants.KEY_CUSTOM_SHORT ;
2015-07-13 21:54:46 +02:00
import static nodomain.freeyourgadget.gadgetbridge.database.DBConstants.KEY_INTENSITY ;
import static nodomain.freeyourgadget.gadgetbridge.database.DBConstants.KEY_PROVIDER ;
import static nodomain.freeyourgadget.gadgetbridge.database.DBConstants.KEY_STEPS ;
import static nodomain.freeyourgadget.gadgetbridge.database.DBConstants.KEY_TIMESTAMP ;
import static nodomain.freeyourgadget.gadgetbridge.database.DBConstants.KEY_TYPE ;
import static nodomain.freeyourgadget.gadgetbridge.database.DBConstants.TABLE_GBACTIVITYSAMPLES ;
2015-05-30 17:28:03 +02:00
2016-02-29 20:54:39 +01:00
public class ActivityDatabaseHandler extends SQLiteOpenHelper implements DBHandler {
2015-05-30 17:28:03 +02:00
2015-07-10 00:31:45 +02:00
private static final Logger LOG = LoggerFactory . getLogger ( ActivityDatabaseHandler . class ) ;
2015-05-30 17:28:03 +02:00
2016-03-07 00:36:39 +01:00
private static final int DATABASE_VERSION = 7 ;
2015-05-30 17:28:03 +02:00
public ActivityDatabaseHandler ( Context context ) {
super ( context , DATABASE_NAME , null , DATABASE_VERSION ) ;
}
@Override
public void onCreate ( SQLiteDatabase db ) {
2015-07-10 00:31:45 +02:00
try {
ActivityDBCreationScript script = new ActivityDBCreationScript ( ) ;
script . createSchema ( db ) ;
} catch ( RuntimeException ex ) {
2015-07-11 21:49:51 +02:00
GB . toast ( " Error creating database. " , Toast . LENGTH_SHORT , GB . ERROR , ex ) ;
2015-07-10 00:31:45 +02:00
}
2015-05-30 17:28:03 +02:00
}
2015-07-10 00:31:45 +02:00
@Override
public void onUpgrade ( SQLiteDatabase db , int oldVersion , int newVersion ) {
2016-03-04 23:37:42 +01:00
LOG . info ( " ActivityDatabase: schema upgrade requested from " + oldVersion + " to " + newVersion ) ;
2015-07-10 00:31:45 +02:00
try {
for ( int i = oldVersion + 1 ; i < = newVersion ; i + + ) {
DBUpdateScript updater = getUpdateScript ( db , i ) ;
if ( updater ! = null ) {
LOG . info ( " upgrading activity database to version " + i ) ;
updater . upgradeSchema ( db ) ;
}
}
LOG . info ( " activity database is now at version " + newVersion ) ;
} catch ( RuntimeException ex ) {
2015-07-11 21:49:51 +02:00
GB . toast ( " Error upgrading database. " , Toast . LENGTH_SHORT , GB . ERROR , ex ) ;
2015-07-10 00:31:45 +02:00
throw ex ; // reject upgrade
2015-06-06 00:10:38 +02:00
}
}
2015-05-30 17:28:03 +02:00
@Override
2015-07-10 00:31:45 +02:00
public void onDowngrade ( SQLiteDatabase db , int oldVersion , int newVersion ) {
2016-03-04 23:37:42 +01:00
LOG . info ( " ActivityDatabase: schema downgrade requested from " + oldVersion + " to " + newVersion ) ;
2015-07-10 00:31:45 +02:00
try {
for ( int i = oldVersion ; i > = newVersion ; i - - ) {
DBUpdateScript updater = getUpdateScript ( db , i ) ;
if ( updater ! = null ) {
LOG . info ( " downgrading activity database to version " + ( i - 1 ) ) ;
updater . downgradeSchema ( db ) ;
}
}
LOG . info ( " activity database is now at version " + newVersion ) ;
} catch ( RuntimeException ex ) {
2015-07-11 21:49:51 +02:00
GB . toast ( " Error downgrading database. " , Toast . LENGTH_SHORT , GB . ERROR , ex ) ;
2015-07-10 00:31:45 +02:00
throw ex ; // reject downgrade
2015-06-04 21:37:48 +02:00
}
2015-05-30 17:28:03 +02:00
}
2015-07-10 00:31:45 +02:00
private DBUpdateScript getUpdateScript ( SQLiteDatabase db , int version ) {
try {
Class < ? > updateClass = getClass ( ) . getClassLoader ( ) . loadClass ( getClass ( ) . getPackage ( ) . getName ( ) + " .schema.ActivityDBUpdate_ " + version ) ;
return ( DBUpdateScript ) updateClass . newInstance ( ) ;
} catch ( ClassNotFoundException e ) {
return null ;
} catch ( InstantiationException | IllegalAccessException e ) {
throw new RuntimeException ( " Error instantiating DBUpdate class for version " + version , e ) ;
}
}
2015-05-30 17:28:03 +02:00
2015-07-27 23:49:53 +02:00
public void addGBActivitySample ( ActivitySample sample ) {
2015-06-04 23:45:46 +02:00
try ( SQLiteDatabase db = this . getWritableDatabase ( ) ) {
ContentValues values = new ContentValues ( ) ;
2015-07-27 23:49:53 +02:00
values . put ( KEY_TIMESTAMP , sample . getTimestamp ( ) ) ;
values . put ( KEY_PROVIDER , sample . getProvider ( ) . getID ( ) ) ;
values . put ( KEY_INTENSITY , sample . getRawIntensity ( ) ) ;
values . put ( KEY_STEPS , sample . getSteps ( ) ) ;
2016-02-29 20:54:39 +01:00
values . put ( KEY_CUSTOM_SHORT , sample . getCustomValue ( ) ) ;
2015-07-27 23:49:53 +02:00
values . put ( KEY_TYPE , sample . getRawKind ( ) ) ;
2015-06-04 23:45:46 +02:00
db . insert ( TABLE_GBACTIVITYSAMPLES , null , values ) ;
}
2015-05-30 17:28:03 +02:00
}
2015-07-27 23:49:53 +02:00
/ * *
* Adds the a new sample to the database
2015-07-28 17:30:20 +02:00
*
2016-02-29 20:54:39 +01:00
* @param timestamp the timestamp of the same , second - based !
* @param provider the SampleProvider ID
* @param intensity the sample ' s raw intensity value
* @param steps the sample ' s steps value
* @param kind the raw activity kind of the sample
* @param customShortValue
2015-07-27 23:49:53 +02:00
* /
2015-08-15 00:23:13 +02:00
@Override
2016-02-29 20:54:39 +01:00
public void addGBActivitySample ( int timestamp , int provider , int intensity , int steps , int kind , int customShortValue ) {
2015-09-01 22:53:47 +02:00
if ( intensity < 0 ) {
LOG . error ( " negative intensity received, ignoring " ) ;
intensity = 0 ;
}
if ( steps < 0 ) {
LOG . error ( " negative steps received, ignoring " ) ;
steps = 0 ;
}
2016-02-26 23:45:17 +01:00
if ( customShortValue < 0 ) {
LOG . error ( " negative short value received, ignoring " ) ;
customShortValue = 0 ;
}
2015-06-04 23:45:46 +02:00
try ( SQLiteDatabase db = this . getWritableDatabase ( ) ) {
ContentValues values = new ContentValues ( ) ;
values . put ( KEY_TIMESTAMP , timestamp ) ;
values . put ( KEY_PROVIDER , provider ) ;
values . put ( KEY_INTENSITY , intensity ) ;
values . put ( KEY_STEPS , steps ) ;
2015-07-27 23:49:53 +02:00
values . put ( KEY_TYPE , kind ) ;
2016-02-26 23:45:17 +01:00
values . put ( KEY_CUSTOM_SHORT , customShortValue ) ;
2015-06-04 23:45:46 +02:00
db . insert ( TABLE_GBACTIVITYSAMPLES , null , values ) ;
}
2015-05-30 17:28:03 +02:00
}
2015-10-23 15:11:21 +02:00
@Override
2015-10-23 16:55:23 +02:00
public void addGBActivitySamples ( ActivitySample [ ] activitySamples ) {
2015-10-23 15:11:21 +02:00
try ( SQLiteDatabase db = this . getWritableDatabase ( ) ) {
String sql = " INSERT INTO " + TABLE_GBACTIVITYSAMPLES + " ( " + KEY_TIMESTAMP + " , " +
2016-02-26 23:45:17 +01:00
KEY_PROVIDER + " , " + KEY_INTENSITY + " , " + KEY_STEPS + " , " + KEY_TYPE + " , " + KEY_CUSTOM_SHORT + " ) " +
" VALUES (?,?,?,?,?,?); " ;
2015-10-23 15:11:21 +02:00
SQLiteStatement statement = db . compileStatement ( sql ) ;
db . beginTransaction ( ) ;
2015-10-23 16:55:23 +02:00
for ( ActivitySample activitySample : activitySamples ) {
2015-10-23 15:11:21 +02:00
statement . clearBindings ( ) ;
statement . bindLong ( 1 , activitySample . getTimestamp ( ) ) ;
statement . bindLong ( 2 , activitySample . getProvider ( ) . getID ( ) ) ;
statement . bindLong ( 3 , activitySample . getRawIntensity ( ) ) ;
statement . bindLong ( 4 , activitySample . getSteps ( ) ) ;
statement . bindLong ( 5 , activitySample . getRawKind ( ) ) ;
2016-02-29 20:54:39 +01:00
statement . bindLong ( 6 , activitySample . getCustomValue ( ) ) ;
2015-10-23 15:11:21 +02:00
statement . execute ( ) ;
}
db . setTransactionSuccessful ( ) ;
db . endTransaction ( ) ;
}
}
2015-07-27 23:49:53 +02:00
public ArrayList < ActivitySample > getSleepSamples ( int timestamp_from , int timestamp_to , SampleProvider provider ) {
2015-07-14 00:29:32 +02:00
return getGBActivitySamples ( timestamp_from , timestamp_to , ActivityKind . TYPE_SLEEP , provider ) ;
2015-07-12 23:42:23 +02:00
}
2015-07-27 23:49:53 +02:00
public ArrayList < ActivitySample > getActivitySamples ( int timestamp_from , int timestamp_to , SampleProvider provider ) {
2015-07-14 00:29:32 +02:00
return getGBActivitySamples ( timestamp_from , timestamp_to , ActivityKind . TYPE_ACTIVITY , provider ) ;
2015-07-12 23:42:23 +02:00
}
2015-08-03 01:17:02 +02:00
@Override
public SQLiteOpenHelper getHelper ( ) {
return this ;
}
@Override
public void release ( ) {
GBApplication . releaseDB ( ) ;
}
2015-07-27 23:49:53 +02:00
public ArrayList < ActivitySample > getAllActivitySamples ( int timestamp_from , int timestamp_to , SampleProvider provider ) {
2015-07-14 00:29:32 +02:00
return getGBActivitySamples ( timestamp_from , timestamp_to , ActivityKind . TYPE_ALL , provider ) ;
2015-07-12 23:42:23 +02:00
}
/ * *
* Returns all available activity samples from between the two timestamps ( inclusive ) , of the given
* provided and type ( s ) .
2015-07-25 21:52:52 +02:00
*
2015-07-12 23:42:23 +02:00
* @param timestamp_from
* @param timestamp_to
2015-07-25 21:52:52 +02:00
* @param activityTypes ORed combination of # TYPE_DEEP_SLEEP , # TYPE_LIGHT_SLEEP , # TYPE_ACTIVITY
2015-07-28 17:30:20 +02:00
* @param provider the producer of the samples to be sought
2015-07-12 23:42:23 +02:00
* @return
* /
2015-07-27 23:49:53 +02:00
private ArrayList < ActivitySample > getGBActivitySamples ( int timestamp_from , int timestamp_to , int activityTypes , SampleProvider provider ) {
2015-09-01 22:43:31 +02:00
if ( timestamp_to < 0 ) {
throw new IllegalArgumentException ( " negative timestamp_to " ) ;
}
if ( timestamp_from < 0 ) {
throw new IllegalArgumentException ( " negative timestamp_from " ) ;
2015-05-30 17:28:03 +02:00
}
2015-11-23 22:46:12 +01:00
ArrayList < ActivitySample > samples = new ArrayList < > ( ) ;
2015-07-27 23:49:53 +02:00
final String where = " (provider= " + provider . getID ( ) + " and timestamp>= " + timestamp_from + " and timestamp<= " + timestamp_to + getWhereClauseFor ( activityTypes , provider ) + " ) " ;
2015-09-24 14:45:21 +02:00
LOG . info ( " Activity query where: " + where ) ;
2015-07-12 21:50:09 +02:00
final String order = " timestamp " ;
2015-07-11 00:03:41 +02:00
try ( SQLiteDatabase db = this . getReadableDatabase ( ) ) {
2015-08-16 00:17:16 +02:00
try ( Cursor cursor = db . query ( TABLE_GBACTIVITYSAMPLES , null , where , null , null , null , order ) ) {
2015-09-09 20:52:04 +02:00
LOG . info ( " Activity query result: " + cursor . getCount ( ) + " samples " ) ;
2016-03-08 21:26:55 +01:00
int colTimeStamp = cursor . getColumnIndex ( KEY_TIMESTAMP ) ;
int colIntensity = cursor . getColumnIndex ( KEY_INTENSITY ) ;
int colSteps = cursor . getColumnIndex ( KEY_STEPS ) ;
int colType = cursor . getColumnIndex ( KEY_TYPE ) ;
int colCustomShort = cursor . getColumnIndex ( KEY_CUSTOM_SHORT ) ;
2016-03-08 23:30:31 +01:00
while ( cursor . moveToNext ( ) ) {
2016-03-08 21:26:55 +01:00
GBActivitySample sample = new GBActivitySample (
provider ,
cursor . getInt ( colTimeStamp ) ,
cursor . getInt ( colIntensity ) ,
cursor . getInt ( colSteps ) ,
cursor . getInt ( colType ) ,
cursor . getInt ( colCustomShort ) ) ;
samples . add ( sample ) ;
2015-08-16 00:17:16 +02:00
}
2015-06-04 23:45:46 +02:00
}
2015-05-30 17:28:03 +02:00
}
2015-07-27 23:49:53 +02:00
return samples ;
2015-05-30 17:28:03 +02:00
}
2015-07-13 21:54:46 +02:00
2015-07-27 23:49:53 +02:00
private String getWhereClauseFor ( int activityTypes , SampleProvider provider ) {
2015-07-14 00:29:32 +02:00
if ( activityTypes = = ActivityKind . TYPE_ALL ) {
2015-07-13 21:54:46 +02:00
return " " ; // no further restriction
}
StringBuilder builder = new StringBuilder ( " and ( " ) ;
2016-02-29 20:54:39 +01:00
int [ ] dbActivityTypes = ActivityKind . mapToDBActivityTypes ( activityTypes , provider ) ;
2015-07-13 21:54:46 +02:00
for ( int i = 0 ; i < dbActivityTypes . length ; i + + ) {
builder . append ( " type= " ) . append ( dbActivityTypes [ i ] ) ;
if ( i + 1 < dbActivityTypes . length ) {
builder . append ( " or " ) ;
}
}
builder . append ( ')' ) ;
return builder . toString ( ) ;
}
2016-02-09 17:52:21 +01:00
@Override
2016-02-29 20:54:39 +01:00
public void changeStoredSamplesType ( int timestampFrom , int timestampTo , int kind , SampleProvider provider ) {
2016-02-09 17:52:21 +01:00
try ( SQLiteDatabase db = this . getReadableDatabase ( ) ) {
2016-02-11 19:14:40 +01:00
String sql = " UPDATE " + TABLE_GBACTIVITYSAMPLES + " SET " + KEY_TYPE + " = ? WHERE "
2016-02-09 17:52:21 +01:00
+ KEY_PROVIDER + " = ? AND "
2016-02-11 19:14:40 +01:00
+ KEY_TIMESTAMP + " >= ? AND " + KEY_TIMESTAMP + " < ? ; " ; //do not use BETWEEN because the range is inclusive in that case!
2016-02-09 17:52:21 +01:00
SQLiteStatement statement = db . compileStatement ( sql ) ;
statement . bindLong ( 1 , kind ) ;
statement . bindLong ( 2 , provider . getID ( ) ) ;
statement . bindLong ( 3 , timestampFrom ) ;
statement . bindLong ( 4 , timestampTo ) ;
statement . execute ( ) ;
}
}
2016-02-11 19:14:40 +01:00
@Override
public int fetchLatestTimestamp ( SampleProvider provider ) {
try ( SQLiteDatabase db = this . getReadableDatabase ( ) ) {
try ( Cursor cursor = db . query ( TABLE_GBACTIVITYSAMPLES , new String [ ] { KEY_TIMESTAMP } , KEY_PROVIDER + " = " + String . valueOf ( provider . getID ( ) ) , null , null , null , KEY_TIMESTAMP + " DESC " , " 1 " ) ) {
if ( cursor . moveToFirst ( ) ) {
return cursor . getInt ( 0 ) ;
}
}
}
return - 1 ;
}
2015-06-12 21:26:11 +02:00
}