mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge
synced 2025-01-24 08:37:32 +01:00
WIP: more db work
This commit is contained in:
parent
ae548d0806
commit
61957d6cb0
@ -60,7 +60,7 @@ public class GBApplication extends Application {
|
|||||||
private static LimitedQueue mIDSenderLookup = new LimitedQueue(16);
|
private static LimitedQueue mIDSenderLookup = new LimitedQueue(16);
|
||||||
private static Prefs prefs;
|
private static Prefs prefs;
|
||||||
private static GBPrefs gbPrefs;
|
private static GBPrefs gbPrefs;
|
||||||
private static DBHandler lockHandler;
|
private static LockHandler lockHandler;
|
||||||
/**
|
/**
|
||||||
* Note: is null on Lollipop and Kitkat
|
* Note: is null on Lollipop and Kitkat
|
||||||
*/
|
*/
|
||||||
@ -156,7 +156,10 @@ public class GBApplication extends Application {
|
|||||||
DBOpenHelper helper = new DBOpenHelper(context, "test-db", null);
|
DBOpenHelper helper = new DBOpenHelper(context, "test-db", null);
|
||||||
SQLiteDatabase db = helper.getWritableDatabase();
|
SQLiteDatabase db = helper.getWritableDatabase();
|
||||||
DaoMaster daoMaster = new DaoMaster(db);
|
DaoMaster daoMaster = new DaoMaster(db);
|
||||||
lockHandler = new LockHandler(daoMaster, helper);
|
if (lockHandler == null) {
|
||||||
|
lockHandler = new LockHandler();
|
||||||
|
}
|
||||||
|
lockHandler.init(daoMaster, helper);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Context getContext() {
|
public static Context getContext() {
|
||||||
@ -179,6 +182,9 @@ public class GBApplication extends Application {
|
|||||||
* If acquiring was successful, callers must call #releaseDB when they
|
* If acquiring was successful, callers must call #releaseDB when they
|
||||||
* are done (from the same thread that acquired the lock!
|
* are done (from the same thread that acquired the lock!
|
||||||
*
|
*
|
||||||
|
* Callers must not hold a reference to the returned instance because it
|
||||||
|
* will be invalidated at some point.
|
||||||
|
*
|
||||||
* @return the DBHandler
|
* @return the DBHandler
|
||||||
* @throws GBException
|
* @throws GBException
|
||||||
* @see #releaseDB()
|
* @see #releaseDB()
|
||||||
|
@ -9,23 +9,48 @@ import nodomain.freeyourgadget.gadgetbridge.entities.DaoMaster;
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
|
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A dummy DBHandler that does nothing more than implementing the release() method.
|
* Provides lowlevel access to the database.
|
||||||
* It is solely used for locking concurrent access to the database session.
|
|
||||||
*/
|
*/
|
||||||
public class LockHandler implements DBHandler {
|
public class LockHandler implements DBHandler {
|
||||||
|
|
||||||
private final DaoMaster daoMaster;
|
private DaoMaster daoMaster = null;
|
||||||
private DaoSession session;
|
private DaoSession session = null;
|
||||||
private final SQLiteOpenHelper helper;
|
private SQLiteOpenHelper helper = null;
|
||||||
|
|
||||||
public LockHandler(DaoMaster daoMaster, DBOpenHelper helper) {
|
public LockHandler() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void init(DaoMaster daoMaster, DBOpenHelper helper) {
|
||||||
|
if (isValid()) {
|
||||||
|
throw new IllegalStateException("DB must be closed before initializing it again");
|
||||||
|
}
|
||||||
|
if (daoMaster == null) {
|
||||||
|
throw new IllegalArgumentException("daoMaster must not be null");
|
||||||
|
}
|
||||||
|
if (helper == null) {
|
||||||
|
throw new IllegalArgumentException("helper must not be null");
|
||||||
|
}
|
||||||
this.daoMaster = daoMaster;
|
this.daoMaster = daoMaster;
|
||||||
this.helper = helper;
|
this.helper = helper;
|
||||||
session = daoMaster.newSession();
|
session = daoMaster.newSession();
|
||||||
|
if (session == null) {
|
||||||
|
throw new RuntimeException("Unable to create database session");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isValid() {
|
||||||
|
return daoMaster != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ensureValid() {
|
||||||
|
if (!isValid()) {
|
||||||
|
throw new IllegalStateException("LockHandler is not in a valid state");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close() {
|
public void close() {
|
||||||
|
ensureValid();
|
||||||
GBApplication.releaseDB();
|
GBApplication.releaseDB();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,7 +59,7 @@ public class LockHandler implements DBHandler {
|
|||||||
if (session != null) {
|
if (session != null) {
|
||||||
throw new IllegalStateException("session must be null");
|
throw new IllegalStateException("session must be null");
|
||||||
}
|
}
|
||||||
// this will create completely new db instances. This handler will be dead
|
// this will create completely new db instances and in turn update this handler through #init()
|
||||||
GBApplication.setupDatabase(GBApplication.getContext());
|
GBApplication.setupDatabase(GBApplication.getContext());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -46,20 +71,25 @@ public class LockHandler implements DBHandler {
|
|||||||
session.clear();
|
session.clear();
|
||||||
session.getDatabase().close();
|
session.getDatabase().close();
|
||||||
session = null;
|
session = null;
|
||||||
|
helper = null;
|
||||||
|
daoMaster = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SQLiteOpenHelper getHelper() {
|
public SQLiteOpenHelper getHelper() {
|
||||||
|
ensureValid();
|
||||||
return helper;
|
return helper;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DaoSession getDaoSession() {
|
public DaoSession getDaoSession() {
|
||||||
|
ensureValid();
|
||||||
return session;
|
return session;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SQLiteDatabase getDatabase() {
|
public SQLiteDatabase getDatabase() {
|
||||||
|
ensureValid();
|
||||||
return daoMaster.getDatabase();
|
return daoMaster.getDatabase();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,20 +4,29 @@ import android.database.sqlite.SQLiteDatabase;
|
|||||||
import android.database.sqlite.SQLiteOpenHelper;
|
import android.database.sqlite.SQLiteOpenHelper;
|
||||||
|
|
||||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.entities.DaoMaster;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
|
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides lowlevel access to the database.
|
||||||
|
*/
|
||||||
public interface DBHandler extends AutoCloseable {
|
public interface DBHandler extends AutoCloseable {
|
||||||
/**
|
/**
|
||||||
* Closes the database.
|
* Closes the database.
|
||||||
*/
|
*/
|
||||||
void closeDb();
|
void closeDb();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens the database. Note that this is only possible after an explicit
|
||||||
|
* #closeDb(). Initially the db is implicitly open.
|
||||||
|
*/
|
||||||
void openDb();
|
void openDb();
|
||||||
|
|
||||||
SQLiteOpenHelper getHelper();
|
SQLiteOpenHelper getHelper();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Releases the DB handler. No access may be performed after calling this method.
|
* Releases the DB handler. No DB access will be possible before
|
||||||
* Same as calling {@link GBApplication#releaseDB()}
|
* #openDb() will be called.
|
||||||
*/
|
*/
|
||||||
void close() throws Exception;
|
void close() throws Exception;
|
||||||
|
|
||||||
|
@ -31,6 +31,13 @@ import nodomain.freeyourgadget.gadgetbridge.util.DateTimeUtils;
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.util.DeviceHelper;
|
import nodomain.freeyourgadget.gadgetbridge.util.DeviceHelper;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.FileUtils;
|
import nodomain.freeyourgadget.gadgetbridge.util.FileUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides utiliy access to some common entities, so you won't need to use
|
||||||
|
* their DAO classes.
|
||||||
|
*
|
||||||
|
* Maybe this code should actually be in the DAO classes themselves, but then
|
||||||
|
* these should be under revision control instead of 100% generated at build time.
|
||||||
|
*/
|
||||||
public class DBHelper {
|
public class DBHelper {
|
||||||
private final Context context;
|
private final Context context;
|
||||||
|
|
||||||
@ -134,9 +141,10 @@ public class DBHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static User getUser(DaoSession session) {
|
public static User getUser(DaoSession session) {
|
||||||
UserDao userDao = session.getUserDao();
|
|
||||||
List<User> users = userDao.loadAll();
|
|
||||||
ActivityUser prefsUser = new ActivityUser();
|
ActivityUser prefsUser = new ActivityUser();
|
||||||
|
UserDao userDao = session.getUserDao();
|
||||||
|
Query<User> query = userDao.queryBuilder().where(UserDao.Properties.Name.eq(prefsUser.getName())).build();
|
||||||
|
List<User> users = query.list();
|
||||||
User user;
|
User user;
|
||||||
if (users.isEmpty()) {
|
if (users.isEmpty()) {
|
||||||
user = createUser(prefsUser, session);
|
user = createUser(prefsUser, session);
|
||||||
@ -155,8 +163,6 @@ public class DBHelper {
|
|||||||
user.setGender(prefsUser.getGender());
|
user.setGender(prefsUser.getGender());
|
||||||
session.getUserDao().insert(user);
|
session.getUserDao().insert(user);
|
||||||
|
|
||||||
ensureUserAttributes(user, prefsUser, session);
|
|
||||||
|
|
||||||
return user;
|
return user;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -187,6 +193,7 @@ public class DBHelper {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: move this into db queries?
|
||||||
private static boolean isValidNow(ValidByDate element) {
|
private static boolean isValidNow(ValidByDate element) {
|
||||||
Calendar cal = DateTimeUtils.getCalendarUTC();
|
Calendar cal = DateTimeUtils.getCalendarUTC();
|
||||||
Date nowUTC = cal.getTime();
|
Date nowUTC = cal.getTime();
|
||||||
@ -221,15 +228,39 @@ public class DBHelper {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean isEqual(DeviceAttributes attr, GBDevice gbDevice) {
|
||||||
|
if (!isEqual(attr.getFirmwareVersion1(), gbDevice.getFirmwareVersion())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!isEqual(attr.getFirmwareVersion2(), gbDevice.getFirmwareVersion2())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isEqual(String s1, String s2) {
|
||||||
|
if (s1 == s2) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (s1 != null) {
|
||||||
|
return s1.equals(s2);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public static Device getDevice(GBDevice gbDevice, DaoSession session) {
|
public static Device getDevice(GBDevice gbDevice, DaoSession session) {
|
||||||
DeviceDao deviceDao = session.getDeviceDao();
|
DeviceDao deviceDao = session.getDeviceDao();
|
||||||
Query<Device> query = deviceDao.queryBuilder().where(DeviceDao.Properties.Identifier.eq(gbDevice.getAddress())).build();
|
Query<Device> query = deviceDao.queryBuilder().where(DeviceDao.Properties.Identifier.eq(gbDevice.getAddress())).build();
|
||||||
List<Device> devices = query.list();
|
List<Device> devices = query.list();
|
||||||
|
Device device;
|
||||||
if (devices.isEmpty()) {
|
if (devices.isEmpty()) {
|
||||||
Device device = createDevice(session, gbDevice);
|
device = createDevice(session, gbDevice);
|
||||||
return device;
|
} else {
|
||||||
|
device = devices.get(0);
|
||||||
}
|
}
|
||||||
return devices.get(0);
|
ensureDeviceAttributes(device, gbDevice, session);
|
||||||
|
|
||||||
|
return device;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Device createDevice(DaoSession session, GBDevice gbDevice) {
|
private static Device createDevice(DaoSession session, GBDevice gbDevice) {
|
||||||
@ -239,18 +270,36 @@ public class DBHelper {
|
|||||||
DeviceCoordinator coordinator = DeviceHelper.getInstance().getCoordinator(gbDevice);
|
DeviceCoordinator coordinator = DeviceHelper.getInstance().getCoordinator(gbDevice);
|
||||||
device.setManufacturer(coordinator.getManufacturer());
|
device.setManufacturer(coordinator.getManufacturer());
|
||||||
session.getDeviceDao().insert(device);
|
session.getDeviceDao().insert(device);
|
||||||
List<DeviceAttributes> deviceAttributes = device.getDeviceAttributesList();
|
|
||||||
|
|
||||||
|
return device;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ensureDeviceAttributes(Device device, GBDevice gbDevice, DaoSession session) {
|
||||||
|
List<DeviceAttributes> deviceAttributes = device.getDeviceAttributesList();
|
||||||
|
if (hasUpToDateDeviceAttributes(deviceAttributes, gbDevice)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
DeviceAttributes attributes = new DeviceAttributes();
|
DeviceAttributes attributes = new DeviceAttributes();
|
||||||
|
|
||||||
attributes.setDeviceId(device.getId());
|
attributes.setDeviceId(device.getId());
|
||||||
attributes.setValidFromUTC(DateTimeUtils.todayUTC());
|
attributes.setValidFromUTC(DateTimeUtils.todayUTC());
|
||||||
attributes.setFirmwareVersion1(gbDevice.getFirmwareVersion());
|
attributes.setFirmwareVersion1(gbDevice.getFirmwareVersion());
|
||||||
// TODO: firmware version2? generically or through DeviceCoordinator?
|
attributes.setFirmwareVersion2(gbDevice.getFirmwareVersion2());
|
||||||
DeviceAttributesDao attributesDao = session.getDeviceAttributesDao();
|
DeviceAttributesDao attributesDao = session.getDeviceAttributesDao();
|
||||||
attributesDao.insert(attributes);
|
attributesDao.insert(attributes);
|
||||||
|
|
||||||
deviceAttributes.add(attributes);
|
deviceAttributes.add(attributes);
|
||||||
|
}
|
||||||
|
|
||||||
return device;
|
private static boolean hasUpToDateDeviceAttributes(List<DeviceAttributes> deviceAttributes, GBDevice gbDevice) {
|
||||||
|
for (DeviceAttributes attr : deviceAttributes) {
|
||||||
|
if (!isValidNow(attr)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (isEqual(attr, gbDevice)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,11 @@ import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.entities.MiBandActivitySampleDao;
|
import nodomain.freeyourgadget.gadgetbridge.entities.MiBandActivitySampleDao;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.ActivityKind;
|
import nodomain.freeyourgadget.gadgetbridge.model.ActivityKind;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for all sample providers. A Sample provider is device specific and provides
|
||||||
|
* access to the device specific samples. There are both read and write operations.
|
||||||
|
* @param <T>
|
||||||
|
*/
|
||||||
public abstract class AbstractSampleProvider<T extends AbstractActivitySample> implements SampleProvider<T> {
|
public abstract class AbstractSampleProvider<T extends AbstractActivitySample> implements SampleProvider<T> {
|
||||||
private static final WhereCondition[] NO_CONDITIONS = new WhereCondition[0];
|
private static final WhereCondition[] NO_CONDITIONS = new WhereCondition[0];
|
||||||
private final DaoSession mSession;
|
private final DaoSession mSession;
|
||||||
@ -51,12 +56,12 @@ public abstract class AbstractSampleProvider<T extends AbstractActivitySample> i
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addGBActivitySample(T activitySample) {
|
public void addGBActivitySample(T activitySample) {
|
||||||
getSampleDao().insert(activitySample);
|
getSampleDao().insertOrReplace(activitySample);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addGBActivitySamples(T[] activitySamples) {
|
public void addGBActivitySamples(T[] activitySamples) {
|
||||||
getSampleDao().insertInTx(activitySamples);
|
getSampleDao().insertOrReplaceInTx(activitySamples);
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Override
|
// @Override
|
||||||
|
@ -46,8 +46,9 @@ public class GBDevice implements Parcelable {
|
|||||||
private final String mName;
|
private final String mName;
|
||||||
private final String mAddress;
|
private final String mAddress;
|
||||||
private final DeviceType mDeviceType;
|
private final DeviceType mDeviceType;
|
||||||
private String mFirmwareVersion = null;
|
private String mFirmwareVersion;
|
||||||
private String mHardwareVersion = null;
|
private String mFirmwareVersion2;
|
||||||
|
private String mHardwareVersion;
|
||||||
private State mState = State.NOT_CONNECTED;
|
private State mState = State.NOT_CONNECTED;
|
||||||
private short mBatteryLevel = BATTERY_UNKNOWN;
|
private short mBatteryLevel = BATTERY_UNKNOWN;
|
||||||
private short mBatteryThresholdPercent = BATTERY_THRESHOLD_PERCENT;
|
private short mBatteryThresholdPercent = BATTERY_THRESHOLD_PERCENT;
|
||||||
@ -68,6 +69,7 @@ public class GBDevice implements Parcelable {
|
|||||||
mAddress = in.readString();
|
mAddress = in.readString();
|
||||||
mDeviceType = DeviceType.values()[in.readInt()];
|
mDeviceType = DeviceType.values()[in.readInt()];
|
||||||
mFirmwareVersion = in.readString();
|
mFirmwareVersion = in.readString();
|
||||||
|
mFirmwareVersion2 = in.readString();
|
||||||
mHardwareVersion = in.readString();
|
mHardwareVersion = in.readString();
|
||||||
mState = State.values()[in.readInt()];
|
mState = State.values()[in.readInt()];
|
||||||
mBatteryLevel = (short) in.readInt();
|
mBatteryLevel = (short) in.readInt();
|
||||||
@ -86,6 +88,7 @@ public class GBDevice implements Parcelable {
|
|||||||
dest.writeString(mAddress);
|
dest.writeString(mAddress);
|
||||||
dest.writeInt(mDeviceType.ordinal());
|
dest.writeInt(mDeviceType.ordinal());
|
||||||
dest.writeString(mFirmwareVersion);
|
dest.writeString(mFirmwareVersion);
|
||||||
|
dest.writeString(mFirmwareVersion2);
|
||||||
dest.writeString(mHardwareVersion);
|
dest.writeString(mHardwareVersion);
|
||||||
dest.writeInt(mState.ordinal());
|
dest.writeInt(mState.ordinal());
|
||||||
dest.writeInt(mBatteryLevel);
|
dest.writeInt(mBatteryLevel);
|
||||||
@ -113,11 +116,18 @@ public class GBDevice implements Parcelable {
|
|||||||
public String getFirmwareVersion() {
|
public String getFirmwareVersion() {
|
||||||
return mFirmwareVersion;
|
return mFirmwareVersion;
|
||||||
}
|
}
|
||||||
|
public String getFirmwareVersion2() {
|
||||||
|
return mFirmwareVersion2;
|
||||||
|
}
|
||||||
|
|
||||||
public void setFirmwareVersion(String firmwareVersion) {
|
public void setFirmwareVersion(String firmwareVersion) {
|
||||||
mFirmwareVersion = firmwareVersion;
|
mFirmwareVersion = firmwareVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setFirmwareVersion2(String firmwareVersion2) {
|
||||||
|
mFirmwareVersion2 = firmwareVersion2;
|
||||||
|
}
|
||||||
|
|
||||||
public String getHardwareVersion() {
|
public String getHardwareVersion() {
|
||||||
return mHardwareVersion;
|
return mHardwareVersion;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user