Introduction: How to Create Android BLE Application Faster and Easier?

About: ElecFreaks is an open design house founded in March 2011. Our goal is to create rapid prototypes and give small-batch manufacture solution for makers and startups. With over 50% staff as engineers and expanded…

If you are an electronics enthusiast, and also fond of programming, I would be very glad to share with you an Android BLE application development method, so you can integrate the phone and MCU to do some more interesting things. Right now we begin to explain how to develop an Android BLE application, and you can also refer to the official Google tutorial. This guide is a packed tutorial, which enables you to build your Android BLE application more easily and more quickly. Of course, I’ll upload my source code for everyone to share it and you can also refer to the official sample sdk/samples/android-18/legacy/BluetoothLeGatt.

Source reading: http://www.elecfreaks.com/7906.html

Step 1: Create a New Android Project

Open Eclipse, File->New->Android Application Project, and then fill the Application name in the Application Name edit box, for example, BleExample, or others. Minimum Required SDK selects API18:Android 4.3, and Target SDK also selects API18:Android 4.3, as buletooth 4.0 must be with Android 4.3edition or above. Others default unchanged and please continue clicking the Next button until Finish button appears, and then click the Finish button.

Step 2: Add the Permissions and Services

Add the below code in the manifest file:

<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>

<uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>

<service android:name="com.elecfreaks.ble.BluetoothLeService" android:enabled="true"/>


Step 3: Create the ListView Item Layout File

Aiming to display each content of ListView, here we use customization(defining by yourself), so that each ListView can show more content, item_list.xml is demonstrated as below:

<?xml version="1.0"encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"    
    >  
    <TextView android:id="@+id/textViewDevName"
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:textSize="24dp"/> 
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:textSize="12dp"/>
    <TextView android:id="@+id/textViewDevAddress"
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:textSize="12dp"/>
</LinearLayout>

Copy the source code of BleExample /com.elecfreaks.ble to your project src directory,and then open the file with error prompt, pressing the shift+ctrl+O keys.

Step 4: Modify Activity_main.xml, Increasing ScanButton and BleDeviceListView

Increased contents are shown as below:

<Button
android:id="@+id/scanButton"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:onClick="scanOnClick"
android:text="scan" />
<ListView      
android:id="@+id/bleDeviceListView"        
android:layout_width="fill_parent"        
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/scanButton"        
android:layout_below="@+id/scanButton"        
android:layout_above="@+id/sendButton"         
>
</ListView>

Step 5: In MainActivity.java, Add ScanButton Mothod of Responding to Events

(onClick="scanOnClick")
public void scanOnClick(final View v){

}

Step 6: Add Member for MainActivity

private Button scanButton;
private ListView bleDeviceListView;
private BLEDeviceListAdapter listViewAdapter;  


private BluetoothHandler bluetoothHandler;
private boolean isConnected;

Step 7: Set Member Value in MainActivity.onCreate

        scanButton = (Button) findViewById(R.id.scanButton);
        bleDeviceListView = (ListView)                  
findViewById(R.id.bleDeviceListView);
        listViewAdapter = new BLEDeviceListAdapter(this);    

        bluetoothHandler = new BluetoothHandler(this);
        bluetoothHandler.setOnConnectedListener(new  
OnConnectedListener() {

            @Override
            public void onConnected(boolean isConnected) {
                   // TODO Auto-generated method stub
                   setConnectStatus(isConnected);
            }

});
        bluetoothHandler.setOnRecievedDataListener(new   OnRecievedDataListener() {


             @Override
             public void onRecievedData(byte[] bytes) {
                    // TODO Auto-generated method stub
                   System.out.printf("REC:");
                   for(byte b:bytes)
                         System.out.printf("%02X ", b);
                  System.out.printf("\n");
              }
        });

Step 8: Adding SetConnectStatus Mothod

public void setConnectStatus(boolean isConnected){
        this.isConnected = isConnected;
        if(isConnected){
            showMessage("Connection successful");
            scanButton.setText("break");
        }else{
            bluetoothHandler.onPause();
         bluetoothHandler.onDestroy();
         scanButton.setText("scan");
        }
}
private void showMessage(String str){
        Toast.makeText(MainActivity.this, str,                    
Toast.LENGTH_SHORT).show();
}

Step 9: Adding Content in ScanOnClick

if(!isConnected){     
    bleDeviceListView.setAdapter(bluetoothHandler.getDeviceListAdapter));
    bleDeviceListView.setOnItemClickListener(new OnItemClickListener() 
{  

    @Override
    public void onItemClick(AdapterView parent, View view,
                            int position, long id) {
        String buttonText = (String) ((Button)v).getText();
                                    if(buttonText.equals("scanning")){
                            showMessage("scanning..."){
                            return ;
                        }
                        BluetoothDevice device = bluetoothHandler.getDeviceListAdapter().getItem(position).device;
                        // connect

                        bluetoothHandler.connect(device.getAddress());
                    }
            });
            bluetoothHandler.setOnScanListener(new OnScanListener() {
                @Override
                public void onScanFinished() {
                    // TODO Auto-generated method stub
                    ((Button)v).setText("scan");
                    ((Button)v).setEnabled(true);
                }
                @Override
                public void onScan(BluetoothDevice device, int rssi, byte[] scanRecord) {}
            });
            ((Button)v).setText("scanning");
            ((Button)v).setEnabled(false);
            bluetoothHandler.scanLeDevice(true);
        }else{
            setConnectStatus(false);

}

Step 10: Send Data

byte[] data = new byte[1];
data[0] = 0x02;
bluetoothHandler.sendData(data);

Step 11: Receive Data

Upon receiving data, the mothod of
OnRecievedDataListener.onRecievedData(byte[] bytes) set from bluetoothHandler.setOnRecievedDataListener()OnRecievedDataListener.onRecievedData(byte[] bytes) would be used, and bytes means received data

Step 12: Send Data to MCU Via Protocol.(Use BLUNO From ElecFreaks)

In src directory, create Transmitter.java, adding the constructed function with two parameters as below:

public Transmitter(Context context,              
BluetoothHandler bluetoothHandler){
        this.context = context;
        this.mBluetoothHandler = bluetoothHandler;
}

How to add sendData()?

private void sendData(byte[] bytes){
        mBluetoothHandler.sendData(bytes);
}

Step 13: Receive MCU Data Via Protocol

MCU data receiving and sending protocol uses JSON packet,and the format is {“T”:your value, “V”:your value, …}. Of course you can define other values. Create the MyArray.java in src directory,aiming to connecting two arrays. The code was shown as below:

public class MyArray {
    static public byte[] arrayCat(byte[] buf1,byte[] buf2){
        byte[] bufret=null;
        int len1 = 0;
        int len2 = 0;
        if(buf1 != null)
         len1 = buf1.length;
        if(buf2 != null)
         len2 = buf2.length;
        if(len1+len2 > 0)
         bufret = new byte[len1+len2];
        if(len1 > 0)
         System.arraycopy(buf1, 0, bufret, 0, len1);
        if(len2 > 0)
         System.arraycopy(buf2, 0, bufret, len1, len2);
        return bufret;
    }
}

Copy the protocol.java in my sample code to src directory Adding member

private Protocol protocol

From onCreate(),delete:

bluetoothHandler.setOnRecievedDataListener();

Add:

protocol = new Protocol(this, new Transmitter(this, bluetoothHandler));
protocol.setOnReceivedDataListener(recListener);

Adding member in MainActivity:

private static final boolean INPUT = false;
private static final boolean OUTPUT = true;
private static final boolean LOW = false;
private static final boolean HIGH = true;
private boolean digitalVal[];
private int analogVal[];

Initializing in onCreate:

        digitalVal = new boolean[14];
        analogVal = new int[14];
        private OnReceivedRightDataListener recListener = new 
OnReceivedRightDataListener() {  
        @Override
        public int onReceivedData(String str) {
            // TODO Auto-generated method stub
        try {
                JSONObject readJSONObject = new JSONObject(str);
                int type = readJSONObject.getInt("T");
                int value = readJSONObject.getInt("V");   
                switch(type){
                    case Protocol.ANALOG:{
                        int pin = readJSONObject.getInt("P");
                        analogVal[pin] = value;
                    }break;
                    case Protocol.DIGITAL:{
                        int pin = readJSONObject.getInt("P");
                        digitalVal[pin] = (value>0)?HIGH:LOW;
                    }break;
                    case Protocol.TEMPERATURE:{
                        float temperature = ((float)value)/100;
                    }break;
                    case Protocol.HUMIDITY:{
                        float humidity = ((float)value)/100;
                    }break;
                    default:break;
                }
            } catch (JSONException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }  
            return 0;
        }
};

Step 14: Use Protocol to Send Data

protocol.writeAnalogData(9, 20);
protocol.writeDigitalData(3, 1);

Step 15: Use Protocol to Receive Data

protocol.readAnalogDataCommand(9);
protocol.readDigitalDataCommand(3);

Note: Returned data is received by recListener

Step 16: MCU Port Protocol(arduino)

Refer to the sample code of AndroidIOControl provided.

Step 17: Reference

If you need more information, please refer to our website.

Step 18: