Migration work

master
cpfeiffer 2016-06-16 21:54:53 +02:00
parent 71d99384c1
commit 687beee501
18 changed files with 184 additions and 21 deletions

View File

@ -33,7 +33,7 @@ public class GBDaoGenerator {
private static final String VALID_BY_DATE = MODEL_PACKAGE + ".ValidByDate";
public static void main(String[] args) throws Exception {
Schema schema = new Schema(7, MAIN_PACKAGE + ".entities");
Schema schema = new Schema(10, MAIN_PACKAGE + ".entities");
addActivityDescription(schema);

View File

@ -32,10 +32,16 @@ public class LockHandler implements DBHandler {
}
this.daoMaster = daoMaster;
this.helper = helper;
session = daoMaster.newSession();
if (session == null) {
throw new RuntimeException("Unable to create database session");
}
if (helper.importOldDbIfNecessary(daoMaster, this)) {
session.clear();
session = daoMaster.newSession();
}
}
private boolean isValid() {

View File

@ -294,7 +294,7 @@ public abstract class AbstractChartFragment extends AbstractGBFragment {
return akActivity.color;
}
protected SampleProvider<AbstractActivitySample> getProvider(DBHandler db, GBDevice device) {
protected SampleProvider<? extends AbstractActivitySample> getProvider(DBHandler db, GBDevice device) {
DeviceCoordinator coordinator = DeviceHelper.getInstance().getCoordinator(device);
return coordinator.getSampleProvider(db);
}
@ -316,8 +316,8 @@ public abstract class AbstractChartFragment extends AbstractGBFragment {
return (tsTo) - (24 * 60 * 60); // -24 hours
}
protected List<? extends ActivitySample> getActivitySamples(DBHandler db, GBDevice device, int tsFrom, int tsTo) {
SampleProvider<AbstractActivitySample> provider = getProvider(db, device);
protected List<? extends AbstractActivitySample> getActivitySamples(DBHandler db, GBDevice device, int tsFrom, int tsTo) {
SampleProvider<? extends AbstractActivitySample> provider = getProvider(db, device);
return provider.getActivitySamples(tsFrom, tsTo);
}

View File

@ -39,6 +39,7 @@ public class ActivityDatabaseHandler extends SQLiteOpenHelper implements DBHandl
private static final Logger LOG = LoggerFactory.getLogger(ActivityDatabaseHandler.class);
private static final int DATABASE_VERSION = 7;
private static final String UPDATER_CLASS_NAME_PREFIX = "ActivityDBUpdate_";
public ActivityDatabaseHandler(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
@ -56,12 +57,12 @@ public class ActivityDatabaseHandler extends SQLiteOpenHelper implements DBHandl
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
new SchemaMigration().onUpgrade(db, oldVersion, newVersion);
new SchemaMigration(UPDATER_CLASS_NAME_PREFIX).onUpgrade(db, oldVersion, newVersion);
}
@Override
public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
new SchemaMigration().onDowngrade(db, oldVersion, newVersion);
new SchemaMigration(UPDATER_CLASS_NAME_PREFIX).onDowngrade(db, oldVersion, newVersion);
}
@Override
@ -176,6 +177,10 @@ public class ActivityDatabaseHandler extends SQLiteOpenHelper implements DBHandl
return getGBActivitySamples(timestamp_from, timestamp_to, ActivityKind.TYPE_ALL, provider);
}
public ArrayList<ActivitySample> getAllActivitySamples() {
return getActivitySamples(null, "timestamp", null);
}
/**
* Returns all available activity samples from between the two timestamps (inclusive), of the given
* provided and type(s).
@ -193,10 +198,17 @@ public class ActivityDatabaseHandler extends SQLiteOpenHelper implements DBHandl
if (timestamp_from < 0) {
throw new IllegalArgumentException("negative timestamp_from");
}
ArrayList<ActivitySample> samples = new ArrayList<>();
final String where = "(provider=" + provider.getID() + " and timestamp>=" + timestamp_from + " and timestamp<=" + timestamp_to + getWhereClauseFor(activityTypes, provider) + ")";
LOG.info("Activity query where: " + where);
final String order = "timestamp";
ArrayList<ActivitySample> samples = getActivitySamples(where, order, null);
return samples;
}
private ArrayList<ActivitySample> getActivitySamples(String where, String order, SampleProvider provider) {
ArrayList<ActivitySample> samples = new ArrayList<>();
try (SQLiteDatabase db = this.getReadableDatabase()) {
try (Cursor cursor = db.query(TABLE_GBACTIVITYSAMPLES, null, where, null, null, null, order)) {
LOG.info("Activity query result: " + cursor.getCount() + " samples");
@ -217,7 +229,6 @@ public class ActivityDatabaseHandler extends SQLiteOpenHelper implements DBHandl
}
}
}
return samples;
}
@ -283,6 +294,6 @@ public class ActivityDatabaseHandler extends SQLiteOpenHelper implements DBHandl
@Override
public DaoSession getDaoSession() {
return null;
throw new UnsupportedOperationException();
}
}

View File

@ -1,5 +1,8 @@
package nodomain.freeyourgadget.gadgetbridge.database;
/**
* TODO: Legacy, can be removed once migration support for old ActivityDatabase is removed
*/
public class DBConstants {
public static final String DATABASE_NAME = "ActivityDatabase";

View File

@ -1,23 +1,118 @@
package nodomain.freeyourgadget.gadgetbridge.database;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import java.util.ArrayList;
import java.util.List;
import nodomain.freeyourgadget.gadgetbridge.LockHandler;
import nodomain.freeyourgadget.gadgetbridge.database.schema.SchemaMigration;
import nodomain.freeyourgadget.gadgetbridge.devices.AbstractSampleProvider;
import nodomain.freeyourgadget.gadgetbridge.devices.DeviceCoordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider;
import nodomain.freeyourgadget.gadgetbridge.entities.AbstractActivitySample;
import nodomain.freeyourgadget.gadgetbridge.entities.DaoMaster;
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
import nodomain.freeyourgadget.gadgetbridge.entities.User;
import nodomain.freeyourgadget.gadgetbridge.impl.GBActivitySample;
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample;
import nodomain.freeyourgadget.gadgetbridge.model.HeartRateSample;
import nodomain.freeyourgadget.gadgetbridge.util.DeviceHelper;
import static nodomain.freeyourgadget.gadgetbridge.database.DBConstants.KEY_CUSTOM_SHORT;
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;
public class DBOpenHelper extends DaoMaster.OpenHelper {
private final String updaterClassNamePrefix;
private final Context context;
public DBOpenHelper(Context context, String dbName, SQLiteDatabase.CursorFactory factory) {
super(context, dbName, factory);
updaterClassNamePrefix = dbName + "Update_";
this.context = context;
}
public boolean importOldDbIfNecessary(DaoMaster daoMaster, DBHandler targetDBHandler) {
DaoSession tempSession = daoMaster.newSession();
try {
if (isEmpty(tempSession)) {
importActivityDatabaseInto(tempSession, targetDBHandler);
return true;
}
} finally {
tempSession.clear();
}
return false;
}
private boolean isEmpty(DaoSession session) {
long totalSamplesCount = session.getMiBandActivitySampleDao().count();
totalSamplesCount += session.getPebbleActivitySampleDao().count();
return totalSamplesCount == 0;
}
private void importActivityDatabaseInto(DaoSession session, DBHandler targetDBHandler) {
ActivityDatabaseHandler handler = new ActivityDatabaseHandler(getContext());
try (SQLiteDatabase db = handler.getReadableDatabase()) {
User user = DBHelper.getUser(session);
for (DeviceCoordinator coordinator : DeviceHelper.getInstance().getAllCoordinators()) {
AbstractSampleProvider<? extends AbstractActivitySample> sampleProvider = (AbstractSampleProvider<? extends AbstractActivitySample>) coordinator.getSampleProvider(targetDBHandler);
importActivitySamples(db, session, sampleProvider, user);
}
}
}
private <T extends AbstractActivitySample> void importActivitySamples(SQLiteDatabase fromDb, DaoSession targetSession, AbstractSampleProvider<T> sampleProvider, User user) {
String order = "timestamp";
final String where = "provider=" + sampleProvider.getID();
try (Cursor cursor = fromDb.query(TABLE_GBACTIVITYSAMPLES, null, where, null, null, null, order)) {
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);
Long userId = user.getId();
List<T> newSamples = new ArrayList<>(cursor.getCount());
while (cursor.moveToNext()) {
T newSample = sampleProvider.createActivitySample();
newSample.setUserId(userId);
newSample.setDeviceId(deviceId);
newSample.setTimestamp(cursor.getInt(colTimeStamp));
newSample.setRawKind(cursor.getInt(colType));
newSample.setProvider(sampleProvider);
newSample.setRawIntensity(cursor.getInt(colIntensity));
newSample.setSteps(cursor.getInt(colSteps));
int hrValue = cursor.getInt(colCustomShort);
if (newSample instanceof HeartRateSample) {
((HeartRateSample)newSample).setHeartRate(hrValue);
}
newSamples.add(newSample);
}
sampleProvider.getSampleDao().insertInTx(newSamples, true);
}
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
new SchemaMigration().onUpgrade(db, oldVersion, newVersion);
new SchemaMigration(updaterClassNamePrefix).onUpgrade(db, oldVersion, newVersion);
}
@Override
public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
new SchemaMigration().onDowngrade(db, oldVersion, newVersion);
new SchemaMigration(updaterClassNamePrefix).onDowngrade(db, oldVersion, newVersion);
}
public Context getContext() {
return context;
}
}

View File

@ -11,6 +11,11 @@ import nodomain.freeyourgadget.gadgetbridge.util.GB;
public class SchemaMigration {
private static final Logger LOG = LoggerFactory.getLogger(SchemaMigration.class);
private final String classNamePrefix;
public SchemaMigration(String updaterClassNamePrefix) {
classNamePrefix = updaterClassNamePrefix;
}
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
LOG.info("ActivityDatabase: schema upgrade requested from " + oldVersion + " to " + newVersion);
@ -48,7 +53,7 @@ public class SchemaMigration {
private DBUpdateScript getUpdateScript(SQLiteDatabase db, int version) {
try {
Class<?> updateClass = getClass().getClassLoader().loadClass(getClass().getPackage().getName() + ".schema.ActivityDBUpdate_" + version);
Class<?> updateClass = getClass().getClassLoader().loadClass(getClass().getPackage().getName() + ".schema." + classNamePrefix + version);
return (DBUpdateScript) updateClass.newInstance();
} catch (ClassNotFoundException e) {
return null;

View File

@ -127,7 +127,7 @@ public abstract class AbstractSampleProvider<T extends AbstractActivitySample> i
trailingConditions);
}
protected abstract AbstractDao<T,?> getSampleDao();
public abstract AbstractDao<T,?> getSampleDao();
protected abstract Property getRawKindSampleProperty();
protected abstract Property getTimestampSampleProperty();

View File

@ -8,6 +8,7 @@ import nodomain.freeyourgadget.gadgetbridge.database.DBHandler;
import nodomain.freeyourgadget.gadgetbridge.entities.AbstractActivitySample;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceCandidate;
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample;
import nodomain.freeyourgadget.gadgetbridge.model.DeviceType;
/**
@ -84,7 +85,7 @@ public interface DeviceCoordinator {
*
* @return
*/
SampleProvider<AbstractActivitySample> getSampleProvider(DBHandler db);
SampleProvider<? extends ActivitySample> getSampleProvider(DBHandler db);
/**
* Finds an install handler for the given uri that can install the given

View File

@ -37,4 +37,6 @@ public interface SampleProvider<T extends AbstractActivitySample> {
void addGBActivitySample(T activitySample);
void addGBActivitySamples(T[] activitySamples);
T createActivitySample();
}

View File

@ -69,6 +69,11 @@ public class UnknownDeviceCoordinator extends AbstractDeviceCoordinator {
public void addGBActivitySamples(AbstractActivitySample[] activitySamples) {
}
@Override
public AbstractActivitySample createActivitySample() {
return null;
}
@Override
public int getID() {
return PROVIDER_UNKNOWN;
@ -105,7 +110,7 @@ public class UnknownDeviceCoordinator extends AbstractDeviceCoordinator {
}
@Override
public SampleProvider getSampleProvider(DBHandler db) {
public SampleProvider<?> getSampleProvider(DBHandler db) {
return new UnknownSampleProvider();
}

View File

@ -14,8 +14,10 @@ import nodomain.freeyourgadget.gadgetbridge.database.DBHandler;
import nodomain.freeyourgadget.gadgetbridge.devices.AbstractDeviceCoordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.InstallHandler;
import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider;
import nodomain.freeyourgadget.gadgetbridge.entities.AbstractActivitySample;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceCandidate;
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample;
import nodomain.freeyourgadget.gadgetbridge.model.ActivityUser;
import nodomain.freeyourgadget.gadgetbridge.model.DeviceType;
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
@ -53,7 +55,7 @@ public class MiBandCoordinator extends AbstractDeviceCoordinator {
}
@Override
public SampleProvider getSampleProvider(DBHandler db) {
public SampleProvider<? extends AbstractActivitySample> getSampleProvider(DBHandler db) {
return new MiBandSampleProvider(db.getDaoSession());
}

View File

@ -79,7 +79,7 @@ public class MiBandSampleProvider extends AbstractSampleProvider<MiBandActivityS
}
@Override
protected AbstractDao<MiBandActivitySample, ?> getSampleDao() {
public AbstractDao<MiBandActivitySample, ?> getSampleDao() {
return getSession().getMiBandActivitySampleDao();
}
@ -92,4 +92,9 @@ public class MiBandSampleProvider extends AbstractSampleProvider<MiBandActivityS
protected Property getRawKindSampleProperty() {
return MiBandActivitySampleDao.Properties.RawKind;
}
@Override
public MiBandActivitySample createActivitySample() {
return new MiBandActivitySample();
}
}

View File

@ -13,7 +13,7 @@ public abstract class AbstractPebbleSampleProvider extends AbstractSampleProvide
}
@Override
protected AbstractDao<PebbleActivitySample, ?> getSampleDao() {
public AbstractDao<PebbleActivitySample, ?> getSampleDao() {
return getSession().getPebbleActivitySampleDao();
}
@ -26,4 +26,9 @@ public abstract class AbstractPebbleSampleProvider extends AbstractSampleProvide
protected Property getRawKindSampleProperty() {
return PebbleActivitySampleDao.Properties.RawKind;
}
@Override
public PebbleActivitySample createActivitySample() {
return new PebbleActivitySample();
}
}

View File

@ -2,6 +2,7 @@ package nodomain.freeyourgadget.gadgetbridge.devices.pebble;
import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider;
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
import nodomain.freeyourgadget.gadgetbridge.entities.PebbleActivitySample;
import nodomain.freeyourgadget.gadgetbridge.model.ActivityKind;
public class HealthSampleProvider extends AbstractPebbleSampleProvider {
@ -43,13 +44,11 @@ public class HealthSampleProvider extends AbstractPebbleSampleProvider {
}
}
@Override
public float normalizeIntensity(int rawIntensity) {
return rawIntensity / movementDivisor;
}
@Override
public int getID() {
return SampleProvider.PROVIDER_PEBBLE_HEALTH;

View File

@ -11,9 +11,12 @@ import nodomain.freeyourgadget.gadgetbridge.database.DBHandler;
import nodomain.freeyourgadget.gadgetbridge.devices.AbstractDeviceCoordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.InstallHandler;
import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider;
import nodomain.freeyourgadget.gadgetbridge.entities.AbstractActivitySample;
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
import nodomain.freeyourgadget.gadgetbridge.entities.PebbleActivitySample;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceCandidate;
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample;
import nodomain.freeyourgadget.gadgetbridge.model.DeviceType;
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
@ -46,7 +49,7 @@ public class PebbleCoordinator extends AbstractDeviceCoordinator {
}
@Override
public SampleProvider getSampleProvider(DBHandler db) {
public SampleProvider<? extends AbstractActivitySample> getSampleProvider(DBHandler db) {
Prefs prefs = GBApplication.getPrefs();
DaoSession session = db.getDaoSession();
int activityTracker = prefs.getInt("pebble_activitytracker", SampleProvider.PROVIDER_PEBBLE_HEALTH);

View File

@ -30,6 +30,18 @@ public abstract class AbstractActivitySample implements ActivitySample {
public abstract void setRawIntensity(int intensity);
public abstract void setSteps(int steps);
public abstract void setTimestamp(int timestamp);
public abstract void setUserId(Long userId);
public abstract Long getUserId();
public abstract void setDeviceId(Long userId);
public abstract Long getDeviceId();
@Override
public String toString() {
return getClass().getSimpleName() + "{" +
@ -37,6 +49,8 @@ public abstract class AbstractActivitySample implements ActivitySample {
", intensity=" + getIntensity() +
", steps=" + getSteps() +
", type=" + getKind() +
", userId=" + getUserId() +
", deviceId=" + getDeviceId() +
'}';
}
}

View File

@ -8,4 +8,11 @@ public interface HeartRateSample extends TimeStamped {
* @return the heart rate value in beats per minute, or null if none
*/
Integer getHeartRate();
/**
* Sets the heart rate value of this sample. Typically only used in
* generic db migration.
* @param value the value in bpm
*/
void setHeartRate(Integer value);
}