diff --git a/src/main/java/de/dennisguse/opentracks/content/sensor/SensorState.java b/src/main/java/de/dennisguse/opentracks/content/sensor/SensorState.java index 3ecda3685..5b7a942fb 100644 --- a/src/main/java/de/dennisguse/opentracks/content/sensor/SensorState.java +++ b/src/main/java/de/dennisguse/opentracks/content/sensor/SensorState.java @@ -8,6 +8,7 @@ public enum SensorState { NONE, CONNECTING, CONNECTED, + DISCONNECTING, DISCONNECTED; public static String getStateAsString(SensorState state, Context c) { @@ -18,6 +19,8 @@ public enum SensorState { return c.getString(R.string.sensor_state_connecting); case CONNECTED: return c.getString(R.string.sensor_state_connected); + case DISCONNECTING: + return c.getString(R.string.sensor_state_disconnected); case DISCONNECTED: return c.getString(R.string.sensor_state_disconnected); default: diff --git a/src/main/java/de/dennisguse/opentracks/services/sensors/BluetoothConnectionManager.java b/src/main/java/de/dennisguse/opentracks/services/sensors/BluetoothConnectionManager.java index 3f534773b..20be6bc1d 100644 --- a/src/main/java/de/dennisguse/opentracks/services/sensors/BluetoothConnectionManager.java +++ b/src/main/java/de/dennisguse/opentracks/services/sensors/BluetoothConnectionManager.java @@ -58,22 +58,37 @@ public class BluetoothConnectionManager { private SensorState sensorState; + private BluetoothGatt bluetoothGatt; + private BluetoothDevice bluetoothDevice; + private BluetoothGattCallback connectCallback = new BluetoothGattCallback() { @Override public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { - if (newState == BluetoothProfile.STATE_CONNECTED) { - gatt.discoverServices(); - setState(SensorState.CONNECTED); + switch (newState) { + case BluetoothProfile.STATE_CONNECTING: + Log.d(TAG, "Connecting to sensor: " + gatt.getDevice()); + setState(SensorState.CONNECTING); + case BluetoothProfile.STATE_CONNECTED: + Log.d(TAG, "Connected to sensor: " + gatt.getDevice()); + setState(SensorState.CONNECTED); - //Inform about status change - Message message = handler.obtainMessage(MESSAGE_DEVICE_NAME); - Bundle bundle = new Bundle(); - bundle.putString(KEY_DEVICE_NAME, gatt.getDevice().getName()); - message.setData(bundle); - handler.sendMessage(message); - return; + gatt.discoverServices(); + + //Inform about status change + Message message = handler.obtainMessage(MESSAGE_DEVICE_NAME); + Bundle bundle = new Bundle(); + bundle.putString(KEY_DEVICE_NAME, gatt.getDevice().getName()); + message.setData(bundle); + handler.sendMessage(message); + break; + case BluetoothProfile.STATE_DISCONNECTING: + Log.d(TAG, "Disconnecting from sensor: " + gatt.getDevice()); + setState(SensorState.DISCONNECTING); + + case BluetoothProfile.STATE_DISCONNECTED: + Log.d(TAG, "Disconnected from sensor: " + gatt.getDevice()); + setState(SensorState.DISCONNECTED); } - Log.d(TAG, "Could not connect to bluetooth sensor: " + gatt.getDevice()); } @Override @@ -104,45 +119,42 @@ public class BluetoothConnectionManager { * * @param handler a handler for sending messages back to the UI activity */ - BluetoothConnectionManager(Context context, Handler handler) { + BluetoothConnectionManager(@NonNull Context context, @NonNull BluetoothDevice bluetoothDevice, @NonNull Handler handler) { this.context = context; + this.bluetoothDevice = bluetoothDevice; this.handler = handler; this.sensorState = SensorState.NONE; } - /** - * Gets the sensor state. - */ + public synchronized void connect() { + if (bluetoothGatt != null) { + Log.w(TAG, "Already connected; ignoring."); + } + + Log.d(TAG, "Connecting to: " + bluetoothDevice); + + setState(SensorState.CONNECTING); + bluetoothGatt = bluetoothDevice.connectGatt(this.context, true, this.connectCallback); + } + + public synchronized void disconnect() { + if (bluetoothGatt == null) { + Log.w(TAG, "Cannot disconnect if not connected."); + return; + } + bluetoothGatt.close(); + bluetoothGatt = null; + } + + public synchronized boolean isSameBluetoothDevice(BluetoothDevice bluetoothDevice) { + return this.bluetoothDevice.equals(bluetoothDevice); + } + synchronized SensorState getSensorState() { return sensorState; } - /** - * Sets the sensor state. - * - * @param sensorState the sensor state - */ private synchronized void setState(SensorState sensorState) { this.sensorState = sensorState; } - - /** - * Resets the bluetooth connection manager. - */ - public synchronized void reset() { - //TODO Disconnect - setState(SensorState.NONE); - } - - /** - * Connects to a bluetooth device. - * - * @param bluetoothDevice the bluetooth device - */ - public synchronized void connect(BluetoothDevice bluetoothDevice) { - Log.d(TAG, "connect to: " + bluetoothDevice); - - bluetoothDevice.connectGatt(this.context, false, this.connectCallback); - setState(SensorState.CONNECTING); - } } diff --git a/src/main/java/de/dennisguse/opentracks/services/sensors/BluetoothRemoteSensorManager.java b/src/main/java/de/dennisguse/opentracks/services/sensors/BluetoothRemoteSensorManager.java index 4052fa083..edfed6733 100644 --- a/src/main/java/de/dennisguse/opentracks/services/sensors/BluetoothRemoteSensorManager.java +++ b/src/main/java/de/dennisguse/opentracks/services/sensors/BluetoothRemoteSensorManager.java @@ -23,18 +23,17 @@ import android.os.Handler; import android.os.Looper; import android.os.Message; import android.util.Log; +import android.widget.Toast; import java.util.ArrayList; import de.dennisguse.opentracks.R; import de.dennisguse.opentracks.content.sensor.SensorDataSet; -import de.dennisguse.opentracks.content.sensor.SensorState; import de.dennisguse.opentracks.util.PreferencesUtils; import de.dennisguse.opentracks.util.UnitConversions; /** * Bluetooth sensor manager. - * TODO: Handle a BluetoothGatt.STATE_DISCONNECTED * * @author Sandor Dornbush */ @@ -46,10 +45,6 @@ public class BluetoothRemoteSensorManager extends RemoteSensorManager { private final Context context; - private final BluetoothConnectionManager bluetoothConnectionManager; - - private SensorDataSet sensorDataSet = null; - // Handler that gets information back from the bluetoothConnectionManager private final Handler messageHandler = new Handler(Looper.getMainLooper()) { @Override @@ -57,6 +52,8 @@ public class BluetoothRemoteSensorManager extends RemoteSensorManager { switch (message.what) { case BluetoothConnectionManager.MESSAGE_DEVICE_NAME: String deviceName = message.getData().getString(BluetoothConnectionManager.KEY_DEVICE_NAME); + String toastMessage = context.getString(R.string.settings_sensor_connected, deviceName); + Toast.makeText(context, toastMessage, Toast.LENGTH_LONG).show(); break; case BluetoothConnectionManager.MESSAGE_READ: if (!(message.obj instanceof SensorDataSet)) { @@ -72,12 +69,14 @@ public class BluetoothRemoteSensorManager extends RemoteSensorManager { } }; + private SensorDataSet sensorDataSet = null; + private BluetoothConnectionManager bluetoothConnectionManager; + /** * @param context the context */ BluetoothRemoteSensorManager(Context context) { this.context = context; - bluetoothConnectionManager = new BluetoothConnectionManager(context, messageHandler); } private static BluetoothAdapter getDefaultBluetoothAdapter() { @@ -118,12 +117,7 @@ public class BluetoothRemoteSensorManager extends RemoteSensorManager { } @Override - public boolean isEnabled() { - return bluetoothAdapter != null && bluetoothAdapter.isEnabled(); - } - - @Override - protected void setUpChannel() { + public void startSensor() { if (!isEnabled()) { Log.w(TAG, "Bluetooth not enabled."); return; @@ -134,26 +128,37 @@ public class BluetoothRemoteSensorManager extends RemoteSensorManager { Log.w(TAG, "No bluetooth address."); return; } - Log.w(TAG, "Connecting to bluetooth address: " + address); + Log.i(TAG, "Connecting to bluetooth address: " + address); BluetoothDevice device; try { device = bluetoothAdapter.getRemoteDevice(address); } catch (IllegalArgumentException e) { - Log.d(TAG, "Unable to get remote device for: " + address, e); + Log.w(TAG, "Unable to get remote device for: " + address, e); + + String toastMessage = context.getString(R.string.sensor_not_known, address); + Toast.makeText(context, toastMessage, Toast.LENGTH_LONG).show(); + return; } - bluetoothConnectionManager.connect(device); + + stopSensor(); + + bluetoothConnectionManager = new BluetoothConnectionManager(context, device, messageHandler); + bluetoothConnectionManager.connect(); } @Override - protected void tearDownChannel() { - bluetoothConnectionManager.reset(); + public void stopSensor() { + if (bluetoothConnectionManager != null) { + bluetoothConnectionManager.disconnect(); + bluetoothConnectionManager = null; + } } @Override - public SensorState getSensorState() { - return bluetoothConnectionManager.getSensorState(); + public boolean isEnabled() { + return bluetoothAdapter != null && bluetoothAdapter.isEnabled(); } @Override diff --git a/src/main/java/de/dennisguse/opentracks/services/sensors/RemoteSensorManager.java b/src/main/java/de/dennisguse/opentracks/services/sensors/RemoteSensorManager.java index 2ef82f91d..42358a925 100644 --- a/src/main/java/de/dennisguse/opentracks/services/sensors/RemoteSensorManager.java +++ b/src/main/java/de/dennisguse/opentracks/services/sensors/RemoteSensorManager.java @@ -16,13 +16,7 @@ package de.dennisguse.opentracks.services.sensors; -import android.util.Log; - -import java.util.Timer; -import java.util.TimerTask; - import de.dennisguse.opentracks.content.sensor.SensorDataSet; -import de.dennisguse.opentracks.content.sensor.SensorState; /** * Manage the connection to a remote sensor. @@ -32,32 +26,14 @@ import de.dennisguse.opentracks.content.sensor.SensorState; public abstract class RemoteSensorManager { public static final long MAX_SENSOR_DATE_SET_AGE_MS = 5000; - public static final long MAX_SENSOR_STATE_AGE_MS = 20000; private static final String TAG = RemoteSensorManager.class.getSimpleName(); - private static final int RETRY_PERIOD_MS = 20000; - - private SensorState sensorState = SensorState.NONE; - private long sensorStateTimestamp_ms = System.currentTimeMillis(); - - private TimerTask timerTask; - private Timer timer; /** * Returns true if the sensor is enabled. */ public abstract boolean isEnabled(); - /** - * Sets up the sensor channel. - */ - protected abstract void setUpChannel(); - - /** - * Tears down the sensor channel. - */ - protected abstract void tearDownChannel(); - /** * Gets the sensor data set. */ @@ -66,61 +42,12 @@ public abstract class RemoteSensorManager { /** * Starts the sensor. */ - public void startSensor() { - setUpChannel(); - timerTask = new TimerTask() { - @Override - public void run() { - switch (getSensorState()) { - case CONNECTING: - if (System.currentTimeMillis() - sensorStateTimestamp_ms > MAX_SENSOR_STATE_AGE_MS) { - Log.i(TAG, "Retry setUpChannel"); - setUpChannel(); - } - break; - case DISCONNECTED: - setUpChannel(); - break; - default: // NONE, CONNECTED or SENDING - } - } - }; - timer = new Timer(RemoteSensorManager.class.getSimpleName()); - timer.schedule(timerTask, RETRY_PERIOD_MS, RETRY_PERIOD_MS); - } + public abstract void startSensor(); /** * Stops the sensor. */ - public void stopSensor() { - if (timerTask != null) { - timerTask.cancel(); - timerTask = null; - } - if (timer != null) { - timer.cancel(); - timer.purge(); - timer = null; - } - tearDownChannel(); - } - - /** - * Gets the sensor state. - */ - public SensorState getSensorState() { - return sensorState; - } - - /** - * Sets the sensor state. - * - * @param sensorState the sensor state - */ - public void setSensorState(SensorState sensorState) { - sensorStateTimestamp_ms = System.currentTimeMillis(); - this.sensorState = sensorState; - } + public abstract void stopSensor(); /** * Returns true if the sensor data set is valid. diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index 983abdb15..902c61e1e 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -1054,7 +1054,9 @@ limitations under the License. sending data."> Sending - + + Sensor %1$s is not known. Please check the settings. +