aboutsummaryrefslogtreecommitdiff
path: root/app/src/main/java/io/trygvis/soilmoisture
diff options
context:
space:
mode:
Diffstat (limited to 'app/src/main/java/io/trygvis/soilmoisture')
-rw-r--r--app/src/main/java/io/trygvis/soilmoisture/Constants.java13
-rw-r--r--app/src/main/java/io/trygvis/soilmoisture/DefaultSmDevicesManager.java224
-rw-r--r--app/src/main/java/io/trygvis/soilmoisture/ExceptionHandler.java8
-rw-r--r--app/src/main/java/io/trygvis/soilmoisture/MainActivity.java178
-rw-r--r--app/src/main/java/io/trygvis/soilmoisture/SmDevice.java35
-rw-r--r--app/src/main/java/io/trygvis/soilmoisture/SmDevicesManager.java50
6 files changed, 396 insertions, 112 deletions
diff --git a/app/src/main/java/io/trygvis/soilmoisture/Constants.java b/app/src/main/java/io/trygvis/soilmoisture/Constants.java
deleted file mode 100644
index 0b891b7..0000000
--- a/app/src/main/java/io/trygvis/soilmoisture/Constants.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package io.trygvis.soilmoisture;
-
-import java.util.UUID;
-
-public interface Constants {
- String TRYGVIS_IO_BASE_UUID = "32D0xxxx-035D-59C5-70D3-BC8E4A1FD83F";
- UUID TRYGVIS_IO_FIKEN_STATUS_PANEL_UUID = UUID.fromString(TRYGVIS_IO_BASE_UUID.replace("xxxx", "0001"));
- UUID TRYGVIS_IO_GAUGE_DATA_UUID = UUID.fromString(TRYGVIS_IO_BASE_UUID.replace("xxxx", "0002"));
- UUID TRYGVIS_IO_GAUGE_CTRL_UUID = UUID.fromString(TRYGVIS_IO_BASE_UUID.replace("xxxx", "0004"));
- UUID TRYGVIS_IO_LED_UUID = UUID.fromString(TRYGVIS_IO_BASE_UUID.replace("xxxx", "0003"));
-
- UUID CLIENT_CHARACTERISTIC_CONFIG = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");
-}
diff --git a/app/src/main/java/io/trygvis/soilmoisture/DefaultSmDevicesManager.java b/app/src/main/java/io/trygvis/soilmoisture/DefaultSmDevicesManager.java
new file mode 100644
index 0000000..301bfc7
--- /dev/null
+++ b/app/src/main/java/io/trygvis/soilmoisture/DefaultSmDevicesManager.java
@@ -0,0 +1,224 @@
+package io.trygvis.soilmoisture;
+
+import android.app.Service;
+import android.bluetooth.BluetoothGatt;
+import android.bluetooth.BluetoothGattCharacteristic;
+import android.bluetooth.BluetoothGattService;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.IBinder;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Set;
+import java.util.TreeSet;
+
+import io.trygvis.android.LocalBinder;
+import io.trygvis.android.bt.BtActionExecutor;
+import io.trygvis.android.bt.BtDevice;
+import io.trygvis.android.bt.BtService;
+import io.trygvis.android.bt.DefaultBtService;
+import io.trygvis.bluetooth.TrygvisIoUuids;
+
+import static io.trygvis.android.bt.BtService.BtServiceListenerBroadcastReceiver;
+
+public class DefaultSmDevicesManager extends Service implements SmDevicesManager {
+ private final static String TAG = DefaultSmDevicesManager.class.getSimpleName();
+
+ private final IBinder binder = new LocalBinder<>(this);
+
+ @SuppressWarnings("UnusedDeclaration")
+ private final DefaultSmDevicesManager context = DefaultSmDevicesManager.this;
+
+ private ServiceConnection serviceConnection;
+
+ private BtService<SmDevice> btService;
+
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return binder;
+ }
+
+ @Override
+ public void onCreate() {
+ Log.i(TAG, "onCreate");
+
+ serviceConnection = new ServiceConnection() {
+ @SuppressWarnings("unchecked")
+ @Override
+ public void onServiceConnected(ComponentName componentName, IBinder service) {
+ btService = ((LocalBinder<BtService<SmDevice>>) service).getService();
+ boolean ok = btService.initialize(DefaultSmDevicesManager.this::onNewDevice);
+
+ sendBroadcast(createReady(ok));
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName componentName) {
+ btService = null;
+ }
+ };
+
+ bindService(new Intent(this, DefaultBtService.class), serviceConnection, BIND_AUTO_CREATE);
+ registerReceiver(btServiceListener, BtServiceListenerBroadcastReceiver.INTENT_FILTER);
+ }
+
+ @Override
+ public void onDestroy() {
+ unregisterReceiver(btServiceListener);
+ Log.i(TAG, "onDestroy" + btService);
+ if (serviceConnection != null) {
+ unbindService(serviceConnection);
+ }
+ }
+
+ private final BtServiceListenerBroadcastReceiver btServiceListener = new BtServiceListenerBroadcastReceiver() {
+ @Override
+ public void onScanStarted() {
+ sendBroadcast(createScanStarted());
+ }
+
+ @Override
+ public void onScanStopped() {
+ sendBroadcast(createScanStopped());
+ }
+
+ @Override
+ public void onNewDevice(String address) {
+ BtDevice<SmDevice> btDevice = btService.getDevice(address);
+ SmDevice smDevice = btDevice.getTag();
+
+ if (!smDevice.isProbed()) {
+ Log.i(TAG, "Probing " + address + ", name=" + btDevice.getName());
+ BtActionExecutor executor = new BtActionExecutor().
+ onConnectionStateChange((gatt, newState) -> {
+ //noinspection SimplifiableIfStatement
+ if (newState == BluetoothGatt.STATE_CONNECTED) {
+ Log.i(TAG, "Connected to " + address + ", getting services");
+ return gatt.discoverServices();
+ }
+
+ Log.i(TAG, "Could not connect to to " + address);
+ smDevice.setIsUseful(false);
+ return false;
+ }).
+ onServicesDiscovered(gatt -> {
+ Log.i(TAG, "Services discovered");
+
+ BluetoothGattService service = gatt.getService(TrygvisIoUuids.Services.SOIL_MOISTURE_SERVICE);
+
+ if (service == null) {
+ smDevice.setIsUseful(false);
+ return false;
+ }
+
+ BluetoothGattCharacteristic characteristic = service.getCharacteristic(TrygvisIoUuids.Characteristics.SOIL_MOISTURE);
+
+ if (characteristic == null) {
+ smDevice.setIsUseful(false);
+ return false;
+ }
+
+ smDevice.setIsUseful(true);
+ sendBroadcast(createNewDevice(address));
+
+ gatt.disconnect();
+
+ return true;
+ });
+
+ btDevice.connect(executor);
+ } else {
+ sendBroadcast(createNewDevice(address));
+ }
+ }
+ };
+
+ // -----------------------------------------------------------------------
+ // SmDevicesManager Implementation
+ // -----------------------------------------------------------------------
+
+ @Override
+ public List<SmDevice> getDevices(Comparator<SmDevice> comparator) {
+ Set<SmDevice> devices = new TreeSet<>(comparator);
+ for (BtDevice<SmDevice> btDevice : btService.getDevices()) {
+ devices.add(btDevice.getTag());
+ }
+ return new ArrayList<>(devices);
+ }
+
+ @Override
+ public SmDevice getDevice(String address) {
+ return btService.getTag(address);
+ }
+
+ @Override
+ public boolean isScanning() {
+ return btService.isScanning();
+ }
+
+ @Override
+ public boolean startScanning(long scanPeriod) {
+ return btService.startScanning(scanPeriod);
+ }
+
+ @Override
+ public void stopScanning() {
+ btService.stopScanning();
+ }
+
+ // -----------------------------------------------------------------------
+ //
+ // -----------------------------------------------------------------------
+
+ private SmDevice onNewDevice(BtDevice<SmDevice> btDevice) {
+ return new SmDevice(btDevice);
+ }
+
+ private Intent createReady(boolean success) {
+ return new Intent(SmDeviceListener.INTENT_NAME).
+ putExtra("event", "ready").
+ putExtra("success", success);
+ }
+
+ private Intent createScanStarted() {
+ return new Intent(SmDeviceListener.INTENT_NAME).
+ putExtra("event", "scanStarted");
+ }
+
+ private Intent createScanStopped() {
+ return new Intent(SmDeviceListener.INTENT_NAME).
+ putExtra("event", "scanStopped");
+ }
+
+ private Intent createNewDevice(String address) {
+ return new Intent(SmDeviceListener.INTENT_NAME).
+ putExtra("event", "newDevice").
+ putExtra("address", address);
+ }
+
+ public static void dispatchEvent(Intent intent, SmDeviceListener listener) {
+ String event = intent.getStringExtra("event");
+ Log.i(TAG, "Dispatching event " + intent.getAction() + "/" + event);
+ switch (event) {
+ case "ready":
+ listener.onReady(intent.getBooleanExtra("success", false));
+ break;
+ case "newDevice":
+ listener.onNewDevice(intent.getStringExtra("address"));
+ break;
+ case "scanStarted":
+ listener.onScanStarted();
+ break;
+ case "scanStopped":
+ listener.onScanStopped();
+ break;
+ default:
+ break;
+ }
+ }
+}
diff --git a/app/src/main/java/io/trygvis/soilmoisture/ExceptionHandler.java b/app/src/main/java/io/trygvis/soilmoisture/ExceptionHandler.java
index faa95e1..ff70b0f 100644
--- a/app/src/main/java/io/trygvis/soilmoisture/ExceptionHandler.java
+++ b/app/src/main/java/io/trygvis/soilmoisture/ExceptionHandler.java
@@ -11,12 +11,6 @@ public class ExceptionHandler implements Thread.UncaughtExceptionHandler {
public void uncaughtException(Thread thread, Throwable ex) {
Log.e(TAG, "Uncaught", ex);
- if (ex instanceof RuntimeException) {
- throw (RuntimeException) ex;
- }
- if (ex instanceof Error) {
- throw (Error) ex;
- }
- throw new RuntimeException(ex);
+ Thread.getDefaultUncaughtExceptionHandler().uncaughtException(thread, ex);
}
}
diff --git a/app/src/main/java/io/trygvis/soilmoisture/MainActivity.java b/app/src/main/java/io/trygvis/soilmoisture/MainActivity.java
index 18c96b8..6adc96c 100644
--- a/app/src/main/java/io/trygvis/soilmoisture/MainActivity.java
+++ b/app/src/main/java/io/trygvis/soilmoisture/MainActivity.java
@@ -2,8 +2,7 @@ package io.trygvis.soilmoisture;
import android.app.ActionBar;
import android.app.ListActivity;
-import android.bluetooth.BluetoothGatt;
-import android.bluetooth.BluetoothGattService;
+import android.app.ProgressDialog;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
@@ -20,20 +19,19 @@ import android.widget.Button;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;
+import android.widget.Toast;
import com.crashlytics.android.Crashlytics;
+import java.util.ArrayList;
+import java.util.List;
+
import io.fabric.sdk.android.Fabric;
-import io.trygvis.android.bt.BtActionExecutor;
+import io.trygvis.android.LocalBinder;
import io.trygvis.android.bt.BtActivitySupport;
-import io.trygvis.android.bt.BtDevice;
-import io.trygvis.android.bt.BtDeviceListener;
-import io.trygvis.android.bt.BtService;
-import io.trygvis.android.bt.DefaultBtService;
-import io.trygvis.bluetooth.TrygvisIoUuids;
-import static io.trygvis.android.bt.BtService.BtServiceListener;
import static io.trygvis.soilmoisture.ExceptionHandler.EXCEPTION_HANDLER;
+import static io.trygvis.soilmoisture.SmDevicesManager.SmDeviceListener;
import static java.lang.String.valueOf;
public class MainActivity extends ListActivity {
@@ -44,11 +42,14 @@ public class MainActivity extends ListActivity {
private static final int REQUEST_ENABLE_BT = 1;
private final BtActivitySupport btActivitySupport = new BtActivitySupport(this, REQUEST_ENABLE_BT);
+ private final SmDeviceListener serviceListener = new MySmDeviceListener();
+ private final MainActivity context = this;
private DeviceListAdapter deviceList;
- private BtService<SmDevice> btService;
-
private ServiceConnection serviceConnection;
+ private SmDevicesManager smDevicesManager;
+ private ProgressDialog initializing;
+ private boolean ready;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -71,26 +72,23 @@ public class MainActivity extends ListActivity {
@SuppressWarnings("unchecked")
@Override
public void onServiceConnected(ComponentName componentName, IBinder service) {
- btService = ((BtService.LocalBinder<SmDevice>) service).getService();
- if (!btService.initialize(serviceListener, SmDevice::new)) {
- finish();
- }
-
- deviceList = new DeviceListAdapter();
- deviceList.notifyDataSetChanged();
- setListAdapter(deviceList);
-
- startScan();
+ Log.i(TAG, "onServiceConnected");
+ smDevicesManager = ((LocalBinder<SmDevicesManager>) service).getService();
+ registerReceiver(serviceListener, SmDeviceListener.INTENT_FILTER);
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
- btService = null;
+ Log.i(TAG, "onServiceDisconnected");
+ smDevicesManager = null;
stopScan();
}
};
- bindService(new Intent(this, DefaultBtService.class), serviceConnection, BIND_AUTO_CREATE);
+ bindService(new Intent(this, DefaultSmDevicesManager.class), serviceConnection, BIND_AUTO_CREATE);
+
+ initializing = ProgressDialog.
+ show(this, "Initializing", "Connecting to Bluetooth system.", true);
}
@Override
@@ -114,7 +112,7 @@ public class MainActivity extends ListActivity {
return;
}
- // registerReceiver(btServiceBroadcastReceiver, IntentAction.ALL_FILTER);
+ registerReceiver(serviceListener, SmDeviceListener.INTENT_FILTER);
}
@Override
@@ -123,7 +121,7 @@ public class MainActivity extends ListActivity {
super.onPause();
stopScan();
- // unregisterReceiver(ntServiceBroadcastReceiver);
+ unregisterReceiver(serviceListener);
}
@Override
@@ -143,14 +141,20 @@ public class MainActivity extends ListActivity {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
- if (!btService.isScanning()) {
+ if (ready) {
+ if (!smDevicesManager.isScanning()) {
+ menu.findItem(R.id.menu_stop).setVisible(false);
+ menu.findItem(R.id.menu_scan).setVisible(true);
+ menu.findItem(R.id.menu_refresh).setActionView(null);
+ } else {
+ menu.findItem(R.id.menu_stop).setVisible(true);
+ menu.findItem(R.id.menu_scan).setVisible(false);
+ menu.findItem(R.id.menu_refresh).setActionView(R.layout.actionbar_indeterminate_progress);
+ }
+ } else {
menu.findItem(R.id.menu_stop).setVisible(false);
menu.findItem(R.id.menu_scan).setVisible(true);
menu.findItem(R.id.menu_refresh).setActionView(null);
- } else {
- menu.findItem(R.id.menu_stop).setVisible(true);
- menu.findItem(R.id.menu_scan).setVisible(false);
- menu.findItem(R.id.menu_refresh).setActionView(R.layout.actionbar_indeterminate_progress);
}
return true;
}
@@ -171,12 +175,12 @@ public class MainActivity extends ListActivity {
}
private void startScan() {
- btService.startScanning(SCAN_PERIOD);
+ smDevicesManager.startScanning(SCAN_PERIOD);
}
private void stopScan() {
- if (btService != null) {
- btService.stopScanning();
+ if (smDevicesManager != null) {
+ smDevicesManager.stopScanning();
}
}
@@ -184,54 +188,9 @@ public class MainActivity extends ListActivity {
protected void onListItemClick(ListView l, View v, int position, long id) {
stopScan();
- BtDevice<SmDevice> state = btService.getDevices().get(position);
-
- BtActionExecutor executor = new BtActionExecutor().
- onConnectionStateChange((gatt, newState) -> {
- if (newState == BluetoothGatt.STATE_CONNECTED) {
- Intent intent = new Intent(this, SoilActivity.class);
- startActivity(intent);
- return true;
- }
- return false;
- }).
- onServicesDiscovered(gatt -> false);
-
- state.connect(executor);
+// SmDevice state = smDevicesManager.getDevices(SmDevice.deviceComparator).get(position);
}
- BtServiceListener<SmDevice> serviceListener = new BtServiceListener<SmDevice>() {
- @Override
- public void onScanStarted() {
- invalidateOptionsMenu();
- }
-
- @Override
- public void onNewDevice(BtDevice<SmDevice> device) {
- device.addListener(deviceListener);
-
- BtActionExecutor executor = new BtActionExecutor().
- onConnectionStateChange((gatt, newState) -> gatt.discoverServices()).
- onServicesDiscovered(gatt -> {
- BluetoothGattService service = gatt.getService(TrygvisIoUuids.Services.SOIL_MOISTURE_SERVICE);
-
- boolean useful = service != null;
- device.getTag().setIsUseful(useful);
- runOnUiThread(deviceList::notifyDataSetChanged);
- return useful;
- });
- device.connect(executor);
- }
-
- @Override
- public void onScanStopped() {
- invalidateOptionsMenu();
- }
- };
-
- BtDeviceListener deviceListener = new BtDeviceListener() {
- };
-
// -----------------------------------------------------------------------
//
// -----------------------------------------------------------------------
@@ -253,16 +212,17 @@ public class MainActivity extends ListActivity {
}
private class DeviceListAdapter extends BaseAdapter {
+ private List<SmDevice> devices = new ArrayList<>();
private LayoutInflater inflater = MainActivity.this.getLayoutInflater();
@Override
public int getCount() {
- return btService.getDevices().size();
+ return devices.size();
}
@Override
- public Object getItem(int i) {
- return btService.getDevices().get(i);
+ public SmDevice getItem(int i) {
+ return devices.get(i);
}
@Override
@@ -283,18 +243,16 @@ public class MainActivity extends ListActivity {
item = (DeviceListItem) view.getTag();
}
- BtDevice<SmDevice> btDevice = btService.getDevices().get(i);
- if (btDevice.getName() != null && btDevice.getName().length() > 0) {
- item.deviceName.setText(btDevice.getName());
+ SmDevice smDevice = getItem(i);
+ if (smDevice.getName() != null) {
+ item.deviceName.setText(smDevice.getName());
} else {
item.deviceName.setText(R.string.unknown_device);
}
- item.deviceAddress.setText(btDevice.getAddress());
+ item.deviceAddress.setText(smDevice.getBtDevice().getAddress());
item.rssi.setText(getText(R.string.rssi) + ": " +
- (btDevice.getRssi() != 0 ? valueOf(btDevice.getRssi()) : getText(R.string.unknown)));
-
- SmDevice smDevice = btDevice.getTag();
+ (smDevice.getBtDevice().getRssi() != 0 ? valueOf(smDevice.getBtDevice().getRssi()) : getText(R.string.unknown)));
boolean useful = smDevice.isUseful();
item.spinner.setVisibility(useful ? View.GONE : View.VISIBLE);
@@ -304,4 +262,46 @@ public class MainActivity extends ListActivity {
return view;
}
}
+
+ private class MySmDeviceListener extends SmDeviceListener {
+ @Override
+ public void onReady(boolean ok) {
+ if (!ok) {
+ Toast.makeText(context,
+ "Could not initialize services.",
+ Toast.LENGTH_SHORT).
+ show();
+
+ finish();
+ } else {
+ ready = true;
+ deviceList = new DeviceListAdapter();
+ setListAdapter(deviceList);
+
+ deviceList.notifyDataSetChanged();
+ startScan();
+
+ initializing.dismiss();
+ }
+ }
+
+ @Override
+ public void onScanStarted() {
+ invalidateOptionsMenu();
+ }
+
+ @Override
+ public void onScanStopped() {
+ invalidateOptionsMenu();
+ }
+
+ @Override
+ public void onNewDevice(String address) {
+ SmDevice device = smDevicesManager.getDevice(address);
+ deviceList.devices.add(device);
+ deviceList.notifyDataSetInvalidated();
+
+ Log.i(TAG, "deviceList.devices.size() = " + deviceList.devices.size());
+ }
+ }
}
diff --git a/app/src/main/java/io/trygvis/soilmoisture/SmDevice.java b/app/src/main/java/io/trygvis/soilmoisture/SmDevice.java
index 6bc522d..1ed7ecb 100644
--- a/app/src/main/java/io/trygvis/soilmoisture/SmDevice.java
+++ b/app/src/main/java/io/trygvis/soilmoisture/SmDevice.java
@@ -2,14 +2,35 @@ package io.trygvis.soilmoisture;
import android.util.Log;
-class SmDevice {
+import java.util.Comparator;
+
+import io.trygvis.android.bt.BtDevice;
+
+class SmDevice implements BtDevice.BtDeviceWrapper<SmDevice> {
+ public static final Comparator<SmDevice> deviceComparator = (a, b) -> a.getBtDevice().getAddress().compareTo(b.getBtDevice().getAddress());
+
private final static String TAG = SmDevice.class.getSimpleName();
- public SmDevice() {
+ private final BtDevice<SmDevice> btDevice;
+
+ private String name;
+
+ private Boolean isUseful;
+
+ public SmDevice(BtDevice<SmDevice> btDevice) {
+ this.btDevice = btDevice;
Log.i(TAG, "new device");
+
+ name = btDevice.getName();
+
+ if (name != null && name.trim().length() == 0) {
+ name = null;
+ }
}
- private Boolean isUseful;
+ public BtDevice<SmDevice> getBtDevice() {
+ return btDevice;
+ }
public boolean isUseful() {
return isUseful != null && isUseful;
@@ -19,8 +40,16 @@ class SmDevice {
return isUseful;
}
+ public boolean isProbed() {
+ return isUseful != null;
+ }
+
public void setIsUseful(Boolean isUseful) {
Log.i(TAG, "useful=" + isUseful);
this.isUseful = isUseful;
}
+
+ public String getName() {
+ return name;
+ }
}
diff --git a/app/src/main/java/io/trygvis/soilmoisture/SmDevicesManager.java b/app/src/main/java/io/trygvis/soilmoisture/SmDevicesManager.java
new file mode 100644
index 0000000..531061a
--- /dev/null
+++ b/app/src/main/java/io/trygvis/soilmoisture/SmDevicesManager.java
@@ -0,0 +1,50 @@
+package io.trygvis.soilmoisture;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+
+import java.util.Comparator;
+import java.util.List;
+
+import io.trygvis.android.bt.BtDevice;
+
+public interface SmDevicesManager {
+ List<SmDevice> getDevices(Comparator<SmDevice> comparator);
+
+ SmDevice getDevice(String address);
+
+ boolean isScanning();
+
+ boolean startScanning(long scanPeriod);
+
+ void stopScanning();
+
+ public abstract static class SmDeviceListener extends BroadcastReceiver {
+
+ public static final String INTENT_NAME = SmDeviceListener.class.getName();
+
+ public static final IntentFilter INTENT_FILTER = new IntentFilter(INTENT_NAME);
+
+ public void onReceive(Context context, Intent intent) {
+ if (!intent.getAction().equals(INTENT_NAME)) {
+ return;
+ }
+
+ DefaultSmDevicesManager.dispatchEvent(intent, this);
+ }
+
+ public void onReady(boolean ok) {
+ }
+
+ public void onScanStarted() {
+ }
+
+ public void onNewDevice(String address) {
+ }
+
+ public void onScanStopped() {
+ }
+ }
+}