aboutsummaryrefslogtreecommitdiff
path: root/app/src/main/java/io/trygvis/android/bt
diff options
context:
space:
mode:
Diffstat (limited to 'app/src/main/java/io/trygvis/android/bt')
-rw-r--r--app/src/main/java/io/trygvis/android/bt/BtDevice.java41
-rw-r--r--app/src/main/java/io/trygvis/android/bt/BtService.java8
-rw-r--r--app/src/main/java/io/trygvis/android/bt/DefaultBtService.java109
3 files changed, 142 insertions, 16 deletions
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()));