Introduction

This document describes how to build an app to interact with external devices to the smartphone, using SAndroidE framework.

The set up is composed by the following SAndroidE compatible devices:

The goal of the application is the development of an alarm button system. The system is composed by two equal Texal devices supporting the same general pourpose firmware distributed by the manufacturer (the firmware which gives access to the BLE resources) and an Android smartphone (Samsung S5-mini). Each device has two buttons and an alarm. The final result of this example will be: pressing buttons on device A will start/stop alarm on device B and viceversa, each click of the buttons raises the related counter of the app's UI.

keyfob.jpg

keyfob.jpg

# Requirements
1. two CC2541 devices 1. a smartphone supporting Bluetooth 4.0-4.1 (aka Bluetooth Smart) 1. a micro USB cable to deploy application to your smartphone, or alternatively ADB wifi Android app to deploy over wireless connection 1. Android Studio 1. SAndroidE zip package: download the zip file and extract to a directory 1. basic programming knowledge of Android applications

Usage

Implementation consists of three steps:

  1. devices firmware flashing (if needed)
  2. enumerating the resources provided by external devices we want to interact with
  3. developing an Android app which exploits the SAndrodE framework to implement the desired application logic
## Firmware flashing
The first step is to flash a Sandroide compatible firmware to the two external devices. As previously said, the firmware is not specific for the application, but if is generic provided within respective development kits. SAndroidE framework handles the the remote devices resources exploiting the description provided by the xml files. How to describe a new device/firmware is described here.
This step may be not needed if you know the firmware installed in the device is already a supported one.
In order to flash the firmware on the device, connect the device to the programmer provided by the manufacturer (CC Debugger) and the programmer to the smartphone via USB, using a micro USB-OTG cable. Flashing is performed using the BLEEmbeddedFlasher.apk Android application provided with the SAndroidE zip file, which must installed to the smartphone using the provided apk.
flashing.jpg
flashing-texas.jpg

Enumerating resources

The resources available on each device shall be enumerated, giving a unique id to each one, which gives the pointer to access at the resources by the framework.

Resource enumeration requires to have the right xml description files within the home of our smartphone internal storage. These files act like a database of the supported devices: describing features and resources available for each device and how to interact with them. VERY IMPORTANT: withouth these files enumeration of resources and the following steps won't be possible: the BLEEmbeddedFlasher app would find some devices near but would never know how to interact with their resources.

xml-files-to-device-int-storage-600px.jpg

xml-files-to-device-int-storage-600px.jpg

Mandatory files to include are: devices.xml, bledeviceparsers.xml and bledataclustermodels.xml. If beacon support is desired, then bleparsers.xml is needed too. Example of these files can be found in the SandroidE zip package.

Now we can start the BLEEmbeddedFlasher app to enumerate devices resources.

addressing-resources.jpg

addressing-resources.jpg

In order to pair the device with the smartphone, we need first to make it discoverable, and then following the instruction in the figures below, to find and giving it a unique name.

NOTE: If the devices is supported/described as previously described the BLE services and attributes will be shown after the connection with the remote device.

NOTE: To enable the bluetooth advertising mode on Texas devices press once the button labeled as B3 on the PCB.

In this example the devices are named respectively bellA and bellB.

enumerating-bellA.jpg

enumerating-bellA.jpg

enumerating-bellB.jpg

enumerating-bellB.jpg

The configuration procedure aims to populate the bleresources.xml, the BLEEmbeddedFlasher application automatically adds them to a file. This dinamically generated file, together with previously mentioned Configuration Files, are needed by the app developed in next step. In case the file already exist (reporting the information of the required devices), because the configuration procedure was previously done, there would be no need to repeate this procedure.

App development

First of all install Android Studio, the official development environment to develop Android apps.

Creating the project

Start creating a project, with an empty activity, supporting the latest Android version.

create-project-1.jpg
create-project-2.jpg
create-project-3.jpg
create-project-4.jpg
create-project-5.jpg

Sandroide Library inclusion

Copy the SAndroidE.aar file from the zip to your app's libs folder.

lib-inclusion-1.jpg

lib-inclusion-1.jpg

lib-inclusion-2.jpg

lib-inclusion-2.jpg

Then add the following lines into your app's build.gradle file and click on Sync now to include the library into your project.

#!java
                                    allprojects {
                                        repositories {
                                            jcenter()
                                            flatDir {
                                                dirs 'libs'
                                            }
                                        }
                                    }

                                    dependencies {
                                        compile(name:'SAndroidE', ext:'aar')
                                    }

Your build.gradle should resemble like the one in the figure below:

lib-inclusion-4.jpg

lib-inclusion-4.jpg

Now the application has access to SAndroidE library classes.

NOTE: SAndroidE is currently provided as .aar Android library file, instead of the common Java library format (.jar), to let your app automatically inherit all the permissions required by SAndroidE framework for working correctly with your devices.


Writing the app

App's layout

The application layout is created by editing the file res/layout/activity_main.xml.

dev-layout-1.jpg

dev-layout-1.jpg

The simple layout shown in figure above may be obtained by switching from Design to Text tab in Android Studio IDE and entering the following XML code:

#!xml
                                        <?xml version="1.0" encoding="utf-8"?>
                                        <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                                        xmlns:tools="http://schemas.android.com/tools"
                                        android:layout_width="match_parent"
                                        android:layout_height="match_parent"
                                        android:paddingBottom="@dimen/activity_vertical_margin"
                                        android:paddingLeft="@dimen/activity_horizontal_margin"
                                        android:paddingRight="@dimen/activity_horizontal_margin"
                                        android:paddingTop="@dimen/activity_vertical_margin"
                                        tools:context="com.example.my.testbuttonincrement.MainActivity">


                                        <TextView
                                        android:layout_width="wrap_content"
                                        android:layout_height="wrap_content"
                                        android:text="Clicks A:"
                                        android:id="@+id/textView"
                                        android:layout_alignParentTop="true"
                                        android:layout_alignParentStart="true"
                                        android:textSize="20pt" />

                                        <TextView
                                        android:layout_width="wrap_content"
                                        android:layout_height="wrap_content"
                                        android:text="-1"
                                        android:id="@+id/tvA"
                                        android:layout_alignParentTop="true"
                                        android:layout_alignParentEnd="true"
                                        android:textSize="20pt" />

                                        <TextView
                                        android:layout_width="wrap_content"
                                        android:layout_height="wrap_content"
                                        android:text="Clicks B:"
                                        android:id="@+id/textView3"
                                        android:layout_centerVertical="true"
                                        android:layout_alignParentStart="true"
                                        android:textSize="20pt" />

                                        <TextView
                                        android:layout_width="wrap_content"
                                        android:layout_height="wrap_content"
                                        android:text="-1"
                                        android:id="@+id/tvB"
                                        android:layout_centerVertical="true"
                                        android:layout_alignParentEnd="true"
                                        android:textSize="20pt" />
                                        </RelativeLayout>

App's logic

The application logic is implemented in the MainActivity.java file.

Both the objects called by the library, representing the remote resources, and the textviews shown on the app's User Interface are global variable:

#!java


                                            BLEButton devAButton1;
                                            BLEButton devAButton2;
                                            BLEAlarm devAAlarm;
                                            BLEButton devBButton1;
                                            BLEButton devBButton2;
                                            BLEAlarm devBAlarm;

                                            TextView tvA,tvB;

Then in the activity's onCreate method the SAndroidE library is initializated by the means of the BLEContext.init method. It is mandatory to insert this method before any other operations related to the SAndrodE library.

#!java
                                                @Override
                                                protected void onCreate(Bundle savedInstanceState) {
                                                    super.onCreate(savedInstanceState);
                                                    setContentView(R.layout.activity_main);

                                                    BLEContext.initBLE(this);

                                                    ...

We link and initialize both remote resources and textviews:

#!java
                                                        tvA=(TextView) findViewById(R.id.tvA);
                                                        tvB=(TextView) findViewById(R.id.tvB);

                                                        devAButton1 = (BLEButton) BLEContext.findViewById("bellA_key_button1");
                                                        devAButton2 = (BLEButton) BLEContext.findViewById("bellA_key_button2");
                                                        devAAlarm = (BLEAlarm) BLEContext.getSystemService(BLEContext.ALARM_SERVICE, "bellA_key_alarm");

                                                        devBButton1 = (BLEButton) BLEContext.findViewById("bellB_key_button1");
                                                        devBButton2 = (BLEButton) BLEContext.findViewById("bellB_key_button2");
                                                        devBAlarm = (BLEAlarm) BLEContext.getSystemService(BLEContext.ALARM_SERVICE, "bellB_key_alarm");
                                                    

NOTE: the String parameters passed to the methods, which initialize the SAndrodE Objects are the 'pointer' defined in the configuration procedure. This 'pointer' can be found in the bleresources.xml file. In the current release of the library (version 0.1) this file is stored in the private memory of the 'BLEEmbeddedFlasher' application, thus in order to work correctly the library needs the application to be installed. In the next releases this limitation will be eliminated

Each remote button handler is declared to perform the following operations:

#!java


                                                        if (devAButton1 != null) {
                                                            devAButton1.setOnClickListener(new BLEOnClickListener() {
                                                                @Override
                                                                public void onClick(BLEItem bleItem) {
                                                                    (MainActivity.this).runOnUiThread(new Runnable() {
                                                                        @Override
                                                                        public void run() {
                                                                            tvA.setText(""+(Integer.parseInt(tvA.getText().toString())+1));
                                                                            devBAlarm.alarm(10000);
                                                                        }
                                                                    }
                                                                    );
                                                                }
                                                            });
                                                        }
                                                        if (devAButton2 != null) {
                                                            devAButton2.setOnClickListener(new BLEOnClickListener() {
                                                                @Override
                                                                public void onClick(BLEItem bleItem) {
                                                                    (MainActivity.this).runOnUiThread(new Runnable() {
                                                                        @Override
                                                                        public void run() {
                                                                            tvA.setText(""+(Integer.parseInt(tvA.getText().toString())+1));
                                                                            devBAlarm.cancel();
                                                                        }
                                                                    }
                                                                    );
                                                                }
                                                            });
                                                        }
                                                        if (devBButton1 != null) {
                                                            devBButton1.setOnClickListener(new BLEOnClickListener() {
                                                                @Override
                                                                public void onClick(BLEItem bleItem) {
                                                                    (MainActivity.this).runOnUiThread(new Runnable() {
                                                                        @Override
                                                                        public void run() {
                                                                            tvB.setText(""+(Integer.parseInt(tvB.getText().toString())+1));
                                                                            devAAlarm.alarm(10000);
                                                                        }
                                                                    }
                                                                    );
                                                                }
                                                            });
                                                        }
                                                        if (devBButton2 != null) {
                                                            devBButton2.setOnClickListener(new BLEOnClickListener() {
                                                                @Override
                                                                public void onClick(BLEItem bleItem) {
                                                                    (MainActivity.this).runOnUiThread(new Runnable() {
                                                                        @Override
                                                                        public void run() {
                                                                            tvB.setText(""+(Integer.parseInt(tvB.getText().toString())+1));
                                                                            devAAlarm.cancel();
                                                                        }
                                                                    }
                                                                    );
                                                                }
                                                            });
                                                        }

Below the full MainActivity.java source code is reported:

#!java


                                                            package com.example.my.testbuttonincrement;

                                                            import android.app.Activity;
                                                            import android.support.v7.app.AppCompatActivity;
                                                            import android.os.Bundle;
                                                            import android.widget.TextView;

                                                            import eu.angel.bleembedded.lib.BLEContext;
                                                            import eu.angel.bleembedded.lib.device.action.BLEAction;
                                                            import eu.angel.bleembedded.lib.item.BLEItem;
                                                            import eu.angel.bleembedded.lib.item.alarm.BLEAlarm;
                                                            import eu.angel.bleembedded.lib.item.button.BLEButton;
                                                            import eu.angel.bleembedded.lib.item.button.BLEOnClickListener;

                                                            public class MainActivity extends Activity {


                                                                private static final String TAG = "MainActivity";

                                                                TextView tvA,tvB;
                                                                BLEButton devAButton1;
                                                                BLEButton devAButton2;
                                                                BLEAlarm devAAlarm;
                                                                BLEButton devBButton1;
                                                                BLEButton devBButton2;
                                                                BLEAlarm devBAlarm;

                                                                @Override
                                                                protected void onCreate(Bundle savedInstanceState) {
                                                                    super.onCreate(savedInstanceState);
                                                                    setContentView(R.layout.activity_main);

                                                                    BLEContext.initBLE(this);

                                                                    tvA=(TextView) findViewById(R.id.tvA);
                                                                    tvB=(TextView) findViewById(R.id.tvB);

                                                                    devAButton1 = (BLEButton) BLEContext.findViewById("bellA_key_button1");
                                                                    devAButton2 = (BLEButton) BLEContext.findViewById("bellA_key_button2");
                                                                    devAAlarm = (BLEAlarm) BLEContext.getSystemService(BLEContext.ALARM_SERVICE, "bellA_key_alarm");

                                                                    devBButton1 = (BLEButton) BLEContext.findViewById("bellB_key_button1");
                                                                    devBButton2 = (BLEButton) BLEContext.findViewById("bellB_key_button2");
                                                                    devBAlarm = (BLEAlarm) BLEContext.getSystemService(BLEContext.ALARM_SERVICE, "bellB_key_alarm");

                                                                    if (devAButton1 != null) {
                                                                        devAButton1.setOnClickListener(new BLEOnClickListener() {
                                                                            @Override
                                                                            public void onClick(BLEItem bleItem) {
                                                                                (MainActivity.this).runOnUiThread(new Runnable() {
                                                                                    @Override
                                                                                    public void run() {
                                                                                        tvA.setText(""+(Integer.parseInt(tvA.getText().toString())+1));
                                                                                        devBAlarm.alarm(10000);
                                                                                    }
                                                                                }
                                                                                );
                                                                            }
                                                                        });
                                                                    }
                                                                    if (devAButton2 != null) {
                                                                        devAButton2.setOnClickListener(new BLEOnClickListener() {
                                                                            @Override
                                                                            public void onClick(BLEItem bleItem) {
                                                                                (MainActivity.this).runOnUiThread(new Runnable() {
                                                                                    @Override
                                                                                    public void run() {
                                                                                        tvA.setText(""+(Integer.parseInt(tvA.getText().toString())+1));
                                                                                        devBAlarm.cancel();
                                                                                    }
                                                                                }
                                                                                );
                                                                            }
                                                                        });
                                                                    }
                                                                    if (devBButton1 != null) {
                                                                        devBButton1.setOnClickListener(new BLEOnClickListener() {
                                                                            @Override
                                                                            public void onClick(BLEItem bleItem) {
                                                                                (MainActivity.this).runOnUiThread(new Runnable() {
                                                                                    @Override
                                                                                    public void run() {
                                                                                        tvB.setText(""+(Integer.parseInt(tvB.getText().toString())+1));
                                                                                        devAAlarm.alarm(10000);
                                                                                    }
                                                                                }
                                                                                );
                                                                            }
                                                                        });
                                                                    }
                                                                    if (devBButton2 != null) {
                                                                        devBButton2.setOnClickListener(new BLEOnClickListener() {
                                                                            @Override
                                                                            public void onClick(BLEItem bleItem) {
                                                                                (MainActivity.this).runOnUiThread(new Runnable() {
                                                                                    @Override
                                                                                    public void run() {
                                                                                        tvB.setText(""+(Integer.parseInt(tvB.getText().toString())+1));
                                                                                        devAAlarm.cancel();
                                                                                    }
                                                                                }
                                                                                );
                                                                            }
                                                                        });
                                                                    }
                                                                    tvA.setText(""+(Integer.parseInt(tvA.getText().toString())+1));
                                                                    tvB.setText(""+(Integer.parseInt(tvB.getText().toString())+1));
                                                                }
                                                            }
                                                        

Let's run it

Finally we are able to run our application by connecting the PC and the smartphone with the USB micro cable. Click the Run button in Android Studio and select the connected smartphone to deploy and run our compiled application on it.

In this example, clicking any of the two buttons on each device results in incrementing the respective label on the application's UI.

run.jpg

run.jpg

NOTE: If devices do not connect at startup, please shutdown all Bluetooth applications already running, like the BleembeddedFlasher app or previously launched versions of our app.