最近在研究Android的蓝牙Ble的开发,由于是低功耗蓝牙,以前没有接触过,看过好多博客,大多数都差不多,不过个人有一点心得关于蓝牙获取心率的。
首先就是权限问题了,在AndroidMainfest清单文件中添加一下权限:
这次研究开发的是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) {
};
};
就这样简单的就能吧蓝牙中的心率得到了;
下面看看源码吧:
先看一下布局文件:
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" >
listview的item:
android:layout_width="match_parent"
android:layout_height="wrap_content">
android:layout_height="wrap_content"
android:textSize="24dp"/>
android:layout_height="wrap_content"
android:textSize="12dp"/>
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
private LayoutInflater mInflator;
public LeDeviceListAdapter() {
super();
mLeDevices = new ArrayList
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;
}
}