com.megster.cordova.rfduino.Peripheral.java Source code

Java tutorial

Introduction

Here is the source code for com.megster.cordova.rfduino.Peripheral.java

Source

// (c) 2103 Don Coleman
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.megster.cordova.rfduino;

import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattService;
import android.util.Log;

import org.apache.cordova.CallbackContext;
import org.apache.cordova.LOG;
import org.apache.cordova.PluginResult;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.UnsupportedEncodingException;
import java.util.Arrays;
import java.util.UUID;

/**
 * Peripheral wraps the BluetoothDevice and provides methods to convert to JSON.
 */
public class Peripheral extends BluetoothGattCallback {

    // RFduino 2220, 2221, 2222, 2223
    public static final UUID RFDUINO_SERVICE_UUID = UUID.fromString("00002220-0000-1000-8000-00805F9B34FB");
    public static final UUID RECEIVE_CHARACTERISTIC_UUID = UUID.fromString("00002221-0000-1000-8000-00805F9B34FB");
    public static final UUID SEND_CHARACTERISTIC_UUID = UUID.fromString("00002222-0000-1000-8000-00805F9B34FB");
    public static final UUID DISCONNECT_CHARACTERISTIC_UUID = UUID
            .fromString("00002223-0000-1000-8000-00805F9B34FB");

    // 0x2902 org.bluetooth.descriptor.gatt.client_characteristic_configuration.xml
    public final static UUID CLIENT_CHARACTERISTIC_CONFIGURATION_UUID = UUID
            .fromString("00002902-0000-1000-8000-00805F9B34FB");

    private static final String TAG = "Peripheral";

    private BluetoothDevice device;
    private String advertising;
    private int advertisingRSSI;
    private boolean connected = false;

    private CallbackContext connectCallback;
    private CallbackContext onDataCallback;

    private BluetoothGattCharacteristic sendCharacteristic;
    private BluetoothGattCharacteristic disconnectCharacteristic;

    public Peripheral(BluetoothDevice device, int advertisingRSSI, byte[] scanRecord) {

        this.device = device;
        this.advertisingRSSI = advertisingRSSI;
        this.advertising = getAdvertisingValue(scanRecord);

    }

    public void disconnect() {
        connectCallback = null;
        connected = false;
    }

    public JSONObject asJSONObject() {

        JSONObject json = new JSONObject();

        try {
            json.put("name", device.getName());
            json.put("uuid", device.getAddress()); // This is MAC address
            json.put("advertising", advertising);
            // TODO real RSSI if we have it, else
            json.put("rssi", advertisingRSSI);
        } catch (JSONException e) { // this shouldn't happen
            e.printStackTrace();
        }

        return json;
    }

    public void setConnectCallback(CallbackContext connectCallback) {
        this.connectCallback = connectCallback;
    }

    public void setOnDataCallback(CallbackContext onDataCallback) {
        this.onDataCallback = onDataCallback;
    }

    public boolean isConnected() {
        return connected;
    }

    public BluetoothDevice getDevice() {
        return device;
    }

    public BluetoothGattCharacteristic getSendCharacteristic() {
        return sendCharacteristic;
    }

    public BluetoothGattCharacteristic getDisconnectCharacteristic() {
        return disconnectCharacteristic;
    }

    @Override
    public void onServicesDiscovered(BluetoothGatt gatt, int status) {
        Log.d(TAG, "gatt " + gatt);
        Log.d(TAG, "status " + status);
        super.onServicesDiscovered(gatt, status);

        BluetoothGattService service = gatt.getService(RFDUINO_SERVICE_UUID);
        Log.d(TAG, "service " + service);

        BluetoothGattCharacteristic receiveCharacteristic = service.getCharacteristic(RECEIVE_CHARACTERISTIC_UUID);
        sendCharacteristic = service.getCharacteristic(SEND_CHARACTERISTIC_UUID);
        disconnectCharacteristic = service.getCharacteristic(DISCONNECT_CHARACTERISTIC_UUID);

        if (receiveCharacteristic != null) {
            gatt.setCharacteristicNotification(receiveCharacteristic, true);

            BluetoothGattDescriptor receiveConfigDescriptor = receiveCharacteristic
                    .getDescriptor(CLIENT_CHARACTERISTIC_CONFIGURATION_UUID);
            if (receiveConfigDescriptor != null) {
                receiveConfigDescriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
                gatt.writeDescriptor(receiveConfigDescriptor);
            } else {
                LOG.e(TAG, "Receive Characteristic can not be configured.");
            }
        } else {
            LOG.e(TAG, "Receive Characteristic is missing.");
        }

        // call the success callback for connect
        PluginResult result = new PluginResult(PluginResult.Status.OK);
        result.setKeepCallback(true);
        connectCallback.sendPluginResult(result);
    }

    @Override
    public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {

        if (newState == BluetoothGatt.STATE_CONNECTED) {

            connected = true;
            gatt.discoverServices();

        } else {

            connected = false;
            if (connectCallback != null) {
                connectCallback.error("Disconnected");
                connectCallback = null;
            }
        }
    }

    @Override
    public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {

        super.onCharacteristicChanged(gatt, characteristic);
        if (characteristic.getUuid().equals(RECEIVE_CHARACTERISTIC_UUID)) {
            PluginResult result = new PluginResult(PluginResult.Status.OK, characteristic.getValue());
            result.setKeepCallback(true);
            onDataCallback.sendPluginResult(result);
        }
    }

    // The "advertising" value is RFduino specific and stored in the manufacturer data
    // https://www.bluetooth.org/en-us/specification/assigned-numbers/generic-access-profile
    // data is length type value length type value
    // Based on BluetoothHelper#parseScanRecord from https://github.com/lann/RFDuinoTest/
    private String getAdvertisingValue(byte[] scanRecord) {

        String advertising = "";

        int i = 0;
        while (i < scanRecord.length) {
            int length = scanRecord[i] & 0xFF;
            if (length == 0) {
                break;
            } // will this really happen?
            i++;
            int type = scanRecord[i] & 0xFF;
            if (type == 0xFF) { // manufacturer data
                // skip the first 2 char (because that's what the rfduino iOS code does)
                byte[] bytes = Arrays.copyOfRange(scanRecord, i + 3, i + length);
                try {
                    advertising = new String(bytes, "UTF-8");
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                    advertising = "error";
                }
                break;
            } else {
                i += length;
            }
        }
        return advertising;
    }

    public void updateRssi(int rssi) {
        advertisingRSSI = rssi;
    }
}