diff options
Diffstat (limited to 'app/src')
7 files changed, 169 insertions, 17 deletions
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 85d6d39..91cd1b2 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -39,7 +39,12 @@ <service android:name="io.trygvis.android.bt.DefaultBtService" - android:enabled="true"/> + android:enabled="true" + android:exported="false"> + <meta-data + android:name="io.trygvis.android.bt.DefaultBtService.migration" + android:value="db/migration/sm"/> + </service> <service android:name=".DefaultSmDevicesManager" diff --git a/app/src/main/assets/db/migration/bt/V001.001__baseline.sql b/app/src/main/assets/db/migration/bt/V001.001__baseline.sql new file mode 100644 index 0000000..daf84be --- /dev/null +++ b/app/src/main/assets/db/migration/bt/V001.001__baseline.sql @@ -0,0 +1,8 @@ +-- drop table bt_device; + +create table bt_device( + id integer not null primary key autoincrement, + address char(17) not null unique, + first_seen timestamp not null, + last_seen timestamp not null +); diff --git a/app/src/main/assets/db/migration/sm/V001.001__sm_baseline.sql b/app/src/main/assets/db/migration/sm/V001.001__sm_baseline.sql new file mode 100644 index 0000000..61e8505 --- /dev/null +++ b/app/src/main/assets/db/migration/sm/V001.001__sm_baseline.sql @@ -0,0 +1,8 @@ +-- drop table soil_monitor; + +create table soil_monitor( + id integer not null primary key autoincrement, + bt_device integer not null references bt_device(id), + last_value integer, + warning_level integer not null +); diff --git a/app/src/main/assets/db/migration/sm/V001.002__sample.sql b/app/src/main/assets/db/migration/sm/V001.002__sample.sql new file mode 100644 index 0000000..23fec3b --- /dev/null +++ b/app/src/main/assets/db/migration/sm/V001.002__sample.sql @@ -0,0 +1,5 @@ +create table soil_sample( + id integer not null primary key autoincrement, + soil_monitor integer not null references soil_monitor(id), + value integer +); diff --git a/app/src/main/java/io/trygvis/android/bt/BtDevice.java b/app/src/main/java/io/trygvis/android/bt/BtDevice.java index e34e9ea..edad522 100644 --- a/app/src/main/java/io/trygvis/android/bt/BtDevice.java +++ b/app/src/main/java/io/trygvis/android/bt/BtDevice.java @@ -3,9 +3,9 @@ package io.trygvis.android.bt; import android.bluetooth.BluetoothDevice; import android.util.Log; -import io.trygvis.android.Function; +import java.util.Date; -public class BtDevice<A> { +public class BtDevice<A extends BtDevice.BtDeviceWrapper<A>> { private final static String TAG = BtDevice.class.getSimpleName(); private final DefaultBtService btService; @@ -14,18 +14,31 @@ public class BtDevice<A> { private BtScanResult scanResult; private A tag; - private boolean seenNow; + private final long id; + private final boolean seenBefore; + private final Date firstSeen; + private Date lastSeen; - public static interface BtDeviceWrapper<A> { + public static interface BtDeviceWrapper<A extends BtDevice.BtDeviceWrapper<A>> { BtDevice<A> getBtDevice(); } - BtDevice(DefaultBtService btService, BluetoothDevice bluetoothDevice, Function<BtDevice<A>, A> tagConstructor, Integer rssi, BtScanResult scanResult) { + BtDevice(DefaultBtService btService, BluetoothDevice bluetoothDevice, + BtService.BtDbIntegration<A> btDbIntegration, long id, Integer rssi, + BtScanResult scanResult, boolean seenBefore, Date firstSeen, Date lastSeen) { this.btService = btService; this.bluetoothDevice = bluetoothDevice; - this.tag = tagConstructor.apply(this); + this.tag = btDbIntegration.createTag(this); + this.id = id; this.rssi = rssi; this.scanResult = scanResult; + this.seenBefore = seenBefore; + this.firstSeen = firstSeen; + this.lastSeen = lastSeen; + } + + public long getId() { + return id; } public A getTag() { @@ -44,6 +57,22 @@ public class BtDevice<A> { return rssi; } + public boolean isSeenBefore() { + return seenBefore; + } + + public Date getFirstSeen() { + return firstSeen; + } + + public Date getLastSeen() { + return lastSeen; + } + + public void setLastSeen(Date lastSeen) { + this.lastSeen = lastSeen; + } + public boolean connect(BtActionExecutor executor) { Log.i(TAG, "connect(), address=" + bluetoothDevice.getAddress() + ", queue=" + executor); bluetoothDevice.connectGatt(btService, false, executor.asCallback()); diff --git a/app/src/main/java/io/trygvis/android/bt/BtService.java b/app/src/main/java/io/trygvis/android/bt/BtService.java index 968a4a8..ca8bcd9 100644 --- a/app/src/main/java/io/trygvis/android/bt/BtService.java +++ b/app/src/main/java/io/trygvis/android/bt/BtService.java @@ -7,11 +7,9 @@ import android.content.IntentFilter; import java.util.Collection; -import io.trygvis.android.Function; - public interface BtService<A extends BtDevice.BtDeviceWrapper<A>> { - boolean initialize(Function<BtDevice<A>, A> tagConstructor); + boolean initialize(BtDbIntegration<A> btDbIntegration); void clearCache(); @@ -29,6 +27,10 @@ public interface BtService<A extends BtDevice.BtDeviceWrapper<A>> { Collection<A> getTags(); + public static interface BtDbIntegration<A extends BtDevice.BtDeviceWrapper<A>> { + A createTag(BtDevice<A> a); + } + public static class BtServiceListenerBroadcastReceiver extends BroadcastReceiver { public static final String INTENT_NAME = BtServiceListenerBroadcastReceiver.class.getName(); diff --git a/app/src/main/java/io/trygvis/android/bt/DefaultBtService.java b/app/src/main/java/io/trygvis/android/bt/DefaultBtService.java index 51d84af..5e13a1f 100644 --- a/app/src/main/java/io/trygvis/android/bt/DefaultBtService.java +++ b/app/src/main/java/io/trygvis/android/bt/DefaultBtService.java @@ -4,20 +4,28 @@ import android.app.Service; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothManager; +import android.content.ComponentName; +import android.content.ContentValues; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.util.Log; import android.widget.Toast; +import org.flywaydb.core.Flyway; +import org.flywaydb.core.api.android.ContextHolder; + import java.util.ArrayList; import java.util.Collection; +import java.util.Date; import java.util.HashSet; import java.util.Set; -import io.trygvis.android.Function; import io.trygvis.android.LocalBinder; import io.trygvis.soilmoisture.R; @@ -34,7 +42,7 @@ public class DefaultBtService<A extends BtDevice.BtDeviceWrapper<A>> extends Ser // State // ----------------------------------------------------------------------- - private Function<BtDevice<A>, A> tagConstructor; + private BtDbIntegration<A> btDbIntegration; private BluetoothManager bluetoothManager; @@ -49,13 +57,13 @@ public class DefaultBtService<A extends BtDevice.BtDeviceWrapper<A>> extends Ser // ----------------------------------------------------------------------- @Override - public boolean initialize(Function<BtDevice<A>, A> tagConstructor) { + public boolean initialize(BtDbIntegration<A> btDbIntegration) { if (bluetoothManager != null) { Log.i(TAG, "Already initialized"); return false; } - this.tagConstructor = tagConstructor; + this.btDbIntegration = btDbIntegration; // Use this check to determine whether BLE is supported on the device. Then you can // selectively disable BLE-related features. @@ -171,19 +179,106 @@ public class DefaultBtService<A extends BtDevice.BtDeviceWrapper<A>> extends Ser return binder; } + @Override + public void onCreate() { + Bundle data; + + try { + ComponentName myService = new ComponentName(this, this.getClass()); + data = getPackageManager().getServiceInfo(myService, PackageManager.GET_META_DATA).metaData; + } catch (PackageManager.NameNotFoundException e) { + throw new RuntimeException(e); + } + + SQLiteDatabase db = openBtDevices(); + String path; + try { + path = db.getPath(); + } finally { + db.close(); + } + + { + ContextHolder.setContext(this); + Flyway flyway = new Flyway(); + flyway.setDataSource("jdbc:sqlite:" + path, "", ""); + flyway.setTable("schema_version_bt"); + flyway.setLocations("db/migration/bt"); + + flyway.migrate(); + } + + String customMigrations = data.getString(getClass().getName() + ".migration", null); + + if (customMigrations != null) { + ContextHolder.setContext(this); + Flyway flyway = new Flyway(); + flyway.setDataSource("jdbc:sqlite:" + path, "", ""); + flyway.setTable("schema_version_custom"); + flyway.setLocations(customMigrations); + + flyway.setBaselineOnMigrate(true); + flyway.migrate(); + } + } + // ----------------------------------------------------------------------- // Stuff // ----------------------------------------------------------------------- + private SQLiteDatabase openBtDevices() { + return openOrCreateDatabase("bt-devices", MODE_ENABLE_WRITE_AHEAD_LOGGING, null); + } + private BtDevice<A> register(BluetoothDevice bluetoothDevice, Integer rssi, BtScanResult scanResult) { - BtDevice<A> btDevice = findDevice(bluetoothDevice.getAddress()); + String address = bluetoothDevice.getAddress(); + BtDevice<A> btDevice = findDevice(address); if (btDevice != null) { return btDevice; } - Log.i(TAG, "New device: " + bluetoothDevice.getAddress()); - btDevice = new BtDevice<>(this, bluetoothDevice, tagConstructor, rssi, scanResult); + long now = System.currentTimeMillis(); + + SQLiteDatabase db = openBtDevices(); + try { + db.beginTransaction(); + + Cursor cursor = db.query("bt_device", new String[]{"id", "first_seen"}, "address=?", + new String[]{address}, null, null, null); + + long id; + Date firstSeen, lastSeen; + boolean seenBefore = cursor.moveToNext(); + + if (seenBefore) { + id = cursor.getLong(0); + firstSeen = new Date(cursor.getLong(1)); + lastSeen = new Date(now); + + ContentValues values = new ContentValues(); + values.put("last_seen", now); + db.update("bt_device", values, "address=?", new String[]{address}); + } else { + ContentValues values = new ContentValues(); + values.put("address", address); + values.put("first_seen", now); + values.put("last_seen", now); + id = db.insert("bt_device", null, values); + firstSeen = lastSeen = new Date(now); + } + + Log.i(TAG, "New device: " + address + ", seenBefore=" + seenBefore); + btDevice = new BtDevice<>(this, bluetoothDevice, btDbIntegration, id, rssi, scanResult, + seenBefore, firstSeen, lastSeen); + + cursor.close(); + db.setTransactionSuccessful(); + } finally { + db.endTransaction(); + db.close(); + } + devices.add(btDevice); sendBroadcast(createNewDevice(btDevice.getAddress())); |