Android蓝牙Ble开发之获取心率

来源:互联网 发布:qq机器人软件下载 编辑:程序博客网 时间:2024/04/28 14:29

最近在研究Android的蓝牙Ble的开发,由于是低功耗蓝牙,以前没有接触过,看过好多博客,大多数都差不多,不过个人有一点心得关于蓝牙获取心率的。

首先就是权限问题了,在AndroidMainfest清单文件中添加一下权限:

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

这次研究开发的是mio的心率手表所以如果没有设备的大家仅供参考:

1、首先 判断当前设备是否支持ble:

/**
         * 判断当前设备是否支持ble
         */
        if (!getPackageManager().hasSystemFeature(
                PackageManager.FEATURE_BLUETOOTH_LE)) {
            System.out.println("不支持BLE设备");
        }

2、获取蓝牙适配器:

mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();

3、搜索蓝牙设备:

/**
     * 搜索蓝牙设备
     *
     * @param enable
     */
    private void scanLeDevice(boolean enable) {
        // TODO Auto-generated method stub
        if (enable) {
            mHandler.postDelayed(new Runnable() {

                @Override
                public void run() {
                    // TODO Auto-generated method stub
                    mScanning = false;
                    mBluetoothAdapter.stopLeScan(callback);
                }
            }, 10000);
            mScanning = true;
            mBluetoothAdapter.startLeScan(callback);
        } else {
            mScanning = false;
            mBluetoothAdapter.stopLeScan(callback);
        }
    }

4、搜索蓝牙设备的回调接口:

/**
     * 蓝牙搜索的回调方法
     */
    private BluetoothAdapter.LeScanCallback callback = new LeScanCallback() {

        public void onLeScan(final BluetoothDevice device, int rssi,
                byte[] scanRecord) {
            System.out.println(device + "****" + device.getName() + "***"
                    + device.getAddress());
            runOnUiThread(new Runnable() {
                public void run() {
                    adapter.addDevice(device);
                    adapter.notifyDataSetChanged();
                }
            });
        }
    };

5、然后搜索到设备之后就是连接蓝牙设备了:

lv.setOnItemClickListener(new OnItemClickListener() {

            private BluetoothGatt gatt;

            @Override
            public void onItemClick(AdapterView<?> parent, View view,
                    int position, long id) {
                //把搜索到的设备信息放到listview中,然后连接设备
                BluetoothDevice device = adapter.getDevice(position);

               //连接设备的方法

                gatt = device.connectGatt(getApplicationContext(), false,
                        mGattCallback);
            }
        });

6、获取设备中的各种信息的方法这里主要是获取心率的:

    private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
        private BluetoothGattCharacteristic mCharacteristic;
        /**
         * 当连接状态发生改变的时候回调的方法
         */
        @Override
        public void onConnectionStateChange(BluetoothGatt gatt, int status,
                int newState) {
            //判断蓝牙连接状态
            if (newState == BluetoothProfile.STATE_CONNECTED) {
                System.out.println("设备已连接");
                //寻找设备中的服务
                gatt.discoverServices();
            } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
                System.out.println("设备已断开连接");
            }
        }
        /**
         * 当服务发现后所调用的方法
         */
        @Override
        public void onServicesDiscovered(BluetoothGatt gatt, int status) {
            if (status == BluetoothGatt.GATT_SUCCESS) {
                System.out.println("Services discovered");
                //得到心率信息的service
                BluetoothGattService service = gatt
                        .getService(mHeartRateServiceUuid);
                if (service == null) {
                    System.out.println("没有得到心率服务");
                } else {
                    System.out.println("得到心率服务");
                    mCharacteristic = service
                            .getCharacteristic(mHeartRateCharacteristicUuid);

                    if (mCharacteristic == null) {
                        System.out.println("不能找到心率");
                    } else {
                        boolean success = gatt.setCharacteristicNotification(
                                mCharacteristic, true);
                        if (!success) {
                            System.out.println("Enabling notification failed!");
                            return;
                        }

                        BluetoothGattDescriptor descriptor = mCharacteristic
                                .getDescriptor(BleDefinedUUIDs.Descriptor.CHAR_CLIENT_CONFIG);
                        if (descriptor != null) {
                            descriptor
                                    .setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
                            gatt.writeDescriptor(descriptor);
                            System.out.println("Notification enabled");
                        } else {
                            System.out
                                    .println("Could not get descriptor for characteristic! Notification are not enabled.");
                        }
                    }
                }
            } else {
                System.out.println("Unable to discover services");
            }
        }
        /**
         * 当service里边的characteristic发生改变调用
         */
        @Override
        public void onCharacteristicChanged(BluetoothGatt gatt,
                BluetoothGattCharacteristic characteristic) {
            //得到心率数据
            if(characteristic.equals(mCharacteristic)){

                byte[] raw = mCharacteristic.getValue();
                System.out.println("心率****="+raw);
                int index = ((raw[0] & 0x01) == 1) ? 2 : 1;
                int format = (index == 1) ? BluetoothGattCharacteristic.FORMAT_UINT8 : BluetoothGattCharacteristic.FORMAT_UINT16;
                int value = mCharacteristic.getIntValue(format, index);
                final String description = value + " bpm";

                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        System.out.println("心率:"+description);
                    }
                });
            
            }
        }

        /* the rest of callbacks are not interested for us */

        @Override
        public void onCharacteristicRead(BluetoothGatt gatt,
                BluetoothGattCharacteristic characteristic, int status) {
        }

        @Override
        public void onCharacteristicWrite(BluetoothGatt gatt,
                BluetoothGattCharacteristic characteristic, int status) {
        };

        @Override
        public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
        };
    };

就这样简单的就能吧蓝牙中的心率得到了;

下面看看源码吧:

先看一下布局文件:

<LinearLayout 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"
    android:orientation="vertical"
    tools:context=".MainActivity" >

    <Button
        android:id="@+id/start"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="18dp"
        android:text="搜索蓝牙设备" />
<ListView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/lv"></ListView>
   
</LinearLayout>

listview的item:

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

BleDefinedUUIDs.java:

 package com.example.watch;

import java.util.UUID;

public class BleDefinedUUIDs {
    
    public static class Service {
        final static public UUID HEART_RATE               = UUID.fromString("0000180d-0000-1000-8000-00805f9b34fb");
    };
    
    public static class Characteristic {
        final static public UUID HEART_RATE_MEASUREMENT   = UUID.fromString("00002a37-0000-1000-8000-00805f9b34fb");
        final static public UUID MANUFACTURER_STRING      = UUID.fromString("00002a29-0000-1000-8000-00805f9b34fb");
        final static public UUID MODEL_NUMBER_STRING      = UUID.fromString("00002a24-0000-1000-8000-00805f9b34fb");
        final static public UUID FIRMWARE_REVISION_STRING = UUID.fromString("00002a26-0000-1000-8000-00805f9b34fb");
        final static public UUID APPEARANCE               = UUID.fromString("00002a01-0000-1000-8000-00805f9b34fb");
        final static public UUID BODY_SENSOR_LOCATION     = UUID.fromString("00002a38-0000-1000-8000-00805f9b34fb");
        final static public UUID BATTERY_LEVEL            = UUID.fromString("00002a19-0000-1000-8000-00805f9b34fb");
    }
    
    public static class Descriptor {
        final static public UUID CHAR_CLIENT_CONFIG       = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");
    }
    
}

MianActivity.java

package com.example.watch;

import java.util.ArrayList;
import java.util.UUID;


import android.os.Bundle;
import android.os.Handler;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothAdapter.LeScanCallback;
import android.bluetooth.BluetoothDevice;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.text.style.BulletSpan;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;

public class MainActivity extends Activity {
    
    private BluetoothAdapter mBluetoothAdapter;
    private static final int REQUEST_ENABLE_BT = 1;
    private Handler mHandler = new Handler();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        /**
         * 判断当前设备是否支持ble
         */
        if (!getPackageManager().hasSystemFeature(
                PackageManager.FEATURE_BLUETOOTH_LE)) {
            System.out.println("不支持BLE设备");
        }
        //得到蓝牙适配器
        mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {
            Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            startActivityForResult(intent, REQUEST_ENABLE_BT);
        }
        Button start = (Button) findViewById(R.id.start);
        lv = (ListView) findViewById(R.id.lv);
        adapter = new LeDeviceListAdapter();
        start.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                scanLeDevice(true);
                lv.setAdapter(adapter);
                adapter.clear();
            }

        });
        lv.setOnItemClickListener(new OnItemClickListener() {

            private BluetoothGatt gatt;

            @Override
            public void onItemClick(AdapterView<?> parent, View view,
                    int position, long id) {
                //把搜索到的设备信息放到listview中,然后连接设备
                BluetoothDevice device = adapter.getDevice(position);
                gatt = device.connectGatt(getApplicationContext(), false,
                        mGattCallback);
            }
        });

    }

    final static private UUID mHeartRateServiceUuid = BleDefinedUUIDs.Service.HEART_RATE;
    final static private UUID mHeartRateCharacteristicUuid = BleDefinedUUIDs.Characteristic.HEART_RATE_MEASUREMENT;

    /**
     * 寻找服务
     */

    private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
        private BluetoothGattCharacteristic mCharacteristic;
        /**
         * 当连接状态发生改变的时候回调的方法
         */
        @Override
        public void onConnectionStateChange(BluetoothGatt gatt, int status,
                int newState) {
            //判断蓝牙连接状态
            if (newState == BluetoothProfile.STATE_CONNECTED) {
                System.out.println("设备已连接");
                //寻找设备中的服务
                gatt.discoverServices();
            } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
                System.out.println("设备已断开连接");
            }
        }
        /**
         * 当服务发现后所调用的方法
         */
        @Override
        public void onServicesDiscovered(BluetoothGatt gatt, int status) {
            if (status == BluetoothGatt.GATT_SUCCESS) {
                System.out.println("Services discovered");
                //得到心率信息的service
                BluetoothGattService service = gatt
                        .getService(mHeartRateServiceUuid);
                if (service == null) {
                    System.out.println("没有得到心率服务");
                } else {
                    System.out.println("得到心率服务");
                    mCharacteristic = service
                            .getCharacteristic(mHeartRateCharacteristicUuid);

                    if (mCharacteristic == null) {
                        System.out.println("不能找到心率");
                    } else {
                        boolean success = gatt.setCharacteristicNotification(
                                mCharacteristic, true);
                        if (!success) {
                            System.out.println("Enabling notification failed!");
                            return;
                        }

                        BluetoothGattDescriptor descriptor = mCharacteristic
                                .getDescriptor(BleDefinedUUIDs.Descriptor.CHAR_CLIENT_CONFIG);
                        if (descriptor != null) {
                            descriptor
                                    .setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
                            gatt.writeDescriptor(descriptor);
                            System.out.println("Notification enabled");
                        } else {
                            System.out
                                    .println("Could not get descriptor for characteristic! Notification are not enabled.");
                        }
                    }
                }
            } else {
                System.out.println("Unable to discover services");
            }
        }
        /**
         * 当service里边的characteristic发生改变调用
         */
        @Override
        public void onCharacteristicChanged(BluetoothGatt gatt,
                BluetoothGattCharacteristic characteristic) {
            //得到心率数据
            if(characteristic.equals(mCharacteristic)){

                byte[] raw = mCharacteristic.getValue();
                System.out.println("心率****="+raw);
                int index = ((raw[0] & 0x01) == 1) ? 2 : 1;
                int format = (index == 1) ? BluetoothGattCharacteristic.FORMAT_UINT8 : BluetoothGattCharacteristic.FORMAT_UINT16;
                int value = mCharacteristic.getIntValue(format, index);
                final String description = value + " bpm";

                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        System.out.println("心率:"+description);
                    }
                });
            
            }
        }

        /* the rest of callbacks are not interested for us */

        @Override
        public void onCharacteristicRead(BluetoothGatt gatt,
                BluetoothGattCharacteristic characteristic, int status) {
        }

        @Override
        public void onCharacteristicWrite(BluetoothGatt gatt,
                BluetoothGattCharacteristic characteristic, int status) {
        };

        @Override
        public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
        };
    };
    private boolean mScanning;

    /**
     * 搜索蓝牙设备
     *
     * @param enable
     */
    private void scanLeDevice(boolean enable) {
        // TODO Auto-generated method stub
        if (enable) {
            mHandler.postDelayed(new Runnable() {

                @Override
                public void run() {
                    // TODO Auto-generated method stub
                    mScanning = false;
                    mBluetoothAdapter.stopLeScan(callback);
                }
            }, 10000);
            mScanning = true;
            mBluetoothAdapter.startLeScan(callback);
        } else {
            mScanning = false;
            mBluetoothAdapter.stopLeScan(callback);
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {

        if (requestCode == REQUEST_ENABLE_BT
                && resultCode == Activity.RESULT_CANCELED) {
            finish();
            return;
        }
        super.onActivityResult(requestCode, resultCode, data);

    }
    /**
     * 蓝牙搜索的回调方法
     */
    private BluetoothAdapter.LeScanCallback callback = new LeScanCallback() {

        public void onLeScan(final BluetoothDevice device, int rssi,
                byte[] scanRecord) {
            System.out.println(device + "****" + device.getName() + "***"
                    + device.getAddress());
            runOnUiThread(new Runnable() {
                public void run() {
                    adapter.addDevice(device);
                    adapter.notifyDataSetChanged();
                }
            });
        }
    };
    private ListView lv;
    private LeDeviceListAdapter adapter;

    private class LeDeviceListAdapter extends BaseAdapter {
        private ArrayList<BluetoothDevice> mLeDevices;
        private LayoutInflater mInflator;

        public LeDeviceListAdapter() {
            super();
            mLeDevices = new ArrayList<BluetoothDevice>();
            mInflator = MainActivity.this.getLayoutInflater();
        }

        public void addDevice(BluetoothDevice device) {
            if (!mLeDevices.contains(device)) {
                mLeDevices.add(device);
            }
        }

        public BluetoothDevice getDevice(int position) {
            return mLeDevices.get(position);
        }

        public void clear() {
            mLeDevices.clear();
        }

        @Override
        public int getCount() {
            return mLeDevices.size();
        }

        @Override
        public Object getItem(int i) {
            return mLeDevices.get(i);
        }

        @Override
        public long getItemId(int i) {
            return i;
        }

        @Override
        public View getView(int i, View view, ViewGroup viewGroup) {
            ViewHolder viewHolder;
            // General ListView optimization code.
            if (view == null) {
                view = mInflator.inflate(R.layout.listitem_device, null);
                viewHolder = new ViewHolder();
                viewHolder.deviceAddress = (TextView) view
                        .findViewById(R.id.device_address);
                viewHolder.deviceName = (TextView) view
                        .findViewById(R.id.device_name);
                view.setTag(viewHolder);
            } else {
                viewHolder = (ViewHolder) view.getTag();
            }

            BluetoothDevice device = mLeDevices.get(i);
            final String deviceName = device.getName();
            if (deviceName != null && deviceName.length() > 0)
                viewHolder.deviceName.setText(deviceName);
            else
                viewHolder.deviceName.setText("未知设备");
            viewHolder.deviceAddress.setText(device.getAddress());

            return view;
        }
    }

    static class ViewHolder {
        TextView deviceName;
        TextView deviceAddress;
    }
}


0 0