From c4685214d8db34166213ffa373a16af1a99401a5 Mon Sep 17 00:00:00 2001 From: Trygve Laugstøl Date: Tue, 27 Jan 2015 21:23:50 +0100 Subject: o Adding 'recently seen' on BtDevice. Updated when scanning. o Removing BtScanResult, it was never used. o Getting MainActivity to listen on device property changed so the UI is properly updated. o Adding a status bar with color to indicate if the device is available, connected or not seen. --- .../main/java/io/trygvis/android/bt/BtDevice.java | 49 ++++-- .../main/java/io/trygvis/android/bt/BtPromise.java | 12 +- .../java/io/trygvis/android/bt/BtScanResult.java | 9 - .../main/java/io/trygvis/android/bt/BtService.java | 3 + .../io/trygvis/android/bt/DefaultBtService.java | 77 ++++++--- .../soilmoisture/DefaultSoilMoistureService.java | 15 +- .../java/io/trygvis/soilmoisture/MainActivity.java | 191 ++++++++++++++------- .../io/trygvis/soilmoisture/SensorActivity.java | 134 +++++++++++++++ .../java/io/trygvis/soilmoisture/SmDevice.java | 4 +- 9 files changed, 364 insertions(+), 130 deletions(-) delete mode 100644 app/src/main/java/io/trygvis/android/bt/BtScanResult.java create mode 100644 app/src/main/java/io/trygvis/soilmoisture/SensorActivity.java (limited to 'app/src/main/java/io/trygvis') 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 fd9e2b9..b90ac4f 100644 --- a/app/src/main/java/io/trygvis/android/bt/BtDevice.java +++ b/app/src/main/java/io/trygvis/android/bt/BtDevice.java @@ -15,14 +15,13 @@ import static io.trygvis.android.bt.BtPromise.PromiseResult.detour; import static io.trygvis.android.bt.BtPromise.PromiseResult.fail; import static io.trygvis.android.bt.BtPromise.PromiseResult.waitForNextEvent; -public class BtDevice { +public class BtDevice implements Comparable { private final static String TAG = BtDevice.class.getSimpleName(); private final DefaultBtService btService; private final BluetoothDevice bluetoothDevice; private BluetoothGatt gatt; private Integer rssi; - private BtScanResult scanResult; private A tag; private final String address; @@ -30,6 +29,10 @@ public class BtDevice { private final boolean seenBefore; private final Date firstSeen; private Date lastSeen; + /** + * If seen in last scan. + */ + private boolean recentlySeen; private boolean connected; private final WrappingBluetoothGattCallback wrappingCallback = new WrappingBluetoothGattCallback(); @@ -37,15 +40,15 @@ public class BtDevice { BtDevice(DefaultBtService btService, BluetoothDevice bluetoothDevice, SQLiteDatabase db, BtService.BtDbIntegration btDbIntegration, long id, Integer rssi, - BtScanResult scanResult, boolean seenBefore, Date firstSeen, Date lastSeen) { + boolean seenBefore, Date firstSeen, Date lastSeen, boolean recentlySeen) { this.btService = btService; this.bluetoothDevice = bluetoothDevice; this.id = id; this.rssi = rssi; - this.scanResult = scanResult; this.seenBefore = seenBefore; this.firstSeen = firstSeen; this.lastSeen = lastSeen; + this.recentlySeen = recentlySeen; this.tag = btDbIntegration.createTag(db, this); this.address = bluetoothDevice.getAddress(); @@ -60,7 +63,7 @@ public class BtDevice { } public String getAddress() { - return bluetoothDevice.getAddress(); + return address; } public String getName() { @@ -71,10 +74,6 @@ public class BtDevice { return rssi; } - public BtScanResult getScanResult() { - return scanResult; - } - public boolean isSeenBefore() { return seenBefore; } @@ -91,6 +90,14 @@ public class BtDevice { this.lastSeen = lastSeen; } + public boolean isRecentlySeen() { + return recentlySeen; + } + + public void setRecentlySeen(boolean recentlySeen) { + this.recentlySeen = recentlySeen; + } + /** * The first handler must handle a onDirect(). *

@@ -101,7 +108,7 @@ public class BtDevice { throw new RuntimeException("The current callback is not done."); } - Log.i(TAG, "withConnection(), address=" + bluetoothDevice.getAddress() + ", connected: " + (gatt != null)); + Log.i(TAG, "withConnection(), address=" + address + ", connected: " + (gatt != null)); BtPromise newPromise; if (gatt == null) { @@ -160,7 +167,7 @@ public class BtDevice { @Override public String toString() { - return "BtDevice{address=" + bluetoothDevice.getAddress() + '}'; + return "BtDevice{address=" + address + '}'; } @Override @@ -174,12 +181,17 @@ public class BtDevice { BtDevice other = (BtDevice) o; - return getAddress().equals(other.getAddress()); + return address.equals(other.getAddress()); } @Override public int hashCode() { - return getAddress().hashCode(); + return address.hashCode(); + } + + @Override + public int compareTo(BtDevice that) { + return address.compareTo(that.address); } private class WrappingBluetoothGattCallback extends BluetoothGattCallback { @@ -196,6 +208,11 @@ public class BtDevice { BtDevice.this.connected = status == BluetoothGatt.GATT_SUCCESS && newState == BluetoothGatt.STATE_CONNECTED; + if (oldConnected && BtDevice.this.connected) { + Log.i(TAG, "Wrapping: Extra 'onConnectionStateChange' event, ignoring. gatt=" + gatt); + return; + } + try { if (callback != null) { callback.onConnectionStateChange(gatt, status, newState); @@ -203,14 +220,14 @@ public class BtDevice { } finally { if (!BtDevice.this.connected) { if (oldConnected) { - Log.i(TAG, "Wrapper: Lost connection, removing gatt. gatt=" + gatt); + Log.i(TAG, "Wrapping: Lost connection, removing gatt. gatt=" + gatt); } else { - Log.i(TAG, "Wrapper: Lost connection, was not connected. gatt=" + gatt); + Log.i(TAG, "Wrapping: Lost connection, was not connected. gatt=" + gatt); } BtDevice.this.gatt = null; } else { - Log.i(TAG, "Wrapper: connected"); + Log.i(TAG, "Wrapping: connected"); } } } diff --git a/app/src/main/java/io/trygvis/android/bt/BtPromise.java b/app/src/main/java/io/trygvis/android/bt/BtPromise.java index 50aad13..bffdd19 100644 --- a/app/src/main/java/io/trygvis/android/bt/BtPromise.java +++ b/app/src/main/java/io/trygvis/android/bt/BtPromise.java @@ -371,17 +371,11 @@ public class BtPromise { if (result instanceof Detour) { BtPromise detour = ((Detour) result).promise; - Log.i(TAG, "Adding detour with " + detour.actionQ.size() + " actions."); +// Log.i(TAG, "Adding detour with " + detour.actionQ.size() + " actions."); events.add("detour, action size=" + detour.actionQ.size() + ", " + // "failure size=" + detour.failureQ.size() + ", " + "finally size=" + detour.finallyQ.size()); - Log.i(TAG, "hasNext(): " + hasNext()); - Log.i(TAG, "currentAction: " + currentAction); - if (hasNext()) { - Log.i(TAG, "next action: " + actionQ.get(currentAction).name); - } - // The new promise should probably be stacked on top, so that all of its // finally handlers are executed after the added set concludes and then the // current stack can continue. @@ -389,10 +383,6 @@ public class BtPromise { actionQ.addAll(currentAction, detour.actionQ); // failureQ.addAll(detour.failureQ);B finallyQ.addAll(detour.finallyQ); - Log.i(TAG, "hasNext(): " + hasNext()); - if (hasNext()) { - Log.i(TAG, "next action: " + actionQ.get(currentAction).name); - } result = PromiseResult.continueDirectly(); } diff --git a/app/src/main/java/io/trygvis/android/bt/BtScanResult.java b/app/src/main/java/io/trygvis/android/bt/BtScanResult.java deleted file mode 100644 index c443afa..0000000 --- a/app/src/main/java/io/trygvis/android/bt/BtScanResult.java +++ /dev/null @@ -1,9 +0,0 @@ -package io.trygvis.android.bt; - -public class BtScanResult { - private final byte[] scanRecord; - - public BtScanResult(byte[] scanRecord) { - this.scanRecord = scanRecord; - } -} 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 06857ee..46f1a80 100644 --- a/app/src/main/java/io/trygvis/android/bt/BtService.java +++ b/app/src/main/java/io/trygvis/android/bt/BtService.java @@ -61,5 +61,8 @@ public interface BtService { public void onDeviceConnection(String address) { } + + public void onDevicePropertyUpdated(String address) { + } } } 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 e42e685..2487bd8 100644 --- a/app/src/main/java/io/trygvis/android/bt/DefaultBtService.java +++ b/app/src/main/java/io/trygvis/android/bt/DefaultBtService.java @@ -31,6 +31,7 @@ import io.trygvis.android.Function; import io.trygvis.android.LocalBinder; import io.trygvis.soilmoisture.R; +import static android.bluetooth.BluetoothAdapter.LeScanCallback; import static java.util.Collections.unmodifiableCollection; public class DefaultBtService extends Service implements BtService { @@ -54,6 +55,8 @@ public class DefaultBtService extends Service implements BtService { private boolean scanning = false; + private Scanner scanner = new Scanner(); + // ----------------------------------------------------------------------- // BtService Implementation // ----------------------------------------------------------------------- @@ -111,7 +114,7 @@ public class DefaultBtService extends Service implements BtService { for (String address : addresses) { BluetoothDevice bluetoothDevice = bluetoothAdapter.getRemoteDevice(address); - register(bluetoothDevice, null, null); + register(bluetoothDevice, null, false); } return true; @@ -134,8 +137,9 @@ public class DefaultBtService extends Service implements BtService { handler.postDelayed(this::stopScanning, timeoutMs); } - if (bluetoothAdapter.startLeScan(leScanCallback)) { + if (bluetoothAdapter.startLeScan(scanner)) { scanning = true; + scanner.found.clear(); sendBroadcast(createScanStarted()); return true; } @@ -148,9 +152,22 @@ public class DefaultBtService extends Service implements BtService { Log.d(TAG, "stopScanning"); // This doesn't mind being called twice. - bluetoothAdapter.stopLeScan(leScanCallback); + bluetoothAdapter.stopLeScan(scanner); scanning = false; + for (BtDevice device : devices) { + boolean recentlySeen = scanner.found.contains(device); + Log.i(TAG, "scanner.found.contains(device)=" + recentlySeen + ", " + + "address=" + device.getAddress()); + + boolean old = device.isRecentlySeen(); + device.setRecentlySeen(recentlySeen); + + // Only if it not seen and it wasn't previously seen + if (!recentlySeen && old) { + sendBroadcast(createDevicePropertyUpdated(device.getAddress())); + } + } sendBroadcast(createScanStopped()); } @@ -163,7 +180,7 @@ public class DefaultBtService extends Service implements BtService { } BluetoothDevice bluetoothDevice = bluetoothAdapter.getRemoteDevice(mac); - return register(bluetoothDevice, null, null); + return register(bluetoothDevice, null, false); } @Override @@ -204,16 +221,6 @@ public class DefaultBtService extends Service implements BtService { } } - // ----------------------------------------------------------------------- - // Scanning - // ----------------------------------------------------------------------- - - private BluetoothAdapter.LeScanCallback leScanCallback = (device, rssi, scanRecord) -> { - BtScanResult scanResult = new BtScanResult(scanRecord); - - register(device, rssi, scanResult); - }; - // ----------------------------------------------------------------------- // Service Implementation // ----------------------------------------------------------------------- @@ -278,17 +285,19 @@ public class DefaultBtService extends Service implements BtService { return openOrCreateDatabase("bt-devices", MODE_ENABLE_WRITE_AHEAD_LOGGING, null); } - private BtDevice register(BluetoothDevice bluetoothDevice, Integer rssi, BtScanResult scanResult) { + private BtDevice register(BluetoothDevice bluetoothDevice, Integer rssi, boolean fromScan) { String address = bluetoothDevice.getAddress(); - BtDevice btDevice = findDevice(address); + BtDevice device = findDevice(address); - if (btDevice != null) { - return btDevice; + if (device != null) { + device.setRecentlySeen(true); + sendBroadcast(createDevicePropertyUpdated(device.getAddress())); + return device; } long now = System.currentTimeMillis(); - btDevice = runTx(db -> { + device = runTx(db -> { Cursor cursor = db.query(Tables.T_BT_DEVICE, new String[]{Tables.C_ID, Tables.C_FIRST_SEEN}, Tables.C_ADDRESS + "=?", new String[]{address}, null, null, null); @@ -315,15 +324,15 @@ public class DefaultBtService extends Service implements BtService { Log.i(TAG, "New device: " + address + ", seenBefore=" + seenBefore); cursor.close(); - return new BtDevice<>(this, bluetoothDevice, db, btDbIntegration, id, rssi, scanResult, - seenBefore, firstSeen, lastSeen); + return new BtDevice<>(this, bluetoothDevice, db, btDbIntegration, id, rssi, seenBefore, + firstSeen, lastSeen, fromScan); }); - devices.add(btDevice); + devices.add(device); - sendBroadcast(createNewDevice(btDevice.getAddress())); + sendBroadcast(createNewDevice(device.getAddress())); - return btDevice; + return device; } Intent createScanStarted() { @@ -348,6 +357,12 @@ public class DefaultBtService extends Service implements BtService { putExtra("address", address); } + Intent createDevicePropertyUpdated(String address) { + return new Intent(BtServiceListenerBroadcastReceiver.INTENT_NAME). + putExtra("event", "devicePropertyUpdated"). + putExtra("address", address); + } + public static void dispatchEvent(Intent intent, BtServiceListenerBroadcastReceiver listener) { String event = intent.getStringExtra("event"); Log.i(TAG, "Dispatching event " + intent.getAction() + "/" + event); @@ -361,6 +376,9 @@ public class DefaultBtService extends Service implements BtService { case "newDevice": listener.onNewDevice(intent.getStringExtra("address")); break; + case "devicePropertyUpdated": + listener.onDevicePropertyUpdated(intent.getStringExtra("address")); + break; case "deviceConnection": listener.onDeviceConnection(intent.getStringExtra("address")); break; @@ -377,4 +395,15 @@ public class DefaultBtService extends Service implements BtService { } return null; } + + private class Scanner implements LeScanCallback { + + private List found = new ArrayList<>(); + + @Override + public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) { + BtDevice d = register(device, rssi, true); + found.add(d); + } + } } diff --git a/app/src/main/java/io/trygvis/soilmoisture/DefaultSoilMoistureService.java b/app/src/main/java/io/trygvis/soilmoisture/DefaultSoilMoistureService.java index 85a6afb..3e1c93b 100644 --- a/app/src/main/java/io/trygvis/soilmoisture/DefaultSoilMoistureService.java +++ b/app/src/main/java/io/trygvis/soilmoisture/DefaultSoilMoistureService.java @@ -119,7 +119,8 @@ public class DefaultSoilMoistureService extends Service implements SoilMoistureS sendBroadcast(createNewDevice(address)); boolean candidate = btDevice.getAddress().startsWith("FB:") || - btDevice.getAddress().startsWith("FD:"); + btDevice.getAddress().startsWith("FD:") || + btDevice.getAddress().startsWith("CE:"); if (!candidate) { Log.w(TAG, "Skipping device: " + btDevice.getAddress()); @@ -131,6 +132,11 @@ public class DefaultSoilMoistureService extends Service implements SoilMoistureS probe(smDevice.getBtDevice().getAddress()); } } + + @Override + public void onDevicePropertyUpdated(String address) { + sendBroadcast(createDevicePropertyUpdated(getDevice(address))); + } }; private BtPromise readAttribute(String value, byte[] req, Function handler) { @@ -159,7 +165,7 @@ public class DefaultSoilMoistureService extends Service implements SoilMoistureS GetSensorNameRes res = parseResponse(bytes, GET_SENSOR_NAME, GetSensorNameRes.class); String name = res.name; - device.getSensorByIndex(index).ifPresent(sensor -> { + device.getSensorByNumber(index).ifPresent(sensor -> { sensor.setName(name); sendBroadcast(createDevicePropertyUpdated(device)); }); @@ -198,6 +204,7 @@ public class DefaultSoilMoistureService extends Service implements SoilMoistureS return continueDirectly(); }). onFinally(success -> { + Log.i(TAG, "finally, smDevice.getIsUseful()=" + smDevice.getIsUseful()); if (smDevice.getIsUseful() == null) { smDevice.setIsUseful(false); } @@ -256,7 +263,11 @@ public class DefaultSoilMoistureService extends Service implements SoilMoistureS values.put(Tables.C_INDEX, i); id = db.insert(Tables.T_SM_SENSOR, null, values); + Log.i(TAG, "Created new sensor row, id=" + id); + device.addSensor(new SmSensor(device, id, (byte) i)); + } else { + Log.i(TAG, "Using existing sensor row, id=" + id); } } diff --git a/app/src/main/java/io/trygvis/soilmoisture/MainActivity.java b/app/src/main/java/io/trygvis/soilmoisture/MainActivity.java index e838f01..6996ef8 100644 --- a/app/src/main/java/io/trygvis/soilmoisture/MainActivity.java +++ b/app/src/main/java/io/trygvis/soilmoisture/MainActivity.java @@ -47,7 +47,7 @@ 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 SoilMoistureListener serviceListener = new MySoilMoistureListener(); + private final SoilMoistureListener serviceListener = new MainSoilMoistureListener(); private final MainActivity context = this; private DeviceListAdapter deviceList; @@ -56,7 +56,10 @@ public class MainActivity extends ListActivity { private ProgressDialog initializing; private boolean ready; - @Override + private int red; + private int yellow; + private int green; + protected void onCreate(Bundle savedInstanceState) { Log.i(TAG, "onCreate"); Thread.setDefaultUncaughtExceptionHandler(EXCEPTION_HANDLER); @@ -92,8 +95,12 @@ public class MainActivity extends ListActivity { bindService(new Intent(this, DefaultSoilMoistureService.class), serviceConnection, BIND_AUTO_CREATE); - initializing = ProgressDialog. - show(this, "Initializing", "Connecting to Bluetooth system.", true); +// initializing = ProgressDialog. +// show(this, "Initializing", "Connecting to Bluetooth system.", true); + + green = getResources().getColor(R.color.green); + yellow = getResources().getColor(R.color.yellow); + red = getResources().getColor(R.color.red); setContentView(R.layout.main); } @@ -264,36 +271,126 @@ public class MainActivity extends ListActivity { Log.i(TAG, "onSensorClick, device=" + sensor.getDevice().getBtDevice().getId() + "/" + sensor.getIndex()); sensor.readCurrentValue(); + +// Intent intent = new Intent(this, SensorActivity.class); +// intent.putExtra(SensorActivity.EXTRA_ADDRESS, sensor.getDevice().getBtDevice().getAddress()); +// intent.putExtra(SensorActivity.EXTRA_NUMBER, sensor.getIndex()); +// startActivity(intent); } // ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- - static class DeviceItem { + class DeviceItem { + final SmDevice device; + final TextView statusBar; final TextView deviceName; final TextView deviceAddress; final TextView rssi; final TextView info; - DeviceItem(View view) { + DeviceItem(SmDevice device, View view) { + this.device = device; + this.statusBar = (TextView) view.findViewById(R.id.status_bar); this.deviceName = (TextView) view.findViewById(R.id.device_name); this.deviceAddress = (TextView) view.findViewById(R.id.device_address); this.rssi = (TextView) view.findViewById(R.id.device_rssi); this.info = (TextView) view.findViewById(R.id.device_info); } + + public void update() { + statusBar.setVisibility(deviceList.isGroupByDevice() ? View.VISIBLE : View.GONE); + statusBar.setBackgroundColor(statusColor(device)); + + if (device.getName() != null) { + deviceName.setText(device.getName()); + } else { + deviceName.setText(R.string.unknown_device); + } + String address = device.getBtDevice().getAddress(); + + if (!device.isProbed()) { + address += " not probed"; + } else if (device.isUseful()) { + address += " useful"; + } else { + address += " not useful"; + } + + address += ", connected=" + device.getBtDevice().connected(); + address += ", recentlySeen=" + device.getBtDevice().isRecentlySeen(); + + deviceAddress.setText(address); + + String rssi = getText(R.string.rssi) + ": " + + (device.getBtDevice().getRssi() != null ? valueOf(device.getBtDevice().getRssi()) : getText(R.string.unknown)); + rssi += ", device: " + device.toString(); + this.rssi.setText(rssi); + +// boolean useful = device.isUseful(); +// +// if (useful) { +// info.setText("Number of sensors: " + device.getSensors().size()); +// } else { +// info.setText(""); +// } + } } - static class SensorItem { + class SensorItem { + final SmDevice device; final SmSensor sensor; + final TextView statusBar; final TextView description; final ProgressBar sensorProgress; SensorItem(SmSensor sensor, View view) { this.sensor = sensor; + this.statusBar = (TextView) view.findViewById(R.id.status_bar); this.description = (TextView) view.findViewById(R.id.description); this.sensorProgress = (ProgressBar) view.findViewById(R.id.sensor_progress); sensorProgress.setMax(1024); + + device = sensor.getDevice(); + + view.setClickable(true); + view.setOnClickListener(v -> { + Log.i(TAG, "onClick, SmSensor: " + +// "position=" + position + ", " + + "sensor=" + sensor /*+ ", " + + "tag=" + v.getTag()*/); + onSensorClick(sensor); + }); + } + + public void update() { + statusBar.setVisibility(deviceList.isGroupByDevice() ? View.GONE : View.VISIBLE); + statusBar.setBackgroundColor(statusColor(device)); + + if (deviceList.isGroupByDevice()) { + statusBar.setVisibility(View.GONE); + } else { + statusBar.setVisibility(View.VISIBLE); + statusBar.setBackgroundColor(statusColor(device)); + } + + Integer value = sensor.getLastValue(); + String text = "Sensor " + sensor; + text += ", value: " + (value == null ? "Unknown" : value); + description.setText(text); + + sensorProgress.setProgress(value != null ? value : 0); + } + } + + private int statusColor(SmDevice device) { + if (device.getBtDevice().connected()) { + return green; + } else if (device.getBtDevice().isRecentlySeen()) { + return yellow; + } else { + return red; } } @@ -349,6 +446,7 @@ public class MainActivity extends ListActivity { } public void notifyDataSetChanged() { + Log.i(TAG, "notifyDataSetChanged"); dataSetObservable.notifyChanged(); } @@ -475,9 +573,9 @@ public class MainActivity extends ListActivity { //noinspection unchecked return getBtDeviceView((BtDevice) o, view); } else if (o instanceof SmDevice) { - return getSmDeviceView(position, (SmDevice) o, view); + return getSmDeviceView((SmDevice) o, view); } else if (o instanceof SmSensor) { - return getSoilSensorView(position, (SmSensor) o, view); + return getSoilSensorView((SmSensor) o, view); } throw new RuntimeException("Not implemented"); @@ -486,7 +584,7 @@ public class MainActivity extends ListActivity { private View getBtDeviceView(BtDevice device, View view) { if (view == null) { view = inflater.inflate(R.layout.fragment_device, null); - view.setTag(new DeviceItem(view)); + view.setTag(new DeviceItem(device.getTag(), view)); view.setOnLongClickListener(v -> MainActivity.this.onBtDeviceLongClick(device)); } @@ -507,79 +605,33 @@ public class MainActivity extends ListActivity { return view; } - private View getSmDeviceView(int position, SmDevice smDevice, View view) { + private View getSmDeviceView(SmDevice smDevice, View view) { if (view == null) { view = inflater.inflate(R.layout.fragment_device, null); - view.setTag(new DeviceItem(view)); + view.setTag(new DeviceItem(smDevice, view)); view.setOnClickListener(v -> onSmDeviceClick(smDevice)); view.setOnLongClickListener(v -> onSmDeviceLongClick(smDevice)); } - DeviceItem item = (DeviceItem) view.getTag(); - - if (smDevice.getName() != null) { - item.deviceName.setText(smDevice.getName()); - } else { - item.deviceName.setText(R.string.unknown_device); - } - String address = smDevice.getBtDevice().getAddress(); - - if (!smDevice.isProbed()) { - address += " not probed"; - } else if (smDevice.isUseful()) { - address += " useful"; - } else { - address += " not useful"; - } - - address += ", connected=" + smDevice.getBtDevice().connected(); - - item.deviceAddress.setText(address); - - String rssi = getText(R.string.rssi) + ": " + - (smDevice.getBtDevice().getRssi() != null ? valueOf(smDevice.getBtDevice().getRssi()) : getText(R.string.unknown)); - rssi += ", device: " + smDevice.toString(); - item.rssi.setText(rssi); - - boolean useful = smDevice.isUseful(); - - if (useful) { - item.info.setText("Number of sensors: " + smDevice.getSensors().size()); - } else { - item.info.setText(""); - } + ((DeviceItem) view.getTag()).update(); return view; } - private View getSoilSensorView(int position, SmSensor smSensor, View view) { + private View getSoilSensorView(SmSensor smSensor, View view) { if (view == null) { - view = inflater.inflate(R.layout.fragment_sensor, null); - view.setTag(new SensorItem(smSensor, view)); - view.setClickable(true); - view.setOnClickListener(v -> { - Log.i(TAG, "onClick, SmSensor: " + -// "position=" + position + ", " + - "sensor=" + smSensor /*+ ", " + - "tag=" + v.getTag()*/); - onSensorClick(smSensor); - }); + view = inflater.inflate(R.layout.fragment_main_sensor, null); + SensorItem item = new SensorItem(smSensor, view); + view.setTag(item); } - SensorItem item = (SensorItem) view.getTag(); - - Integer value = smSensor.getLastValue(); - String text = "Sensor " + smSensor; - text += ", value: " + (value == null ? "Unknown" : value); - item.description.setText(text); - - item.sensorProgress.setProgress(value != null ? value : 0); + ((SensorItem) view.getTag()).update(); return view; } } - private class MySoilMoistureListener extends SoilMoistureListener { + private class MainSoilMoistureListener extends SoilMoistureListener { @Override public void onToast(int id, int length) { CharSequence text = getText(id); @@ -605,7 +657,9 @@ public class MainActivity extends ListActivity { deviceList.notifyDataSetChanged(); startScan(); - initializing.dismiss(); + if (initializing != null) { + initializing.dismiss(); + } } } @@ -630,5 +684,10 @@ public class MainActivity extends ListActivity { public void onNewSample(String address, int sensor) { deviceList.notifyDataSetChanged(); } + + @Override + public void onDevicePropertyUpdated(String address) { + deviceList.notifyDataSetChanged(); + } } } diff --git a/app/src/main/java/io/trygvis/soilmoisture/SensorActivity.java b/app/src/main/java/io/trygvis/soilmoisture/SensorActivity.java new file mode 100644 index 0000000..358382c --- /dev/null +++ b/app/src/main/java/io/trygvis/soilmoisture/SensorActivity.java @@ -0,0 +1,134 @@ +package io.trygvis.soilmoisture; + +import android.app.ActionBar; +import android.app.Activity; +import android.app.Fragment; +import android.content.ComponentName; +import android.content.Context; +import android.content.ServiceConnection; +import android.os.Bundle; +import android.os.IBinder; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Toast; + +import io.trygvis.android.LocalBinder; +import io.trygvis.android.Optional; + +import static io.trygvis.soilmoisture.SoilMoistureService.SoilMoistureListener; + +public class SensorActivity extends Activity { + private final static String TAG = SensorActivity.class.getSimpleName(); + + public static final String EXTRA_ADDRESS = "address"; + public static final String EXTRA_NUMBER = "number"; + + private final Context context = this; + private String address; + private int number; + + private ServiceConnection serviceConnection; + private SoilMoistureService soilMoistureService; + private SensorSoilMoistureListener serviceListener = new SensorSoilMoistureListener(); + private SmDevice device; + private SmSensor sensor; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_sensor); + if (savedInstanceState == null) { + getFragmentManager().beginTransaction() + .add(R.id.container, new PlaceholderFragment()) + .commit(); + } + + address = getIntent().getStringExtra(EXTRA_ADDRESS); + number = getIntent().getIntExtra(EXTRA_NUMBER, -1); + + ActionBar actionBar = getActionBar(); + + if (actionBar != null) { + actionBar.setTitle(number + ": " + address); + } + + serviceConnection = new ServiceConnection() { + @SuppressWarnings("unchecked") + @Override + public void onServiceConnected(ComponentName componentName, IBinder service) { + Log.i(TAG, "onServiceConnected"); + soilMoistureService = ((LocalBinder) service).getService(); + registerReceiver(serviceListener, SoilMoistureListener.INTENT_FILTER); + + device = soilMoistureService.getDevice(address); + Optional o = device.getSensorByNumber(number); + + if (!o.isPresent()) { + Toast.makeText(context, "Could not find sensor #" + number + " on device " + address, + Toast.LENGTH_LONG).show(); + finish(); + } + sensor = o.get(); + + runOnUiThread(SensorActivity.this::initializeView); + } + + @Override + public void onServiceDisconnected(ComponentName componentName) { + Log.i(TAG, "onServiceDisconnected"); + soilMoistureService = null; + } + }; + } + + public void initializeView() { + // current value, last updated + // sync to cloud + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.menu_sensor, menu); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + // Handle action bar item clicks here. The action bar will + // automatically handle clicks on the Home/Up button, so long + // as you specify a parent activity in AndroidManifest.xml. + int id = item.getItemId(); + + //noinspection SimplifiableIfStatement + if (id == R.id.action_settings) { + return true; + } + + return super.onOptionsItemSelected(item); + } + + /** + * A placeholder fragment containing a simple view. + */ + public static class PlaceholderFragment extends Fragment { + + public PlaceholderFragment() { + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + View rootView = inflater.inflate(R.layout.fragment_sensor, container, false); + return rootView; + } + } + + + + private class SensorSoilMoistureListener extends SoilMoistureListener { + } +} diff --git a/app/src/main/java/io/trygvis/soilmoisture/SmDevice.java b/app/src/main/java/io/trygvis/soilmoisture/SmDevice.java index bf2b5f3..808cbb6 100644 --- a/app/src/main/java/io/trygvis/soilmoisture/SmDevice.java +++ b/app/src/main/java/io/trygvis/soilmoisture/SmDevice.java @@ -80,7 +80,7 @@ class SmDevice { return sensors; } - public Optional getSensorByIndex(int index) { + public Optional getSensorByNumber(int index) { if (!isUseful()) { throw new IllegalStateException("Not a useful device"); } @@ -95,7 +95,7 @@ class SmDevice { } void addSensor(SmSensor sensor) { - if (getSensorByIndex(sensor.index).isPresent()) { + if (getSensorByNumber(sensor.index).isPresent()) { throw new IllegalStateException("This device already contains a sensor with index=" + sensor.index); } -- cgit v1.2.3