forked from upstream-mirrors/OpenTracks
Implement gain/loss via Bluetooth LE Environmental Sensing Sensor.
Fixes #1424.
This commit is contained in:
@@ -17,6 +17,7 @@
|
|||||||
package de.dennisguse.opentracks.sensors;
|
package de.dennisguse.opentracks.sensors;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
|
import android.bluetooth.BluetoothAdapter;
|
||||||
import android.bluetooth.BluetoothDevice;
|
import android.bluetooth.BluetoothDevice;
|
||||||
import android.bluetooth.BluetoothGatt;
|
import android.bluetooth.BluetoothGatt;
|
||||||
import android.bluetooth.BluetoothGattCallback;
|
import android.bluetooth.BluetoothGattCallback;
|
||||||
@@ -33,19 +34,22 @@ import androidx.annotation.NonNull;
|
|||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import de.dennisguse.opentracks.sensors.driver.Driver;
|
||||||
import de.dennisguse.opentracks.sensors.sensorData.SensorHandlerInterface;
|
import de.dennisguse.opentracks.sensors.sensorData.SensorHandlerInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manages connection to a Bluetooth LE sensor and subscribes for onChange-notifications.
|
* Manages connection to a Bluetooth LE sensor and subscribes for onChange-notifications.
|
||||||
*/
|
*/
|
||||||
@SuppressLint("MissingPermission")
|
@SuppressLint("MissingPermission")
|
||||||
public class BluetoothConnectionManager {
|
public class BluetoothConnectionManager implements Driver {
|
||||||
|
|
||||||
private static final String TAG = BluetoothConnectionManager.class.getSimpleName();
|
private static final String TAG = BluetoothConnectionManager.class.getSimpleName();
|
||||||
|
|
||||||
private final SensorManager.SensorDataChangedObserver observer;
|
private final SensorManager.SensorDataChangedObserver observer;
|
||||||
|
|
||||||
private final SensorHandlerInterface sensorHandler;
|
private final SensorHandlerInterface sensorHandler;
|
||||||
|
|
||||||
|
private final BluetoothAdapter bluetoothAdapter;
|
||||||
private BluetoothGatt bluetoothGatt;
|
private BluetoothGatt bluetoothGatt;
|
||||||
private final BluetoothGattCallback connectCallback = new BluetoothGattCallback() {
|
private final BluetoothGattCallback connectCallback = new BluetoothGattCallback() {
|
||||||
@Override
|
@Override
|
||||||
@@ -127,17 +131,46 @@ public class BluetoothConnectionManager {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
BluetoothConnectionManager(SensorManager.SensorDataChangedObserver observer, SensorHandlerInterface sensorHandler) {
|
BluetoothConnectionManager(BluetoothAdapter bluetoothAdapter, SensorManager.SensorDataChangedObserver observer, SensorHandlerInterface sensorHandler) {
|
||||||
|
this.bluetoothAdapter = bluetoothAdapter;
|
||||||
this.observer = observer;
|
this.observer = observer;
|
||||||
this.sensorHandler = sensorHandler;
|
this.sensorHandler = sensorHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized void connect(Context context, Handler handler, @NonNull BluetoothDevice device) {
|
@Override
|
||||||
if (bluetoothGatt != null) {
|
public synchronized void connect(Context context, Handler handler, @NonNull String address) {
|
||||||
|
if (!isBluetoothEnabled()) {
|
||||||
|
Log.w(TAG, "Bluetooth not enabled.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SensorType.NONE.getPreferenceValue().equals(address)) {
|
||||||
|
Log.w(TAG, "NONE: going to disconnect");
|
||||||
|
if (isConnected()) {
|
||||||
|
disconnect();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isConnected()) {
|
||||||
Log.w(TAG, "Already connected; ignoring.");
|
Log.w(TAG, "Already connected; ignoring.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isSameBluetoothDevice(address)) {
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
BluetoothDevice device;
|
||||||
|
try {
|
||||||
|
device = bluetoothAdapter.getRemoteDevice(address);
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
Log.e(TAG, address + ": Unable to get remote device for", e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Log.d(TAG, device + ": trying to connect");
|
Log.d(TAG, device + ": trying to connect");
|
||||||
|
|
||||||
bluetoothGatt = device.connectGatt(context, false, connectCallback, BluetoothDevice.TRANSPORT_AUTO, 0, handler);
|
bluetoothGatt = device.connectGatt(context, false, connectCallback, BluetoothDevice.TRANSPORT_AUTO, 0, handler);
|
||||||
@@ -149,8 +182,10 @@ public class BluetoothConnectionManager {
|
|||||||
observer.onDisconnect(sensorHandler.createEmptySensorData(bluetoothGatt.getDevice().getAddress(), bluetoothGatt.getDevice().getName()));
|
observer.onDisconnect(sensorHandler.createEmptySensorData(bluetoothGatt.getDevice().getAddress(), bluetoothGatt.getDevice().getName()));
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized void disconnect() {
|
@Override
|
||||||
if (bluetoothGatt == null) {
|
public synchronized void disconnect() {
|
||||||
|
if (!isConnected()) {
|
||||||
|
Log.w(TAG, "Not connected; no need to re-connect.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Log.i(TAG, bluetoothGatt.getDevice() + ": start disconnect");
|
Log.i(TAG, bluetoothGatt.getDevice() + ": start disconnect");
|
||||||
@@ -161,11 +196,21 @@ public class BluetoothConnectionManager {
|
|||||||
bluetoothGatt = null;
|
bluetoothGatt = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized boolean isSameBluetoothDevice(String address) {
|
private synchronized boolean isSameBluetoothDevice(String address) {
|
||||||
if (bluetoothGatt == null) {
|
if (bluetoothGatt == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return address.equals(bluetoothGatt.getDevice().getAddress());
|
return address.equals(bluetoothGatt.getDevice().getAddress());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private boolean isBluetoothEnabled() {
|
||||||
|
return bluetoothAdapter != null && bluetoothAdapter.isEnabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isConnected() {
|
||||||
|
return bluetoothGatt != null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package de.dennisguse.opentracks.sensors;
|
package de.dennisguse.opentracks.sensors;
|
||||||
|
|
||||||
import android.bluetooth.BluetoothGattCharacteristic;
|
import android.bluetooth.BluetoothGattCharacteristic;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
@@ -32,9 +33,15 @@ public class BluetoothHandlerBarometricPressure implements SensorHandlerInterfac
|
|||||||
public void handlePayload(SensorManager.SensorDataChangedObserver observer, ServiceMeasurementUUID serviceMeasurementUUID, String sensorName, String address, BluetoothGattCharacteristic characteristic) {
|
public void handlePayload(SensorManager.SensorDataChangedObserver observer, ServiceMeasurementUUID serviceMeasurementUUID, String sensorName, String address, BluetoothGattCharacteristic characteristic) {
|
||||||
AtmosphericPressure value = parseEnvironmentalSensing(characteristic);
|
AtmosphericPressure value = parseEnvironmentalSensing(characteristic);
|
||||||
if (value == null) return;
|
if (value == null) return;
|
||||||
|
Log.i("ZXCV", "VALUE: " + value);
|
||||||
observer.onChange(new Raw<>(value));
|
observer.onChange(new Raw<>(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decoding:
|
||||||
|
* org.bluetooth.service.environmental_sensing.xml
|
||||||
|
* org.bluetooth.characteristic.pressure.xml
|
||||||
|
*/
|
||||||
public static AtmosphericPressure parseEnvironmentalSensing(BluetoothGattCharacteristic characteristic) {
|
public static AtmosphericPressure parseEnvironmentalSensing(BluetoothGattCharacteristic characteristic) {
|
||||||
byte[] raw = characteristic.getValue();
|
byte[] raw = characteristic.getValue();
|
||||||
|
|
||||||
|
|||||||
@@ -17,11 +17,9 @@
|
|||||||
package de.dennisguse.opentracks.sensors;
|
package de.dennisguse.opentracks.sensors;
|
||||||
|
|
||||||
import android.bluetooth.BluetoothAdapter;
|
import android.bluetooth.BluetoothAdapter;
|
||||||
import android.bluetooth.BluetoothDevice;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
@@ -30,7 +28,6 @@ import java.time.Duration;
|
|||||||
|
|
||||||
import de.dennisguse.opentracks.R;
|
import de.dennisguse.opentracks.R;
|
||||||
import de.dennisguse.opentracks.settings.PreferencesUtils;
|
import de.dennisguse.opentracks.settings.PreferencesUtils;
|
||||||
import de.dennisguse.opentracks.util.PermissionRequester;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bluetooth LE sensor manager: manages connections to Bluetooth LE sensors.
|
* Bluetooth LE sensor manager: manages connections to Bluetooth LE sensors.
|
||||||
@@ -45,7 +42,6 @@ public class BluetoothRemoteSensorManager implements SensorConnector, SharedPref
|
|||||||
|
|
||||||
public static final Duration MAX_SENSOR_DATE_SET_AGE = Duration.ofSeconds(5);
|
public static final Duration MAX_SENSOR_DATE_SET_AGE = Duration.ofSeconds(5);
|
||||||
|
|
||||||
private final BluetoothAdapter bluetoothAdapter;
|
|
||||||
private final Context context;
|
private final Context context;
|
||||||
private final Handler handler;
|
private final Handler handler;
|
||||||
private boolean started = false;
|
private boolean started = false;
|
||||||
@@ -59,14 +55,13 @@ public class BluetoothRemoteSensorManager implements SensorConnector, SharedPref
|
|||||||
public BluetoothRemoteSensorManager(@NonNull Context context, @NonNull Handler handler, @Nullable SensorManager.SensorDataChangedObserver observer) {
|
public BluetoothRemoteSensorManager(@NonNull Context context, @NonNull Handler handler, @Nullable SensorManager.SensorDataChangedObserver observer) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.handler = handler;
|
this.handler = handler;
|
||||||
bluetoothAdapter = BluetoothUtils.getAdapter(context);
|
|
||||||
|
|
||||||
this.heartRate = new BluetoothConnectionManager(observer, new BluetoothHandlerManagerHeartRate());
|
|
||||||
this.cyclingCadence = new BluetoothConnectionManager(observer, new BluetoothHandlerCyclingCadence());
|
|
||||||
this.cyclingSpeed = new BluetoothConnectionManager(observer, new BluetoothHandlerCyclingDistanceSpeed());
|
|
||||||
this.cyclingPower = new BluetoothConnectionManager(observer, new BluetoothHandlerManagerCyclingPower());
|
|
||||||
this.runningSpeedAndCadence = new BluetoothConnectionManager(observer, new BluetoothHandlerRunningSpeedAndCadence());
|
|
||||||
|
|
||||||
|
BluetoothAdapter bluetoothAdapter = BluetoothUtils.getAdapter(context);
|
||||||
|
this.heartRate = new BluetoothConnectionManager(bluetoothAdapter, observer, new BluetoothHandlerManagerHeartRate());
|
||||||
|
this.cyclingCadence = new BluetoothConnectionManager(bluetoothAdapter, observer, new BluetoothHandlerCyclingCadence());
|
||||||
|
this.cyclingSpeed = new BluetoothConnectionManager(bluetoothAdapter, observer, new BluetoothHandlerCyclingDistanceSpeed());
|
||||||
|
this.cyclingPower = new BluetoothConnectionManager(bluetoothAdapter, observer, new BluetoothHandlerManagerCyclingPower());
|
||||||
|
this.runningSpeedAndCadence = new BluetoothConnectionManager(bluetoothAdapter, observer, new BluetoothHandlerRunningSpeedAndCadence());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -88,39 +83,8 @@ public class BluetoothRemoteSensorManager implements SensorConnector, SharedPref
|
|||||||
started = false;
|
started = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isEnabled() {
|
|
||||||
return bluetoothAdapter != null && bluetoothAdapter.isEnabled();
|
|
||||||
}
|
|
||||||
|
|
||||||
private synchronized void connect(BluetoothConnectionManager connectionManager, String address) {
|
private synchronized void connect(BluetoothConnectionManager connectionManager, String address) {
|
||||||
if (!isEnabled()) {
|
connectionManager.connect(context, handler, address);
|
||||||
Log.w(TAG, "Bluetooth not enabled.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SensorType.NONE.getPreferenceValue().equals(address)) {
|
|
||||||
Log.w(TAG, "No Bluetooth address.");
|
|
||||||
connectionManager.disconnect();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if there is an ongoing connection; if yes, check if the address changed.
|
|
||||||
if (connectionManager.isSameBluetoothDevice(address)) {
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
connectionManager.disconnect();
|
|
||||||
}
|
|
||||||
if (!PermissionRequester.BLUETOOTH.hasPermission(context)) {
|
|
||||||
Log.w(TAG, "BLUETOOTH_SCAN and/or BLUETOOTH_CONNECT not granted; not connecting.");
|
|
||||||
}
|
|
||||||
|
|
||||||
Log.i(TAG, "Connecting to bluetooth address: " + address);
|
|
||||||
try {
|
|
||||||
BluetoothDevice device = bluetoothAdapter.getRemoteDevice(address);
|
|
||||||
connectionManager.connect(context, handler, device);
|
|
||||||
} catch (IllegalArgumentException e) {
|
|
||||||
Log.e(TAG, "Unable to get remote device for: " + address, e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -5,12 +5,9 @@ import android.content.SharedPreferences;
|
|||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
|
|
||||||
import de.dennisguse.opentracks.data.models.AtmosphericPressure;
|
|
||||||
import de.dennisguse.opentracks.sensors.driver.BarometerInternal;
|
import de.dennisguse.opentracks.sensors.driver.BarometerInternal;
|
||||||
|
import de.dennisguse.opentracks.sensors.driver.Driver;
|
||||||
import de.dennisguse.opentracks.sensors.sensorData.AggregatorBarometer;
|
import de.dennisguse.opentracks.sensors.sensorData.AggregatorBarometer;
|
||||||
import de.dennisguse.opentracks.sensors.sensorData.Raw;
|
|
||||||
import de.dennisguse.opentracks.settings.PreferencesUtils;
|
import de.dennisguse.opentracks.settings.PreferencesUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -20,7 +17,6 @@ public class GainManager implements SensorConnector {
|
|||||||
|
|
||||||
private static final String TAG = GainManager.class.getSimpleName();
|
private static final String TAG = GainManager.class.getSimpleName();
|
||||||
|
|
||||||
private BarometerInternal driver;
|
|
||||||
|
|
||||||
private final SensorManager.SensorDataChangedObserver listener;
|
private final SensorManager.SensorDataChangedObserver listener;
|
||||||
|
|
||||||
@@ -30,10 +26,10 @@ public class GainManager implements SensorConnector {
|
|||||||
|
|
||||||
private Context context;
|
private Context context;
|
||||||
private Handler handler;
|
private Handler handler;
|
||||||
|
private Driver driver;
|
||||||
|
|
||||||
public GainManager(SensorManager.SensorDataChangedObserver listener) {
|
public GainManager(SensorManager.SensorDataChangedObserver listener) {
|
||||||
this.listener = listener;
|
this.listener = listener;
|
||||||
driver = new BarometerInternal();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void start(Context context, Handler handler) {
|
public void start(Context context, Handler handler) {
|
||||||
@@ -48,37 +44,34 @@ public class GainManager implements SensorConnector {
|
|||||||
this.handler = null;
|
this.handler = null;
|
||||||
PreferencesUtils.unregisterOnSharedPreferenceChangeListener(sharedPreferenceChangeListener);
|
PreferencesUtils.unregisterOnSharedPreferenceChangeListener(sharedPreferenceChangeListener);
|
||||||
|
|
||||||
onDisconnect(context);
|
onDisconnect();
|
||||||
}
|
|
||||||
|
|
||||||
public void onSensorValueChanged(AtmosphericPressure currentSensorValue) {
|
|
||||||
listener.onChange(new Raw<>(currentSensorValue));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void connect() {
|
private void connect() {
|
||||||
onDisconnect(context);
|
onDisconnect();
|
||||||
|
|
||||||
String address = PreferencesUtils.getBarometerSensorAddress();
|
String address = PreferencesUtils.getBarometerSensorAddress();
|
||||||
switch (PreferencesUtils.getSensorType(address)) {
|
switch (PreferencesUtils.getSensorType(address)) {
|
||||||
case NONE -> driver = null;
|
case NONE -> driver = null;
|
||||||
case INTERNAL -> driver = new BarometerInternal();
|
case INTERNAL -> driver = new BarometerInternal(listener);
|
||||||
case REMOTE -> throw new RuntimeException("Not implemented"); //TODO #1424
|
case REMOTE -> driver =
|
||||||
|
new BluetoothConnectionManager(
|
||||||
|
BluetoothUtils.getAdapter(context),
|
||||||
|
listener,
|
||||||
|
new BluetoothHandlerBarometricPressure()
|
||||||
|
);
|
||||||
default -> throw new RuntimeException("Not implemented");
|
default -> throw new RuntimeException("Not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (driver != null) {
|
if (driver != null) {
|
||||||
driver.connect(context, handler, this);
|
driver.connect(context, handler, address);
|
||||||
|
|
||||||
if (driver.isConnected()) {
|
|
||||||
listener.onConnect(new AggregatorBarometer("internal", null));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onDisconnect(@NonNull Context context) {
|
private void onDisconnect() {
|
||||||
if (driver == null) return;
|
if (driver == null) return;
|
||||||
|
|
||||||
driver.disconnect(context);
|
driver.disconnect();
|
||||||
listener.onDisconnect(new AggregatorBarometer("internal", null));
|
listener.onDisconnect(new AggregatorBarometer("GainManager", null));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,24 +4,29 @@ import android.content.Context;
|
|||||||
import android.hardware.Sensor;
|
import android.hardware.Sensor;
|
||||||
import android.hardware.SensorEvent;
|
import android.hardware.SensorEvent;
|
||||||
import android.hardware.SensorEventListener;
|
import android.hardware.SensorEventListener;
|
||||||
import android.hardware.SensorManager;
|
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.data.models.AtmosphericPressure;
|
import de.dennisguse.opentracks.data.models.AtmosphericPressure;
|
||||||
import de.dennisguse.opentracks.sensors.GainManager;
|
import de.dennisguse.opentracks.sensors.SensorManager;
|
||||||
|
import de.dennisguse.opentracks.sensors.sensorData.AggregatorBarometer;
|
||||||
|
import de.dennisguse.opentracks.sensors.sensorData.Raw;
|
||||||
|
|
||||||
public class BarometerInternal {
|
public class BarometerInternal implements Driver {
|
||||||
|
|
||||||
private static final String TAG = BarometerInternal.class.getSimpleName();
|
private static final String TAG = BarometerInternal.class.getSimpleName();
|
||||||
|
|
||||||
private static final int SAMPLING_PERIOD = (int) TimeUnit.SECONDS.toMicros(5);
|
private static final int SAMPLING_PERIOD = (int) TimeUnit.SECONDS.toMicros(5);
|
||||||
|
|
||||||
private GainManager observer;
|
private final SensorManager.SensorDataChangedObserver listener;
|
||||||
|
|
||||||
private final SensorEventListener listener = new SensorEventListener() {
|
private Context context;
|
||||||
|
|
||||||
|
private final SensorEventListener sensorEventListener = new SensorEventListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onSensorChanged(SensorEvent event) {
|
public void onSensorChanged(SensorEvent event) {
|
||||||
if (!isConnected()) {
|
if (!isConnected()) {
|
||||||
@@ -29,7 +34,7 @@ public class BarometerInternal {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
observer.onSensorValueChanged(AtmosphericPressure.ofHPA(event.values[0]));
|
listener.onChange(new Raw<>(AtmosphericPressure.ofHPA(event.values[0])));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -38,30 +43,40 @@ public class BarometerInternal {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public void connect(Context context, Handler handler, GainManager observer) {
|
public BarometerInternal(@NonNull SensorManager.SensorDataChangedObserver listener) {
|
||||||
SensorManager sensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
|
this.listener = listener;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void connect(Context context, Handler handler, String addressIgnored) {
|
||||||
|
|
||||||
|
android.hardware.SensorManager sensorManager = (android.hardware.SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
|
||||||
Sensor pressureSensor = sensorManager.getDefaultSensor(Sensor.TYPE_PRESSURE);
|
Sensor pressureSensor = sensorManager.getDefaultSensor(Sensor.TYPE_PRESSURE);
|
||||||
if (pressureSensor == null) {
|
if (pressureSensor == null) {
|
||||||
Log.w(TAG, "No pressure sensor available.");
|
Log.w(TAG, "No pressure sensor available.");
|
||||||
this.observer = null;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sensorManager.registerListener(listener, pressureSensor, SAMPLING_PERIOD, handler)) {
|
if (sensorManager.registerListener(sensorEventListener, pressureSensor, SAMPLING_PERIOD, handler)) {
|
||||||
this.observer = observer;
|
this.context = context;
|
||||||
|
listener.onConnect(new AggregatorBarometer("internal", null));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
disconnect(context);
|
disconnect();
|
||||||
}
|
|
||||||
|
|
||||||
public void disconnect(Context context) {
|
|
||||||
SensorManager sensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
|
|
||||||
sensorManager.unregisterListener(listener);
|
|
||||||
observer = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isConnected() {
|
public boolean isConnected() {
|
||||||
return observer != null;
|
return context != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void disconnect() {
|
||||||
|
if (!isConnected()) return;
|
||||||
|
|
||||||
|
android.hardware.SensorManager sensorManager = (android.hardware.SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
|
||||||
|
sensorManager.unregisterListener(sensorEventListener);
|
||||||
|
this.context = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package de.dennisguse.opentracks.sensors.driver;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Handler;
|
||||||
|
|
||||||
|
public interface Driver {
|
||||||
|
void connect(Context context, Handler handler, String address);
|
||||||
|
|
||||||
|
boolean isConnected();
|
||||||
|
|
||||||
|
void disconnect();
|
||||||
|
}
|
||||||
@@ -120,10 +120,6 @@ public final class SensorDataSet {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (value instanceof AtmosphericPressure) {
|
if (value instanceof AtmosphericPressure) {
|
||||||
if (this.barometer == null) {
|
|
||||||
//TODO Quick fix. This shouldn't happen, but it does. May be a race condition?
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.barometer.add((Raw<AtmosphericPressure>) data);
|
this.barometer.add((Raw<AtmosphericPressure>) data);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -253,10 +253,6 @@ public class PreferencesUtils {
|
|||||||
return SensorType.NONE.getPreferenceValue();
|
return SensorType.NONE.getPreferenceValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isBluetoothSensorAddressNone(String currentValue) {
|
|
||||||
return getBluetoothSensorAddressNone().equals(currentValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static SensorType getSensorType(String address) {
|
public static SensorType getSensorType(String address) {
|
||||||
return Arrays.stream(SensorType.values())
|
return Arrays.stream(SensorType.values())
|
||||||
.filter(it -> it.getPreferenceValue().equals(address))
|
.filter(it -> it.getPreferenceValue().equals(address))
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package de.dennisguse.opentracks.settings.bluetooth;
|
package de.dennisguse.opentracks.settings.bluetooth;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
import android.bluetooth.BluetoothDevice;
|
import android.bluetooth.BluetoothDevice;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
@@ -7,10 +8,13 @@ import android.view.ViewGroup;
|
|||||||
import android.widget.BaseAdapter;
|
import android.widget.BaseAdapter;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
|
@SuppressLint("MissingPermission")
|
||||||
public class BluetoothLeAdapter extends BaseAdapter {
|
public class BluetoothLeAdapter extends BaseAdapter {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -50,22 +54,30 @@ public class BluetoothLeAdapter extends BaseAdapter {
|
|||||||
return currentView;
|
return currentView;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void add(String name, String address) {
|
/**
|
||||||
Device device = new Device(name, address);
|
* @return Data changed?
|
||||||
|
*/
|
||||||
|
public boolean add(String address, String name) {
|
||||||
|
Device device = new Device(address, name);
|
||||||
if (!devices.contains(device)) {
|
if (!devices.contains(device)) {
|
||||||
devices.add(new Device(name, address));
|
devices.add(device);
|
||||||
|
return true;
|
||||||
} else {
|
} else {
|
||||||
for (Device currentDevice : devices) {
|
for (Device currentDevice : devices) {
|
||||||
if (currentDevice.getAddress().equals(address)) {
|
if (currentDevice.address.equals(address)) {
|
||||||
currentDevice.setName(name);
|
currentDevice.name = name;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
notifyDataSetChanged();
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void add(BluetoothDevice bluetoothDevice) {
|
public void addAll(List<BluetoothDevice> bluetoothDevices) {
|
||||||
add(bluetoothDevice.getName(), bluetoothDevice.getAddress());
|
boolean dataSetChanged = bluetoothDevices.stream()
|
||||||
|
.anyMatch(bluetoothDevice -> add(bluetoothDevice.getAddress(), bluetoothDevice.getName()));
|
||||||
|
|
||||||
|
if (dataSetChanged) notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Device get(int index) {
|
public Device get(int index) {
|
||||||
@@ -73,19 +85,14 @@ public class BluetoothLeAdapter extends BaseAdapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static class Device {
|
public static class Device {
|
||||||
private String name;
|
|
||||||
|
@NonNull
|
||||||
private final String address;
|
private final String address;
|
||||||
|
private String name;
|
||||||
|
|
||||||
public Device(String name, String address) {
|
Device(@NonNull String address, String name) {
|
||||||
this.name = name;
|
Objects.requireNonNull(address);
|
||||||
this.address = address;
|
this.address = address;
|
||||||
}
|
|
||||||
|
|
||||||
public String getNameOrAddress() {
|
|
||||||
return name != null ? name : getAddress();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setName(String name) {
|
|
||||||
this.name = name;
|
this.name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,16 +100,21 @@ public class BluetoothLeAdapter extends BaseAdapter {
|
|||||||
return address;
|
return address;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getNameOrAddress() {
|
||||||
|
return name != null ? name : address;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (this == o) return true;
|
if (this == o) return true;
|
||||||
if (!(o instanceof Device device)) return false;
|
if (!(o instanceof Device device)) return false;
|
||||||
|
|
||||||
return address.equals(device.address);
|
return address.equals(device.address);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return Objects.hash(name, address);
|
return Objects.hash(address);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-3
@@ -7,7 +7,9 @@ import android.util.AttributeSet;
|
|||||||
|
|
||||||
import androidx.preference.PreferenceDialogFragmentCompat;
|
import androidx.preference.PreferenceDialogFragmentCompat;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.List;
|
||||||
|
|
||||||
|
import de.dennisguse.opentracks.sensors.BluetoothHandlerBarometricPressure;
|
||||||
|
|
||||||
public class BluetoothLePressurePreference extends BluetoothLeSensorPreference {
|
public class BluetoothLePressurePreference extends BluetoothLeSensorPreference {
|
||||||
|
|
||||||
@@ -34,7 +36,6 @@ public class BluetoothLePressurePreference extends BluetoothLeSensorPreference {
|
|||||||
boolean hasInternalSensor = pressureSensor != null;
|
boolean hasInternalSensor = pressureSensor != null;
|
||||||
|
|
||||||
return BluetoothLeSensorPreference.BluetoothLeSensorPreferenceDialog
|
return BluetoothLeSensorPreference.BluetoothLeSensorPreferenceDialog
|
||||||
// .newInstance(getKey(), List.of(BluetoothHandlerBarometricPressure.BAROMETRIC_PRESSURE), hasInternalSensor); //TODO #1424
|
.newInstance(getKey(), List.of(BluetoothHandlerBarometricPressure.BAROMETRIC_PRESSURE), hasInternalSensor);
|
||||||
.newInstance(getKey(), Collections.emptyList(), hasInternalSensor);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+8
-13
@@ -102,7 +102,7 @@ public abstract class BluetoothLeSensorPreference extends DialogPreference {
|
|||||||
|
|
||||||
BluetoothDevice device = bluetoothAdapter.getRemoteDevice(value);
|
BluetoothDevice device = bluetoothAdapter.getRemoteDevice(value);
|
||||||
if (device != null && device.getName() != null) {
|
if (device != null && device.getName() != null) {
|
||||||
return getContext().getString(R.string.bluetooth_sensor_summary, device.getAddress(), device.getName());
|
return getContext().getString(R.string.bluetooth_sensor_summary, device.getAddress(), device.getName());
|
||||||
}
|
}
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
@@ -121,14 +121,12 @@ public abstract class BluetoothLeSensorPreference extends DialogPreference {
|
|||||||
@Override
|
@Override
|
||||||
public void onScanResult(int callbackType, ScanResult result) {
|
public void onScanResult(int callbackType, ScanResult result) {
|
||||||
Log.d(TAG, "Found device " + result.getDevice().getName() + " " + result);
|
Log.d(TAG, "Found device " + result.getDevice().getName() + " " + result);
|
||||||
listAdapter.add(result.getDevice());
|
onBatchScanResults(List.of(result));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBatchScanResults(List<ScanResult> results) {
|
public void onBatchScanResults(List<ScanResult> results) {
|
||||||
for (ScanResult result : results) {
|
listAdapter.addAll(results.stream().map(ScanResult::getDevice).collect(Collectors.toList()));
|
||||||
onScanResult(-1, result);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -205,24 +203,21 @@ public abstract class BluetoothLeSensorPreference extends DialogPreference {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
String deviceNone = getContext().getString(R.string.sensor_type_value_none);
|
listAdapter.add(SensorType.NONE.getPreferenceValue(), getContext().getString(DEVICE_NONE_RESOURCEID));
|
||||||
String sensorInternal = getString(R.string.sensor_type_value_internal);
|
|
||||||
|
|
||||||
listAdapter.add(getContext().getString(DEVICE_NONE_RESOURCEID), deviceNone);
|
|
||||||
selectedEntryIndex = 0;
|
selectedEntryIndex = 0;
|
||||||
|
|
||||||
BluetoothLeSensorPreference preference = (BluetoothLeSensorPreference) getPreference();
|
BluetoothLeSensorPreference preference = (BluetoothLeSensorPreference) getPreference();
|
||||||
String deviceSelected = preference.value;
|
String deviceSelected = preference.value;
|
||||||
if (includeInternalSensor) {
|
if (includeInternalSensor) {
|
||||||
listAdapter.add(getString(SENSOR_INTERNAL_RESOURCEID), sensorInternal);
|
listAdapter.add(SensorType.INTERNAL.getPreferenceValue(), getString(SENSOR_INTERNAL_RESOURCEID));
|
||||||
if (sensorInternal.equals(deviceSelected)) {
|
if (SensorType.INTERNAL.getPreferenceValue().equals(deviceSelected)) {
|
||||||
selectedEntryIndex = 1;
|
selectedEntryIndex = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (deviceSelected != null && !deviceNone.equals(deviceSelected) && !sensorInternal.equals(deviceSelected)) {
|
if (deviceSelected != null && SensorType.REMOTE.equals(PreferencesUtils.getSensorType(deviceSelected))) {
|
||||||
listAdapter.add(preference.value, preference.value);
|
listAdapter.add(preference.value, preference.value);
|
||||||
selectedEntryIndex++;
|
selectedEntryIndex = !includeInternalSensor ? 1 : 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<ScanFilter> scanFilter = null;
|
List<ScanFilter> scanFilter = null;
|
||||||
|
|||||||
Reference in New Issue
Block a user