Template profile rewritten to use new BleManager API

This commit is contained in:
Aleksander Nowakowski
2018-05-24 15:11:35 +02:00
parent 025f4118db
commit b23eee2763
8 changed files with 287 additions and 108 deletions

View File

@@ -27,8 +27,10 @@ import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.IntentFilter; import android.content.IntentFilter;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.content.LocalBroadcastManager; import android.support.v4.content.LocalBroadcastManager;
import android.view.Menu; import android.view.Menu;
import android.view.View;
import android.widget.TextView; import android.widget.TextView;
import java.util.UUID; import java.util.UUID;
@@ -47,7 +49,7 @@ public class TemplateActivity extends BleProfileServiceReadyActivity<TemplateSer
// TODO change view references to match your need // TODO change view references to match your need
private TextView mValueView; private TextView mValueView;
private TextView mValueUnitView; private TextView mBatteryLevelView;
@Override @Override
protected void onCreateView(final Bundle savedInstanceState) { protected void onCreateView(final Bundle savedInstanceState) {
@@ -59,7 +61,9 @@ public class TemplateActivity extends BleProfileServiceReadyActivity<TemplateSer
private void setGUI() { private void setGUI() {
// TODO assign your views to fields // TODO assign your views to fields
mValueView = findViewById(R.id.value); mValueView = findViewById(R.id.value);
mValueUnitView = findViewById(R.id.value_unit); mBatteryLevelView = findViewById(R.id.battery);
findViewById(R.id.action_set_name).setOnClickListener(v -> getService().performAction("Template"));
} }
@Override @Override
@@ -77,16 +81,7 @@ public class TemplateActivity extends BleProfileServiceReadyActivity<TemplateSer
protected void setDefaultUI() { protected void setDefaultUI() {
// TODO clear your UI // TODO clear your UI
mValueView.setText(R.string.not_available_value); mValueView.setText(R.string.not_available_value);
} mBatteryLevelView.setText(R.string.not_available);
@Override
protected void onServiceBound(final TemplateService.TemplateBinder binder) {
// not used
}
@Override
protected void onServiceUnbound() {
// not used
} }
@Override @Override
@@ -133,25 +128,53 @@ public class TemplateActivity extends BleProfileServiceReadyActivity<TemplateSer
return TemplateService.class; return TemplateService.class;
} }
@Override
protected void onServiceBound(final TemplateService.TemplateBinder binder) {
// not used
}
@Override
protected void onServiceUnbound() {
// not used
}
@Override @Override
public void onServicesDiscovered(final BluetoothDevice device, final boolean optionalServicesFound) { public void onServicesDiscovered(final BluetoothDevice device, final boolean optionalServicesFound) {
// this may notify user or show some views // this may notify user or show some views
} }
private void setValueOnView(final int value) { @Override
public void onDeviceDisconnected(final BluetoothDevice device) {
super.onDeviceDisconnected(device);
mBatteryLevelView.setText(R.string.not_available);
}
// Handling updates from the device
@SuppressWarnings("unused")
private void setValueOnView(@NonNull final BluetoothDevice device, final int value) {
// TODO assign the value to a view // TODO assign the value to a view
mValueView.setText(String.valueOf(value)); mValueView.setText(String.valueOf(value));
} }
@SuppressWarnings("unused")
public void onBatteryLevelChanged(@NonNull final BluetoothDevice device, final int value) {
mBatteryLevelView.setText(getString(R.string.battery, value));
}
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override @Override
public void onReceive(final Context context, final Intent intent) { public void onReceive(final Context context, final Intent intent) {
final String action = intent.getAction(); final String action = intent.getAction();
final BluetoothDevice device = intent.getParcelableExtra(TemplateService.EXTRA_DEVICE);
if (TemplateService.BROADCAST_TEMPLATE_MEASUREMENT.equals(action)) { if (TemplateService.BROADCAST_TEMPLATE_MEASUREMENT.equals(action)) {
final int value = intent.getIntExtra(TemplateService.EXTRA_DATA, 0); final int value = intent.getIntExtra(TemplateService.EXTRA_DATA, 0);
// Update GUI // Update GUI
setValueOnView(value); setValueOnView(device, value);
} else if (TemplateService.BROADCAST_BATTERY_LEVEL.equals(action)) {
final int batteryLevel = intent.getIntExtra(TemplateService.EXTRA_BATTERY_LEVEL, 0);
// Update GUI
onBatteryLevelChanged(device, batteryLevel);
} }
} }
}; };
@@ -159,6 +182,7 @@ public class TemplateActivity extends BleProfileServiceReadyActivity<TemplateSer
private static IntentFilter makeIntentFilter() { private static IntentFilter makeIntentFilter() {
final IntentFilter intentFilter = new IntentFilter(); final IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(TemplateService.BROADCAST_TEMPLATE_MEASUREMENT); intentFilter.addAction(TemplateService.BROADCAST_TEMPLATE_MEASUREMENT);
intentFilter.addAction(TemplateService.BROADCAST_BATTERY_LEVEL);
return intentFilter; return intentFilter;
} }
} }

View File

@@ -21,34 +21,43 @@
*/ */
package no.nordicsemi.android.nrftoolbox.template; package no.nordicsemi.android.nrftoolbox.template;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt; import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic; import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattService; import android.bluetooth.BluetoothGattService;
import android.content.Context; import android.content.Context;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import java.util.Deque;
import java.util.LinkedList;
import java.util.UUID; import java.util.UUID;
import no.nordicsemi.android.ble.BleManager; import no.nordicsemi.android.ble.BleManager;
import no.nordicsemi.android.ble.Request; import no.nordicsemi.android.ble.data.Data;
import no.nordicsemi.android.log.LogContract; import no.nordicsemi.android.log.LogContract;
import no.nordicsemi.android.nrftoolbox.parser.TemplateParser; import no.nordicsemi.android.nrftoolbox.battery.BatteryManager;
import no.nordicsemi.android.nrftoolbox.template.callback.TemplateDataCallback;
/** /**
* Modify to template manager to match your requirements. * Modify to template manager to match your requirements.
* The TemplateManager extends {@link BatteryManager}, but it may easily extend {@link BleManager}
* instead if you don't need Battery Service support. If not, also modify the
* {@link TemplateManagerCallbacks} to extend {@link no.nordicsemi.android.ble.BleManagerCallbacks}
* and replace BatteryManagerGattCallback to BleManagerGattCallback in this class.
*/ */
public class TemplateManager extends BleManager<TemplateManagerCallbacks> { public class TemplateManager extends BatteryManager<TemplateManagerCallbacks> {
private static final String TAG = "TemplateManager"; // TODO Replace the services and characteristics below to match your device.
/** The service UUID */ /** The service UUID */
public final static UUID SERVICE_UUID = UUID.fromString("0000180D-0000-1000-8000-00805f9b34fb"); // TODO change the UUID to your match your service static final UUID SERVICE_UUID = UUID.fromString("0000180D-0000-1000-8000-00805f9b34fb"); // Heart Rate service
/** The characteristic UUID */ /** A UUID of a characteristic with notify property */
private static final UUID MEASUREMENT_CHARACTERISTIC_UUID = UUID.fromString("00002A37-0000-1000-8000-00805f9b34fb"); // TODO change the UUID to your match your characteristic private static final UUID MEASUREMENT_CHARACTERISTIC_UUID = UUID.fromString("00002A37-0000-1000-8000-00805f9b34fb"); // Heart Rate Measurement
/** A UUID of a characteristic with read property */
private static final UUID READABLE_CHARACTERISTIC_UUID = UUID.fromString("00002A38-0000-1000-8000-00805f9b34fb"); // Body Sensor Location
/** Some other service UUID */
private static final UUID OTHER_SERVICE_UUID = UUID.fromString("00001800-0000-1000-8000-00805f9b34fb"); // Generic Access service
/** A UUID of a characteristic with write property */
private static final UUID WRITABLE_CHARACTERISTIC_UUID = UUID.fromString("00002A00-0000-1000-8000-00805f9b34fb"); // Device Name
// TODO add more services and characteristics, if required // TODO Add more services and characteristics references.
private BluetoothGattCharacteristic mCharacteristic; private BluetoothGattCharacteristic mRequiredCharacteristic, mDeviceNameCharacteristic, mOptionalCharacteristic;
public TemplateManager(final Context context) { public TemplateManager(final Context context) {
super(context); super(context);
@@ -56,83 +65,147 @@ public class TemplateManager extends BleManager<TemplateManagerCallbacks> {
@NonNull @NonNull
@Override @Override
protected BleManagerGattCallback getGattCallback() { protected BatteryManagerGattCallback getGattCallback() {
return mGattCallback; return mGattCallback;
} }
/** /**
* BluetoothGatt callbacks for connection/disconnection, service discovery, receiving indication, etc * BluetoothGatt callbacks for connection/disconnection, service discovery, receiving indication, etc
*/ */
private final BleManagerGattCallback mGattCallback = new BleManagerGattCallback() { private final BatteryManagerGattCallback mGattCallback = new BatteryManagerGattCallback() {
@Override @Override
protected Deque<Request> initGatt(@NonNull final BluetoothGatt gatt) { protected void initialize() {
final LinkedList<Request> requests = new LinkedList<>(); // Initialize the Battery Manager. It will enable Battery Level notifications.
// TODO initialize your device, enable required notifications and indications, write what needs to be written to start working // Remove it if you don't need this feature.
requests.add(Request.newEnableNotificationsRequest(mCharacteristic)); super.initialize();
return requests;
// TODO Initialize your manager here.
// Initialization is done once, after the device is connected. Usually it should
// enable notifications or indications on some characteristics, write some data or
// read some features / version.
// After the initialization is complete, the onDeviceReady(...) method will be called.
// Increase the MTU
requestMtu(43)
.with((device, mtu) -> log(LogContract.Log.Level.APPLICATION, "MTU changed to " + mtu))
.done(device -> {
// You may do some logic in here that should be done when the request finished successfully.
// In case of MTU this method is called also when the MTU hasn't changed, or has changed
// to a different (lower) value. Use .with(...) to get the MTU value.
})
.fail((device, status) -> log(LogContract.Log.Level.WARNING, "MTU change not supported"));
// Set notification callback
setNotificationCallback(mRequiredCharacteristic)
// This callback will be called each time the notification is received
.with(new TemplateDataCallback() {
@Override
public void onSampleValueReceived(@NonNull final BluetoothDevice device, final int value) {
// Let's lass received data to the service
mCallbacks.onSampleValueReceived(device, value);
}
@Override
public void onInvalidDataReceived(@NonNull final BluetoothDevice device, @NonNull final Data data) {
log(LogContract.Log.Level.WARNING, "Invalid data received: " + data);
}
});
// Enable notifications
enableNotifications(mRequiredCharacteristic)
// Method called after the data were sent (data will contain 0x0100 in this case)
.with((device, data) -> log(LogContract.Log.Level.DEBUG, "Data sent: " + data))
// Method called when the request finished successfully. This will be called after .with(..) callback
.done(device -> log(LogContract.Log.Level.APPLICATION, "Notifications enabled successfully"))
// Methods called in case of an error, for example when the characteristic does not have Notify property
.fail((device, status) -> log(LogContract.Log.Level.WARNING, "Failed to enable notifications"));
} }
@Override @Override
protected boolean isRequiredServiceSupported(@NonNull final BluetoothGatt gatt) { protected boolean isRequiredServiceSupported(@NonNull final BluetoothGatt gatt) {
// TODO Initialize required characteristics.
// It should return true if all has been discovered (that is that device is supported).
final BluetoothGattService service = gatt.getService(SERVICE_UUID); final BluetoothGattService service = gatt.getService(SERVICE_UUID);
if (service != null) { if (service != null) {
mCharacteristic = service.getCharacteristic(MEASUREMENT_CHARACTERISTIC_UUID); mRequiredCharacteristic = service.getCharacteristic(MEASUREMENT_CHARACTERISTIC_UUID);
} }
return mCharacteristic != null; final BluetoothGattService otherService = gatt.getService(OTHER_SERVICE_UUID);
if (otherService != null) {
mDeviceNameCharacteristic = otherService.getCharacteristic(WRITABLE_CHARACTERISTIC_UUID);
}
return mRequiredCharacteristic != null && mDeviceNameCharacteristic != null;
}
@Override
protected boolean isOptionalServiceSupported(@NonNull final BluetoothGatt gatt) {
// Initialize Battery characteristic
super.isOptionalServiceSupported(gatt);
// TODO If there are some optional characteristics, initialize them there.
final BluetoothGattService service = gatt.getService(SERVICE_UUID);
if (service != null) {
mOptionalCharacteristic = service.getCharacteristic(READABLE_CHARACTERISTIC_UUID);
}
return mOptionalCharacteristic != null;
} }
@Override @Override
protected void onDeviceDisconnected() { protected void onDeviceDisconnected() {
mCharacteristic = null; // Release Battery Service
} super.onDeviceDisconnected();
// TODO implement data handlers. Methods below are called after the initialization is complete. // TODO Release references to your characteristics.
mRequiredCharacteristic = null;
mDeviceNameCharacteristic = null;
mOptionalCharacteristic = null;
}
@Override @Override
protected void onDeviceReady() { protected void onDeviceReady() {
super.onDeviceReady(); super.onDeviceReady();
// TODO initialization is now ready. The activity is being notified using TemplateManagerCallbacks#onDeviceReady() method. // Initialization is now ready.
// This method may be removed from this class if not required as the super class implementation handles this event. // The service or activity has been notified with TemplateManagerCallbacks#onDeviceReady().
} // TODO Do some extra logic here, of remove onDeviceReady().
@Override // Device is ready, let's read something here. Usually there is nothing else to be done
protected void onCharacteristicNotified(@NonNull final BluetoothGatt gatt, @NonNull final BluetoothGattCharacteristic characteristic) { // here, as all had been done during initialization.
// TODO this method is called when a notification has been received readCharacteristic(mOptionalCharacteristic)
// This method may be removed from this class if not required .with((device, data) -> {
// Characteristic value has been read
log(LogContract.Log.Level.APPLICATION, "\"" + TemplateParser.parse(characteristic) + "\" received"); // Let's do some magic with it.
if (data.size() > 0) {
int value; final Integer value = data.getIntValue(Data.FORMAT_UINT8, 0);
final int flags = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, 0); log(LogContract.Log.Level.APPLICATION, "Value '" + value + "' has been read!");
if ((flags & 0x01) > 0) { } else {
value = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT16, 1); log(LogContract.Log.Level.WARNING, "Value is empty!");
} else { }
value = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, 1); });
}
//This will send callback to the Activity when new value is received from HR device
mCallbacks.onSampleValueReceived(gatt.getDevice(), value);
}
@Override
protected void onCharacteristicIndicated(@NonNull final BluetoothGatt gatt, @NonNull final BluetoothGattCharacteristic characteristic) {
// TODO this method is called when an indication has been received
// This method may be removed from this class if not required
}
@Override
protected void onCharacteristicRead(@NonNull final BluetoothGatt gatt, @NonNull final BluetoothGattCharacteristic characteristic) {
// TODO this method is called when the characteristic has been read
// This method may be removed from this class if not required
}
@Override
protected void onCharacteristicWrite(@NonNull final BluetoothGatt gatt, @NonNull final BluetoothGattCharacteristic characteristic) {
// TODO this method is called when the characteristic has been written
// This method may be removed from this class if not required
} }
}; };
// TODO Define manager's API
/**
* This method will write important data to the device.
*
* @param parameter parameter to be written.
*/
void performAction(final String parameter) {
log(LogContract.Log.Level.VERBOSE, "Changing device name to \"" + parameter + "\"");
// Write some data to the characteristic.
writeCharacteristic(mDeviceNameCharacteristic, Data.from(parameter))
// If data are longer than MTU-3, they will be chunked into multiple packets.
// Check out other split options, with .split(...).
.split()
// Callback called when data were sent, or added to outgoing queue is Write Without Request
// type has been chosen.
.with((device, data) -> log(LogContract.Log.Level.DEBUG, data.size() + " bytes were sent"))
// Callback called when data were sent, or added to outgoing queue is Write Without Request
// type has been chosen.
.done(device -> log(LogContract.Log.Level.APPLICATION, "Device name set to \"" + parameter + "\""))
// Callback called when write has failed.
.fail((device, status) -> log(LogContract.Log.Level.WARNING, "Failed to change device name"));
}
} }

View File

@@ -21,24 +21,18 @@
*/ */
package no.nordicsemi.android.nrftoolbox.template; package no.nordicsemi.android.nrftoolbox.template;
import android.bluetooth.BluetoothDevice; import no.nordicsemi.android.nrftoolbox.battery.BatteryManagerCallbacks;
import no.nordicsemi.android.nrftoolbox.template.callback.TemplateCharacteristicCallback;
import no.nordicsemi.android.ble.BleManagerCallbacks;
/** /**
* Interface {@link TemplateManagerCallbacks} must be implemented by {@link TemplateActivity} in order to receive callbacks from {@link TemplateManager} * Interface {@link TemplateManagerCallbacks} must be implemented by {@link TemplateService}
* in order to receive callbacks from {@link TemplateManager}
*/ */
public interface TemplateManagerCallbacks extends BleManagerCallbacks { interface TemplateManagerCallbacks extends BatteryManagerCallbacks, TemplateCharacteristicCallback {
// TODO add more callbacks. Callbacks are called when a data has been received/written to a remote device. This is the way how the manager notifies the activity about this event. // Callbacks are called when a data has been received/written to a remote device.
// This is the way how the manager notifies the activity about this event.
/**
* Called when a value is received.
*
* @param device a device from which the value was obtained
* @param value
* the new value
*/
void onSampleValueReceived(final BluetoothDevice device, int value);
// TODO add more callbacks.
// If you need, create more ...Callback interfaces and extend this interface with them.
} }

View File

@@ -30,6 +30,7 @@ import android.content.BroadcastReceiver;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.IntentFilter; import android.content.IntentFilter;
import android.support.annotation.NonNull;
import android.support.v4.app.NotificationCompat; import android.support.v4.app.NotificationCompat;
import android.support.v4.content.LocalBroadcastManager; import android.support.v4.content.LocalBroadcastManager;
@@ -44,6 +45,9 @@ public class TemplateService extends BleProfileService implements TemplateManage
public static final String BROADCAST_TEMPLATE_MEASUREMENT = "no.nordicsemi.android.nrftoolbox.template.BROADCAST_MEASUREMENT"; public static final String BROADCAST_TEMPLATE_MEASUREMENT = "no.nordicsemi.android.nrftoolbox.template.BROADCAST_MEASUREMENT";
public static final String EXTRA_DATA = "no.nordicsemi.android.nrftoolbox.template.EXTRA_DATA"; public static final String EXTRA_DATA = "no.nordicsemi.android.nrftoolbox.template.EXTRA_DATA";
public static final String BROADCAST_BATTERY_LEVEL = "no.nordicsemi.android.nrftoolbox.BROADCAST_BATTERY_LEVEL";
public static final String EXTRA_BATTERY_LEVEL = "no.nordicsemi.android.nrftoolbox.EXTRA_BATTERY_LEVEL";
private final static String ACTION_DISCONNECT = "no.nordicsemi.android.nrftoolbox.template.ACTION_DISCONNECT"; private final static String ACTION_DISCONNECT = "no.nordicsemi.android.nrftoolbox.template.ACTION_DISCONNECT";
private final static int NOTIFICATION_ID = 864; private final static int NOTIFICATION_ID = 864;
@@ -55,16 +59,19 @@ public class TemplateService extends BleProfileService implements TemplateManage
private final LocalBinder mBinder = new TemplateBinder(); private final LocalBinder mBinder = new TemplateBinder();
/** /**
* This local binder is an interface for the bonded activity to operate with the HTS sensor * This local binder is an interface for the bound activity to operate with the sensor.
*/ */
public class TemplateBinder extends LocalBinder { class TemplateBinder extends LocalBinder {
// empty // TODO Define service API that may be used by a bound Activity
// TODO add some service API that mey be used from the Activity
// public void setLights(final boolean on) { /**
// Logger.v(getLogSession(), "Light set to: " + on); * Sends some important data to the device.
// mManager.setLights(on); *
// } * @param parameter some parameter.
*/
public void performAction(final String parameter) {
mManager.performAction(parameter);
}
} }
@Override @Override
@@ -108,7 +115,7 @@ public class TemplateService extends BleProfileService implements TemplateManage
} }
@Override @Override
public void onSampleValueReceived(final BluetoothDevice device, final int value) { public void onSampleValueReceived(@NonNull final BluetoothDevice device, final int value) {
final Intent broadcast = new Intent(BROADCAST_TEMPLATE_MEASUREMENT); final Intent broadcast = new Intent(BROADCAST_TEMPLATE_MEASUREMENT);
broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice()); broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice());
broadcast.putExtra(EXTRA_DATA, value); broadcast.putExtra(EXTRA_DATA, value);
@@ -120,14 +127,17 @@ public class TemplateService extends BleProfileService implements TemplateManage
} }
} }
@Override
public void onBatteryLevelChanged(@NonNull final BluetoothDevice device, final int batteryLevel) {
}
/** /**
* Creates the notification * Creates the notification.
* *
* @param messageResId * @param messageResId message resource id. The message must have one String parameter,<br />
* message resource id. The message must have one String parameter,<br /> * f.e. <code>&lt;string name="name"&gt;%s is connected&lt;/string&gt;</code>
* f.e. <code>&lt;string name="name"&gt;%s is connected&lt;/string&gt;</code> * @param defaults signals that will be used to notify the user
* @param defaults
* signals that will be used to notify the user
*/ */
private void createNotification(final int messageResId, final int defaults) { private void createNotification(final int messageResId, final int defaults) {
final Intent parentIntent = new Intent(this, FeaturesActivity.class); final Intent parentIntent = new Intent(this, FeaturesActivity.class);
@@ -138,7 +148,7 @@ public class TemplateService extends BleProfileService implements TemplateManage
final PendingIntent disconnectAction = PendingIntent.getBroadcast(this, DISCONNECT_REQ, disconnect, PendingIntent.FLAG_UPDATE_CURRENT); final PendingIntent disconnectAction = PendingIntent.getBroadcast(this, DISCONNECT_REQ, disconnect, PendingIntent.FLAG_UPDATE_CURRENT);
// both activities above have launchMode="singleTask" in the AndroidManifest.xml file, so if the task is already running, it will be resumed // both activities above have launchMode="singleTask" in the AndroidManifest.xml file, so if the task is already running, it will be resumed
final PendingIntent pendingIntent = PendingIntent.getActivities(this, OPEN_ACTIVITY_REQ, new Intent[] { parentIntent, targetIntent }, PendingIntent.FLAG_UPDATE_CURRENT); final PendingIntent pendingIntent = PendingIntent.getActivities(this, OPEN_ACTIVITY_REQ, new Intent[]{parentIntent, targetIntent}, PendingIntent.FLAG_UPDATE_CURRENT);
final NotificationCompat.Builder builder = new NotificationCompat.Builder(this, ToolboxApplication.CONNECTED_DEVICE_CHANNEL); final NotificationCompat.Builder builder = new NotificationCompat.Builder(this, ToolboxApplication.CONNECTED_DEVICE_CHANNEL);
builder.setContentIntent(pendingIntent); builder.setContentIntent(pendingIntent);
builder.setContentTitle(getString(R.string.app_name)).setContentText(getString(messageResId, getDeviceName())); builder.setContentTitle(getString(R.string.app_name)).setContentText(getString(messageResId, getDeviceName()));
@@ -172,5 +182,4 @@ public class TemplateService extends BleProfileService implements TemplateManage
stopSelf(); stopSelf();
} }
}; };
} }

View File

@@ -0,0 +1,21 @@
package no.nordicsemi.android.nrftoolbox.template.callback;
import android.bluetooth.BluetoothDevice;
import android.support.annotation.NonNull;
/**
* This class defines your characteristic API.
* In this example (that is the HRM characteristic, which the template is based on), is notifying
* with a value (Heart Rate). The single method just returns the value and ignores other
* optional data from Heart Rate Measurement characteristic for simplicity.
*/
public interface TemplateCharacteristicCallback {
/**
* Called when a value is received.
*
* @param device a device from which the value was obtained.
* @param value the new value.
*/
void onSampleValueReceived(@NonNull final BluetoothDevice device, int value);
}

View File

@@ -0,0 +1,47 @@
package no.nordicsemi.android.nrftoolbox.template.callback;
import android.bluetooth.BluetoothDevice;
import android.support.annotation.NonNull;
import no.nordicsemi.android.ble.callback.profile.ProfileDataCallback;
import no.nordicsemi.android.ble.data.Data;
/**
* This is a sample data callback, that's based on Heart Rate Measurement characteristic.
* It parses the HR value and ignores other optional data for simplicity.
* Check {@link no.nordicsemi.android.ble.common.callback.hr.HeartRateMeasurementDataCallback}
* for full implementation.
*
* TODO Modify the content to parse your data.
*/
@SuppressWarnings("ConstantConditions")
public abstract class TemplateDataCallback implements ProfileDataCallback, TemplateCharacteristicCallback {
@Override
public void onDataReceived(@NonNull final BluetoothDevice device, @NonNull final Data data) {
if (data.size() < 2) {
onInvalidDataReceived(device, data);
return;
}
// Read flags
int offset = 0;
final int flags = data.getIntValue(Data.FORMAT_UINT8, offset);
final int hearRateType = (flags & 0x01) == 0 ? Data.FORMAT_UINT8 : Data.FORMAT_UINT16;
offset += 1;
// Validate packet length. The type's lower nibble is its length.
if (data.size() < 1 + (hearRateType & 0x0F)) {
onInvalidDataReceived(device, data);
return;
}
final int value = data.getIntValue(hearRateType, offset);
// offset += hearRateType & 0xF;
// ...
// Report the parsed value(s)
onSampleValueReceived(device, value);
}
}

View File

@@ -79,6 +79,7 @@
<!-- Application section --> <!-- Application section -->
<LinearLayout <LinearLayout
android:id="@+id/container"
style="@style/Widget.List" style="@style/Widget.List"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@@ -131,6 +132,15 @@
</TableLayout> </TableLayout>
</LinearLayout> </LinearLayout>
<Button
android:id="@+id/action_set_name"
style="@style/Widget.AppCompat.Button.Colored"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_below="@+id/container"
android:text="@string/template_action"/>
<Button <Button
android:id="@+id/action_connect" android:id="@+id/action_connect"
style="@style/Widget.Connect" style="@style/Widget.Connect"

View File

@@ -31,6 +31,7 @@
<string name="template_section_header">Values</string> <string name="template_section_header">Values</string>
<string name="template_value_title">Value</string> <string name="template_value_title">Value</string>
<string name="template_unit_bpm">bpm</string> <string name="template_unit_bpm">bpm</string>
<string name="template_action">An action</string>
<string name="template_notification_action_disconnect">Disconnect</string> <string name="template_notification_action_disconnect">Disconnect</string>
<string name="template_notification_connected_message">%s is connected.</string> <string name="template_notification_connected_message">%s is connected.</string>