Skip to content

Commit

Permalink
Template profile added
Browse files Browse the repository at this point in the history
  • Loading branch information
philips77 committed Apr 16, 2015
1 parent f274ce7 commit 29b35d4
Show file tree
Hide file tree
Showing 18 changed files with 994 additions and 6 deletions.
4 changes: 2 additions & 2 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ android {
applicationId "no.nordicsemi.android.nrftoolbox"
minSdkVersion 18
targetSdkVersion 22
versionCode 30
versionName "1.12.1"
versionCode 31
versionName "1.13.0"
}
buildTypes {
release {
Expand Down
24 changes: 22 additions & 2 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="no.nordicsemi.android.nrftoolbox"
android:installLocation="auto"
android:versionCode="30"
android:versionName="1.12.1" >
android:versionCode="31"
android:versionName="1.13.0" >

<uses-sdk
android:minSdkVersion="18"
Expand Down Expand Up @@ -59,6 +59,26 @@
android:label="@string/app_name"
android:launchMode="singleTask" >
</activity>

<!-- Template plugin activities -->
<!-- Remember to add your plug-in Activities to the Android Manifest file. -->
<activity
android:name="no.nordicsemi.android.nrftoolbox.template.TemplateActivity"
android:icon="@drawable/ic_template_feature"
android:label="@string/template_feature_title" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="no.nordicsemi.android.nrftoolbox.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="no.nordicsemi.android.nrftoolbox.template.settings.SettingsActivity"
android:label="@string/template_settings_title" />
<service
android:name="no.nordicsemi.android.nrftoolbox.template.TemplateService"
android:label="@string/template_feature_title" />

<!-- Plug-in activities -->
<activity
android:name="no.nordicsemi.android.nrftoolbox.dfu.DfuActivity"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* Copyright (c) 2015, Nordic Semiconductor
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package no.nordicsemi.android.nrftoolbox.parser;

import android.bluetooth.BluetoothGattCharacteristic;

import java.util.ArrayList;
import java.util.List;

// TODO this method may be used for developing purposes to log the data from your device using the nRF Logger application.
public class TemplateParser {
// TODO add some flags, if needed
private static final byte HEART_RATE_VALUE_FORMAT = 0x01; // 1 bit

/**
* This method converts the value of the characteristic to the String. The String is then logged in the nRF logger log session
* @param characteristic the characteristic to be parsed
* @return human readable value of the characteristic
*/
public static String parse(final BluetoothGattCharacteristic characteristic) {
int offset = 0;
final int flags = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, offset++);

/*
* In the template we are using the HRM values as an example.
* false Heart Rate Value Format is set to UINT8. Units: beats per minute (bpm)
* true Heart Rate Value Format is set to UINT16. Units: beats per minute (bpm)
*/
final boolean value16bit = (flags & HEART_RATE_VALUE_FORMAT) > 0;

// heart rate value is 8 or 16 bit long
int value = characteristic.getIntValue(value16bit ? BluetoothGattCharacteristic.FORMAT_UINT16 : BluetoothGattCharacteristic.FORMAT_UINT8, offset++); // bits per minute
if (value16bit)
offset++;

// TODO parse more data

final StringBuilder builder = new StringBuilder();
builder.append("Template Measurement: ").append(value).append(" bpm");
return builder.toString();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
* Copyright (c) 2015, Nordic Semiconductor
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

nRF Toolbox demonstrates how to implement the Bluetooth Smart features in an Android application.
It consists of number of profiles, like Heart Rate, Blood Pressure etc. that may be use as is to communicate with real devices.
They use the Bluetooth SIG adopted profiles, that may be found here: https://developer.bluetooth.org/gatt/profiles/Pages/ProfilesHome.aspx

The Template Profile has been created to give a quick start with implementing proprietary services. Just start modifying 4 classes inside
the template package to implement features you need.

Below you will find a short step-by-step tutorial:

1. The template consists of the following files:
- TemplateActivity - the main class that is responsible for managing the view of your profile
- TemplateService - the service that is started whenever you connect to a device. I handles the Bluetooth Smart communication using the...
- TemplateManager - the manager that handles all the BLE logic required to communicate with the device. The TemplateManager derives from
the BleManager which handles most of the event itself and propagates the data-relevant to deriving class. You don't
have to, or even shouldn't modify the BleManager (unless you want to change the default behaviour).
- TemplateManagerCallbacks - the interface with a list of callbacks that the TemplateManager can call. Each method is usually related to one
BLE event, e.g. receiving a new value of the characteristic.\
- TemplateParser - an optional class in the .parser package that is responsible for converting the characteristic value to String.
This is used only for debugging. The String returned by the parse(..) method is then logged into the nRF Logger application
(if such installed).
- /settings/SettingsActivity and /settings/SettingsFragment - classes used to present user preferences. A stub implementation in the template.
- /res/layout/activity_feature_template.xml - the layout file for the TemplateActivity
- /res/values/strings_template.xml - a set of strings used in the layout file
- /res/xml/settings/template.xml - the user settings configuration
- /res/drawable/(x)hdpi/ic_template_feature.png - the template profile icon (HDPI, XHDPI). Please, keep the files size.
- /res/drawable/(x)hdpi/ic_stat_notify_template - the icon that is used in the notification

2. The communication between the components goes as follows:
- User clicks the CONNECT button and selects a target device on TemplateActivity.
- The base class of the TemplateActivity starts the service given by getServiceClass() method.
- The service starts and initializes the TemplateManager. TemplateActivity binds to the service and is being given the TemplateBinder object (the service API) as a result.
- The manager connects to the device using Bluetooth Smart and discovers its services.
- The manager initializes the device. Initialization is done using the list of actions given by the initGatt(..) method in the TemplateManager.
Initialization usually contains enabling notifications, writing some initial values etc.
- When initialization is complete the manager calls the onDeviceReady() callback.
- The service sends the BROADCAST_DEVICE_READY broadcast to the activity. Communication from the Service to the Activity is always done using the LocalBroadcastManager broadcasts.
- The base class of the TemplateActivity listens to the broadcasts and calls appropriate methods.

- When a custom event occurs, for example a notification is received, the manager parses the incoming data and calls the proper callback.
- The callback implementation in the TemplateService sends a broadcast message with values given in parameters.
- The TemplateActivity, which had registered a broadcast receiver before, listens to the broadcasts, reads the values and present them to users.

- Communication Activity->Service is done using the API in the TemplateBinder. You may find the example of how to use it in the ProximityActivity.

3. Please read the files listed above and the TODO messages for more information what to modify in the files.

4. Remember to add your activities and the service in the AndroidManifest.xml file. The nRF Toolbox lists all activities with the following intent filter:
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="no.nordicsemi.android.nrftoolbox.LAUNCHER" />
</intent-filter>

5. Feel free to rename the nRF Toolbox application (/res/values/strings.xml ->app_name), change the toolbar colors (/res/values/color.xml -> actionBarColor, actionBarColorDark).
In order to remove unused profiles from the main FeaturesActivity just comment out their intent-filter tags in the AndroidManifest.xml file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
/*
* Copyright (c) 2015, Nordic Semiconductor
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package no.nordicsemi.android.nrftoolbox.template;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.support.v4.content.LocalBroadcastManager;
import android.view.Menu;
import android.widget.TextView;

import java.util.UUID;

import no.nordicsemi.android.nrftoolbox.R;
import no.nordicsemi.android.nrftoolbox.profile.BleProfileService;
import no.nordicsemi.android.nrftoolbox.profile.BleProfileServiceReadyActivity;
import no.nordicsemi.android.nrftoolbox.template.settings.SettingsActivity;

/**
* Modify the Template Activity to match your needs.
*/
public class TemplateActivity extends BleProfileServiceReadyActivity<TemplateService.TemplateBinder> {
@SuppressWarnings("unused")
private final String TAG = "TemplateActivity";

// TODO change view references to match your need
private TextView mValueView;
private TextView mValueUnitView;

@Override
protected void onCreateView(final Bundle savedInstanceState) {
// TODO modify the layout file(s). By default the activity shows only one field - the Heart Rate value as a sample
setContentView(R.layout.activity_feature_template);
setGUI();
}

private void setGUI() {
// TODO assign your views to fields
mValueView = (TextView) findViewById(R.id.value);
mValueUnitView = (TextView) findViewById(R.id.value_unit);
}

@Override
protected void onInitialize(final Bundle savedInstanceState) {
LocalBroadcastManager.getInstance(this).registerReceiver(mBroadcastReceiver, makeIntentFilter());
}

@Override
protected void onDestroy() {
super.onDestroy();
LocalBroadcastManager.getInstance(this).unregisterReceiver(mBroadcastReceiver);
}

@Override
protected void setDefaultUI() {
// TODO clear your UI
mValueView.setText(R.string.not_available_value);
}

@Override
protected void onServiceBinded(final TemplateService.TemplateBinder binder) {
// not used
}

@Override
protected void onServiceUnbinded() {
// not used
}

@Override
protected int getLoggerProfileTitle() {
return R.string.template_feature_title;
}

@Override
protected int getAboutTextId() {
return R.string.template_about_text;
}

@Override
public boolean onCreateOptionsMenu(final Menu menu) {
getMenuInflater().inflate(R.menu.settings_and_about, menu);
return true;
}

@Override
protected boolean onOptionsItemSelected(final int itemId) {
switch (itemId) {
case R.id.action_settings:
final Intent intent = new Intent(this, SettingsActivity.class);
startActivity(intent);
break;
}
return true;
}

@Override
protected int getDefaultDeviceName() {
return R.string.template_default_name;
}

@Override
protected UUID getFilterUUID() {
// TODO this method may return the UUID of the service that is required to be in the advertisement packet of a device in order to be listed on the Scanner dialog.
// If null is returned no filtering is done.
return TemplateManager.SERVICE_UUID;
}

@Override
protected Class<? extends BleProfileService> getServiceClass() {
return TemplateService.class;
}

@Override
public void onServicesDiscovered(boolean optionalServicesFound) {
// this may notify user or show some views
}

private void setValueOnView(final int value) {
// TODO assign the value to a view
mValueView.setText(String.valueOf(value));
}

private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(final Context context, final Intent intent) {
final String action = intent.getAction();

if (TemplateService.BROADCAST_TEMPLATE_MEASUREMENT.equals(action)) {
final int value = intent.getIntExtra(TemplateService.EXTRA_DATA, 0);
// Update GUI
setValueOnView(value);
}
}
};

private static IntentFilter makeIntentFilter() {
final IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(TemplateService.BROADCAST_TEMPLATE_MEASUREMENT);
return intentFilter;
}
}
Loading

0 comments on commit 29b35d4

Please sign in to comment.