1.蓝牙1.0简介
蓝牙4.0是2012年最新蓝牙版本,是3.0的升级版本;较3.0版本更省电、成本低、3毫秒低延迟、超长有效连接距离、AES-128加密等,通常安卓设备版本必须在安卓4.3以上版本才能支持此功能;
2.安卓项目使用
项目需求:安卓设备与硬件设备通过蓝牙4.0进行实时数据交互。
3.代码实现
3.1打开蓝牙,搜索设备,显示蓝牙列表:
package com.zhts.hejing.act;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Handler;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import com.zhts.hejing.R;
import com.zhts.hejing.base.BaseActivity;
import com.zhts.hejing.base.BaseHolder;
import com.zhts.hejing.base.LBaseAdapter;
import com.zhts.hejing.manager.DataManager;
import java.util.ArrayList;
import java.util.List;
/**
* @version V1.0 <描述当前版本>
* @category DeviceActivity是用于显示可连接的蓝牙设备
* @FileName: com.zhts.hejing.act.DeviceActivity.java
* @author: Layne
* @date: 2016-06-06 11:40
*/
public class DeviceActivity extends BaseActivity{
private static final String TAG = "DeviceActivity";
private static final int RESULT_CODE = 20;
/**搜索BLE终端*/
private BluetoothAdapter mBluetoothAdapter;
private boolean mScanning;
// Stops scanning after 10 seconds.
private static final long SCAN_PERIOD = 10000;
private List<BluetoothDevice> deviceList;
private ListView lv_common;
private ConnectAdapter connectAdapter;
private String title;
public final int REQUEST_ENABLE_BT = 110;
private Handler mHandler = null;
@Override
public void setLayout() {
setContentView(R.layout.activity_common_list);
}
@Override
public void initView() {
title = getIntent().getStringExtra("title");
dealTitle(title,true,"搜索");
lv_common = (ListView) findViewById(R.id.lv_common);
deviceList = new ArrayList<BluetoothDevice>();
mHandler = new Handler();
setAnimation(lv_common,0.2f,R.anim.layout_zero_animation);
}
@Override
public void initData() {
// Use this check to determine whether BLE is supported on the device. Then you can
// selectively disable BLE-related features.
//判断设备是否支持BLE,
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
Toast.makeText(this, "您的手机不支持ble功能", Toast.LENGTH_SHORT).show();
finish();
}
//获取蓝牙终端
final BluetoothManager bluetoothManager =
(BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = bluetoothManager.getAdapter();
//判断是否支持蓝牙功能
if (mBluetoothAdapter == null) {
Toast.makeText(this,"您的手机不支持蓝牙功能", Toast.LENGTH_SHORT).show();
finish();
return;
}
//初始化蓝牙列表适配器
connectAdapter = new ConnectAdapter(_context);
lv_common.setAdapter(connectAdapter);
//开启蓝牙
open();
}
@Override
public void bindOnClick() {
lv_common.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
BluetoothDevice device = deviceList.get(position);
if (device == null) return;
if (mScanning) {
mBluetoothAdapter.stopLeScan(mLeScanCallback);
mScanning = false;
}
DataManager.getInstance().setObj(device);
setResult(RESULT_OK,new Intent());
finish();
}
});
}
@Override
public void rightAction() {
search();
}
/**
* 打开蓝牙
*/
private void open() {
// 发intent通知系统打开蓝牙
if (!mBluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
}
/**
* 查找周围的蓝牙
*/
private void search() {
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
mScanning = false;
mBluetoothAdapter.stopLeScan(mLeScanCallback);
}
}, SCAN_PERIOD);
mScanning = true;
if(mBluetoothAdapter ==null){
final BluetoothManager bluetoothManager =
(BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = bluetoothManager.getAdapter();
}
mBluetoothAdapter.startLeScan(mLeScanCallback);
showToast("正在搜索,请稍后……");
}
private BluetoothAdapter.LeScanCallback mLeScanCallback =
new BluetoothAdapter.LeScanCallback() {
@Override
public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
runOnUiThread(new Runnable() {
@Override
public void run() {
boolean isSame = true;
for (BluetoothDevice bd : deviceList) {
if(bd.getAddress().equalsIgnoreCase(device.getAddress())){
isSame = false;
}
}
if(isSame){
deviceList.add(device);
connectAdapter.notifyDataSetChanged();
}
}
});
}
};
class ConnectAdapter extends LBaseAdapter<BluetoothDevice> {
public ConnectAdapter(Context context) {
super(context,deviceList,R.layout.layout_connect_item);
}
@Override
public BaseHolder getBaseHolder() {
return new MyHolder();
}
}
class MyHolder implements BaseHolder<BluetoothDevice>{
private TextView name_tv;
private TextView address_tv;
@Override
public void initView(View view) {
name_tv = (TextView) view.findViewById(R.id.name_tv);
address_tv = (TextView) view.findViewById(R.id.address_tv);
}
@Override
public void bindComponentEvent(int position) {
}
@Override
public void initData(BluetoothDevice bluetoothDevice) {
name_tv.setText(bluetoothDevice.getName());
address_tv.setText(bluetoothDevice.getAddress());
}
}
@Override
protected void onResume() {
super.onResume();
}
}
以上代码是实现搜索蓝牙设备并点击item选择对应蓝牙设备进行连接操作。
3.2需要用到两个BLE操作的工具类BluetoothLeClass和BleUtils(从网上找的开源代码),代码上有版权声明,直接上代码:
/*
* Copyright (C) 2013 The Android Open Source Project
*
* 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.zhts.hejing.utils;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattService;
import android.text.TextUtils;
import android.util.Log;
/**
* This class includes a small subset of standard GATT attributes for demonstration purposes.
*/
public class BleUtils {
private static HashMap<Integer, String> serviceTypes = new HashMap();
static {
// Sample Services.
serviceTypes.put(BluetoothGattService.SERVICE_TYPE_PRIMARY, "PRIMARY");
serviceTypes.put(BluetoothGattService.SERVICE_TYPE_SECONDARY, "SECONDARY");
}
public static String getServiceType(int type){
return serviceTypes.get(type);
}
//-------------------------------------------
private static HashMap<Integer, String> charPermissions = new HashMap();
static {
charPermissions.put(0, "UNKNOW");
charPermissions.put(BluetoothGattCharacteristic.PERMISSION_READ, "READ");
charPermissions.put(BluetoothGattCharacteristic.PERMISSION_READ_ENCRYPTED, "READ_ENCRYPTED");
charPermissions.put(BluetoothGattCharacteristic.PERMISSION_READ_ENCRYPTED_MITM, "READ_ENCRYPTED_MITM");
charPermissions.put(BluetoothGattCharacteristic.PERMISSION_WRITE, "WRITE");
charPermissions.put(BluetoothGattCharacteristic.PERMISSION_WRITE_ENCRYPTED, "WRITE_ENCRYPTED");
charPermissions.put(BluetoothGattCharacteristic.PERMISSION_WRITE_ENCRYPTED_MITM, "WRITE_ENCRYPTED_MITM");
charPermissions.put(BluetoothGattCharacteristic.PERMISSION_WRITE_SIGNED, "WRITE_SIGNED");
charPermissions.put(BluetoothGattCharacteristic.PERMISSION_WRITE_SIGNED_MITM, "WRITE_SIGNED_MITM");
}
public static String getCharPermission(int permission){
return getHashMapValue(charPermissions,permission);
}
//-------------------------------------------
private static HashMap<Integer, String> charProperties = new HashMap();
static {
charProperties.put(BluetoothGattCharacteristic.PROPERTY_BROADCAST, "BROADCAST");
charProperties.put(BluetoothGattCharacteristic.PROPERTY_EXTENDED_PROPS, "EXTENDED_PROPS");
charProperties.put(BluetoothGattCharacteristic.PROPERTY_INDICATE, "INDICATE");
charProperties.put(BluetoothGattCharacteristic.PROPERTY_NOTIFY, "NOTIFY");
charProperties.put(BluetoothGattCharacteristic.PROPERTY_READ, "READ");
charProperties.put(BluetoothGattCharacteristic.PROPERTY_SIGNED_WRITE, "SIGNED_WRITE");
charProperties.put(BluetoothGattCharacteristic.PROPERTY_WRITE, "WRITE");
charProperties.put(BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE, "WRITE_NO_RESPONSE");
}
public static String getCharPropertie(int property){
return getHashMapValue(charProperties,property);
}
//--------------------------------------------------------------------------
private static HashMap<Integer, String> descPermissions = new HashMap();
static {
descPermissions.put(0, "UNKNOW");
descPermissions.put(BluetoothGattDescriptor.PERMISSION_READ, "READ");
descPermissions.put(BluetoothGattDescriptor.PERMISSION_READ_ENCRYPTED, "READ_ENCRYPTED");
descPermissions.put(BluetoothGattDescriptor.PERMISSION_READ_ENCRYPTED_MITM, "READ_ENCRYPTED_MITM");
descPermissions.put(BluetoothGattDescriptor.PERMISSION_WRITE, "WRITE");
descPermissions.put(BluetoothGattDescriptor.PERMISSION_WRITE_ENCRYPTED, "WRITE_ENCRYPTED");
descPermissions.put(BluetoothGattDescriptor.PERMISSION_WRITE_ENCRYPTED_MITM, "WRITE_ENCRYPTED_MITM");
descPermissions.put(BluetoothGattDescriptor.PERMISSION_WRITE_SIGNED, "WRITE_SIGNED");
descPermissions.put(BluetoothGattDescriptor.PERMISSION_WRITE_SIGNED_MITM, "WRITE_SIGNED_MITM");
}
public static String getDescPermission(int property){
return getHashMapValue(descPermissions,property);
}
private static String getHashMapValue(HashMap<Integer, String> hashMap,int number){
String result =hashMap.get(number);
if(TextUtils.isEmpty(result)){
List<Integer> numbers = getElement(number);
result="";
for(int i=0;i<numbers.size();i++){
result+=hashMap.get(numbers.get(i))+"|";
}
}
return result;
}
/**
* 位运算结果的反推函数10 -> 2 | 8;
*/
static private List<Integer> getElement(int number){
List<Integer> result = new ArrayList<Integer>();
for (int i = 0; i < 32; i++){
int b = 1 << i;
if ((number & b) > 0)
result.add(b);
}
return result;
}
public static String bytesToHexString(byte[] src){
StringBuilder stringBuilder = new StringBuilder("");
if (src == null || src.length <= 0) {
return null;
}
for (int i = 0; i < src.length; i++) {
int v = src[i] & 0xFF;
String hv = Integer.toHexString(v);
if (hv.length() < 2) {
stringBuilder.append(0);
}
stringBuilder.append(hv);
}
return stringBuilder.toString();
}
//转化字符串为十六进制编码
public static byte[] toHexByte(String s) {
s = s.toUpperCase();
byte[] bytes = new byte[s.length()];
for (int i = 0; i < s.length(); i++) {
char ch = s.charAt(i);
int index = -1;
for (int j = 0; j < HEX_CHAR_TABLE.length; j++) {
if(ch==HEX_CHAR_TABLE[j]){
index = j;
}
}
if(index==-1){
return null;
}
bytes[i] = HEX_TABLE[index];;
}
return bytes;
}
static final byte[] HEX_TABLE = {0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xA,0xB,0xC,0xD,0xE,0xF};
static final char[] HEX_CHAR_TABLE = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
}
/*
* Copyright (C) 2013 The Android Open Source Project
*
* 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.zhts.hejing.utils;
import java.util.List;
import android.annotation.TargetApi;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.os.Build;
import android.util.Log;
/**
* Service for managing connection and data communication with a GATT server hosted on a
* given Bluetooth LE device.
*/
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
public class BluetoothLeClass{
private final static String TAG = BluetoothLeClass.class.getSimpleName();
public static BluetoothLeClass mBle = null;
private BluetoothManager mBluetoothManager;
private BluetoothAdapter mBluetoothAdapter;
private String mBluetoothDeviceAddress;
private BluetoothGatt mBluetoothGatt;
public interface OnConnectListener {
public void onConnect(BluetoothGatt gatt);
}
public interface OnDisconnectListener {
public void onDisconnect(BluetoothGatt gatt);
}
public interface OnServiceDiscoverListener {
public void onServiceDiscover(BluetoothGatt gatt);
}
public interface OnDataAvailableListener {
public void onCharacteristicRead(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic,
int status);
public void onCharacteristicWrite(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic, int status);
public void onCharacteristicChanged(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic);
}
private OnConnectListener mOnConnectListener;
private OnDisconnectListener mOnDisconnectListener;
private OnServiceDiscoverListener mOnServiceDiscoverListener;
private OnDataAvailableListener mOnDataAvailableListener;
private Context mContext;
public void setOnConnectListener(OnConnectListener l){
mOnConnectListener = l;
}
public void setOnDisconnectListener(OnDisconnectListener l){
mOnDisconnectListener = l;
}
public void setOnServiceDiscoverListener(OnServiceDiscoverListener l){
mOnServiceDiscoverListener = l;
}
public void setOnDataAvailableListener(OnDataAvailableListener l){
mOnDataAvailableListener = l;
}
/**
* modify
* @param c
*/
private BluetoothLeClass(Context c){
mContext = c;
}
public static BluetoothLeClass getInstance(Context c){
if(mBle==null){
mBle = new BluetoothLeClass(c);
}
return mBle;
}
// Implements callback methods for GATT events that the app cares about. For example,
// connection change and services discovered.
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
if(mOnConnectListener!=null)
mOnConnectListener.onConnect(gatt);
Log.i(TAG, "Connected to GATT server.");
// Attempts to discover services after successful connection.
Log.i(TAG, "Attempting to start service discovery:" +
mBluetoothGatt.discoverServices());
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
if(mOnDisconnectListener!=null)
mOnDisconnectListener.onDisconnect(gatt);
Log.i(TAG, "Disconnected from GATT server.");
}
}
@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS && mOnServiceDiscoverListener!=null) {
mOnServiceDiscoverListener.onServiceDiscover(gatt);
} else {
Log.w(TAG, "onServicesDiscovered received: " + status);
}
}
@Override
public void onCharacteristicRead(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic,
int status) {
if (mOnDataAvailableListener!=null)
mOnDataAvailableListener.onCharacteristicRead(gatt, characteristic, status);
}
@Override
public void onCharacteristicWrite(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic, int status) {
if (mOnDataAvailableListener!=null)
mOnDataAvailableListener.onCharacteristicWrite(gatt, characteristic,status);
}
@Override
public void onCharacteristicChanged(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic) {
if (mOnDataAvailableListener!=null)
mOnDataAvailableListener.onCharacteristicChanged(gatt, characteristic);
}
};
/**
* Initializes a reference to the local Bluetooth adapter.
*
* @return Return true if the initialization is successful.
*/
public boolean initialize() {
// For API level 18 and above, get a reference to BluetoothAdapter through
// BluetoothManager.
if (mBluetoothManager == null) {
mBluetoothManager = (BluetoothManager) mContext.getSystemService(Context.BLUETOOTH_SERVICE);
if (mBluetoothManager == null) {
Log.e(TAG, "Unable to initialize BluetoothManager.");
return false;
}
}
mBluetoothAdapter = mBluetoothManager.getAdapter();
if (mBluetoothAdapter == null) {
Log.e(TAG, "Unable to obtain a BluetoothAdapter.");
return false;
}
return true;
}
/**
* Connects to the GATT server hosted on the Bluetooth LE device.
*
* @param address The device address of the destination device.
*
* @return Return true if the connection is initiated successfully. The connection result
* is reported asynchronously through the
* {@code BluetoothGattCallback#onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int)}
* callback.
*/
public boolean connect(final String address) {
if (mBluetoothAdapter == null || address == null) {
Log.w(TAG, "BluetoothAdapter not initialized or unspecified address.");
return false;
}
// Previously connected device. Try to reconnect.
if (mBluetoothDeviceAddress != null && address.equals(mBluetoothDeviceAddress)
&& mBluetoothGatt != null) {
Log.d(TAG, "Trying to use an existing mBluetoothGatt for connection.");
if (mBluetoothGatt.connect()) {
return true;
} else {
return false;
}
}
final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
if (device == null) {
Log.w(TAG, "Device not found. Unable to connect.");
return false;
}
// We want to directly connect to the device, so we are setting the autoConnect
// parameter to false.
mBluetoothGatt = device.connectGatt(mContext, false, mGattCallback);
Log.d(TAG, "Trying to create a new connection.");
mBluetoothDeviceAddress = address;
return true;
}
/**
* Disconnects an existing connection or cancel a pending connection. The disconnection result
* is reported asynchronously through the
* {@code BluetoothGattCallback#onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int)}
* callback.
*/
public void disconnect() {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
mBluetoothGatt.disconnect();
}
/**
* After using a given BLE device, the app must call this method to ensure resources are
* released properly.
*/
public void close() {
if (mBluetoothGatt == null) {
return;
}
mBluetoothGatt.close();
mBluetoothGatt = null;
}
/**
* Request a read on a given {@code BluetoothGattCharacteristic}. The read result is reported
* asynchronously through the {@code BluetoothGattCallback#onCharacteristicRead(android.bluetooth.BluetoothGatt, android.bluetooth.BluetoothGattCharacteristic, int)}
* callback.
*
* @param characteristic The characteristic to read from.
*/
public void readCharacteristic(BluetoothGattCharacteristic characteristic) {
if (mBluetoothAdapter == null || mBluetoothGatt == null||characteristic ==null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
mBluetoothGatt.readCharacteristic(characteristic);
}
/**
* Enables or disables notification on a give characteristic.
*
* @param characteristic Characteristic to act on.
* @param enabled If true, enable notification. False otherwise.
*/
public void setCharacteristicNotification(BluetoothGattCharacteristic characteristic,
boolean enabled) {
if (mBluetoothAdapter == null || mBluetoothGatt == null||characteristic ==null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);
}
public void writeCharacteristic(BluetoothGattCharacteristic characteristic){
if (mBluetoothAdapter == null || mBluetoothGatt == null||characteristic ==null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
mBluetoothGatt.writeCharacteristic(characteristic);
}
/**
* Retrieves a list of supported GATT services on the connected device. This should be
* invoked only after {@code BluetoothGatt#discoverServices()} completes successfully.
*
* @return A {@code List} of supported services.
*/
public List<BluetoothGattService> getSupportedGattServices() {
if (mBluetoothGatt == null) return null;
return mBluetoothGatt.getServices();
}
}
3.3链接获取对应需要操作的渠道,BLE和之前的蓝牙版本有所不同的地方在于它对蓝牙进行了进一步的封装,通常会分成三个通道:读 ,写,广播。
package com.zhts.hejing.fragment;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattService;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.baidu.location.BDLocation;
import com.baidu.location.BDLocationListener;
import com.baidu.location.LocationClient;
import com.baidu.location.LocationClientOption;
import com.xfdream.applib.config.Config;
import com.zhts.hejing.R;
import com.zhts.hejing.base.BaseFragment;
import com.zhts.hejing.manager.DataManager;
import com.zhts.hejing.manager.UserManager;
import com.zhts.hejing.net.OnNetResponseListener;
import com.zhts.hejing.utils.BleUtils;
import com.zhts.hejing.utils.BluetoothLeClass;
import com.zhts.hejing.utils.CommonUtil;
import com.zhts.hejing.utils.IntentUtil;
import com.zhts.hejing.widget.TestTimeView;
import java.util.HashMap;
import java.util.List;
/**
* 测试页面
* Created by Layne on 16/4/15.
*/
public class TestFragment extends BaseFragment {
private boolean isTesting = false;
private static final String TAG = "TestFragment";
public final static String UUID_KEY_CHARACTERISTIC = "0000FFF0-0000-1000-8000-00805f9b34fb";
public final static String UUID_KEY_READ = "0000FFF2-0000-1000-8000-00805f9b34fb";
public final static String UUID_KEY_WRITE = "0000FFF1-0000-1000-8000-00805f9b34fb";
public final static String UUID_KEY_NOTIFY = "0000FFF4-0000-1000-8000-00805f9b34fb";
public final static String UUID_KEY_INFO = "0000FFF5-0000-1000-8000-00805f9b34fb";
private View layout = null;
private LinearLayout whole_layout = null;
private RelativeLayout rl_progress = null;
private ImageView iv_electric = null;
private TextView tv_temperature = null;
private TestTimeView ttv_progress = null;
private LinearLayout ll_test = null;
private Button btn_pause_test = null;
private TextView tv_test_time = null;
private boolean isConnect = false;
/**搜索BLE终端*/
private BluetoothAdapter mBluetoothAdapter = null;
/**读写BLE终端*/
private BluetoothLeClass mBLE = null;
/**连接设备*/
private BluetoothDevice device = null;
/**读操作的特征值*/
private BluetoothGattCharacteristic readCharacteristic = null;
/**写操作的特征值*/
private BluetoothGattCharacteristic writeCharacteristic = null;
/**通知操作的特征值*/
private BluetoothGattCharacteristic notifyCharacteristic = null;
/**获取版本号的特征值*/
private BluetoothGattCharacteristic infoCharacteristic = null;
/******************测试数据上传接口所需数据*****************/
private String tokenid =""; //(string)用户令牌
private String checkData = "0" ; //(String)核辐射
private int noiseValue ; //(int)噪音值
private double longitude; //(string)经度
private double latitude; //(string)纬度
private int temperature= 0; //(int)温度
private int env ; //(string)检测环境(0:室内、1:医院、2:野外...)
private int checkType = -1 ; //(int)检测类型(0:普通测量 1:飞行测量)
private int continueTime = 0 ; //(int)持续时间
private String deviceVersion = ""; //(string)核辐射设备版本号
private String mac = "" ; //(string)核辐射设备mac
private String province = ""; //(string)省
private String city = ""; //(string)市
private String district = ""; //(string)区
private int deviceTime ; //设备已测量时间
private int deviceStatus ; //命令运行状态标志
private int energy =0;
/**
* 定位SDK的核心类
*/
private LocationClient mLocClient = null;
public MyLocationListenner myListener = new MyLocationListenner();
private OnNetResponseListener listener = null;
private int totalTime = 300*1000;
private int testTime = 0;
private int viewTime = 0;
public final static int REFRESH_TIME = 1000;
private int notifyTime = -1;
private int isRead = 0;
private Handler handler = new Handler(){
public void handleMessage(Message msg) {
switch (msg.what) {
case 1:
showToast("测试完成", new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialogInterface) {
ll_test.setVisibility(View.VISIBLE);
btn_pause_test.setVisibility(View.GONE);
testTime = 0;
ttv_progress.stop();
pauseTest();
}
});
/*AlertDialog.Builder builder = new Builder(VideoViewPlayingActivity.this);
builder.setTitle("提示").setMessage("您已经10分钟没有点击了");
builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Toast.makeText(VideoViewPlayingActivity.this, "点击。。。",Toast.LENGTH_SHORT).show();
handler.postDelayed(runnable, 1000);
}
});
builder.show();*/
break;
case 2:
//cancelLoading();
// ttv_progress.onProgressChanged(viewTime*60);
tv_temperature.setText(temperature+"°C");
ll_test.setVisibility(View.GONE);
btn_pause_test.setVisibility(View.VISIBLE);
switch (energy/25){
case 0:
iv_electric.setImageResource(R.drawable.icon_home_dianchi1_nor);
break;
case 1:
iv_electric.setImageResource(R.drawable.icon_home_dianchi2_nor);
break;
case 2:
iv_electric.setImageResource(R.drawable.icon_home_dianchi3_nor);
break;
case 3:
iv_electric.setImageResource(R.drawable.icon_home_dianchi4_nor);
break;
case 4:
iv_electric.setImageResource(R.drawable.icon_home_dianchi5_nor);
break;
default:
iv_electric.setImageResource(R.drawable.icon_home_dianchi5_nor);
break;
}
switch(checkType){
case 0:
int minute = (totalTime-testTime)/(60*1000);
int second = (totalTime-testTime)%(60*1000)/1000;
tv_test_time.setText("剩余时间:"+ minute+":"+(second<10?"0"+second:second));
break;
case 1:
int min = testTime/(60*1000);
int sec = testTime%(60*1000)/1000;
tv_test_time.setText("飞行测试用时:"+ min+":"+(sec<10?"0"+sec:sec));
break;
}
break;
}
};
};
/**
* 计时器操作
*/
private Runnable runnable = new Runnable() {
public void run() {
viewTime = viewTime+REFRESH_TIME;
mBLE.readCharacteristic(readCharacteristic);
testTime = deviceTime*1000;
totalTime = notifyTime*60000;
Message message = Message.obtain();
if(deviceStatus == 0||(isRead==1&&checkType==0&&viewTime>=300*1000)){
message.what = 1;
handler.sendMessage(message);
handler.removeCallbacks(runnable);
}else{
message.what = 2;
handler.sendMessage(message);
handler.postDelayed(this, REFRESH_TIME);
}
}
};
@Override
protected View getContentView(LayoutInflater inflater) {
layout = inflater.inflate(R.layout.fragment_test, null);
init();
return layout;
}
private void init(){
ll_test = (LinearLayout) layout.findViewById(R.id.ll_test);
btn_pause_test = (Button) layout.findViewById(R.id.btn_pause_test);
whole_layout = (LinearLayout) layout.findViewById(R.id.whole_layout);
rl_progress = (RelativeLayout) layout.findViewById(R.id.rl_progress);
layout.findViewById(R.id.btn_start_test).setOnClickListener(click);
layout.findViewById(R.id.btn_fly_test).setOnClickListener(click);
btn_pause_test.setOnClickListener(click);
if(testTime == 0){
ll_test.setVisibility(View.VISIBLE);
btn_pause_test.setVisibility(View.GONE);
}else{
ll_test.setVisibility(View.GONE);
btn_pause_test.setVisibility(View.VISIBLE);
}
iv_electric = (ImageView) layout.findViewById(R.id.iv_electric);
tv_temperature = (TextView) layout.findViewById(R.id.tv_temperature);
tv_test_time = (TextView) layout.findViewById(R.id.tv_test_time);
ttv_progress = (TestTimeView) layout.findViewById(R.id.ttv_progress);
mBLE = BluetoothLeClass.getInstance(getContext());
if (!mBLE.initialize()) {
Log.e(Config.TAG, "Unable to initialize Bluetooth");
showToast("蓝牙初始化失败");
}
//发现BLE终端的Service时回调
mBLE.setOnServiceDiscoverListener(mOnServiceDiscover);
//收到BLE终端数据交互的事件
mBLE.setOnDataAvailableListener(mOnDataAvailable);
// 定位初始化
mLocClient = new LocationClient(getContext());
mLocClient.registerLocationListener(myListener);
LocationClientOption option = new LocationClientOption();
option.setOpenGps(true); // 打开gps
option.setCoorType("bd09ll"); // 设置坐标类型
option.setScanSpan(1000);
mLocClient.setLocOption(option);
mLocClient.start();
}
/**
* 搜索到BLE终端服务的事件
*/
private BluetoothLeClass.OnServiceDiscoverListener mOnServiceDiscover = new BluetoothLeClass.OnServiceDiscoverListener(){
@Override
public void onServiceDiscover(BluetoothGatt gatt) {
if (gatt == null|| CommonUtil.isNullCollect(gatt.getServices())) {
showToast("服务连接失败");
return;
}
isConnect = true;
getBLEData();
}
};
/**
* 收到BLE终端数据交互的事件
*/
private BluetoothLeClass.OnDataAvailableListener mOnDataAvailable = new BluetoothLeClass.OnDataAvailableListener(){
/**
* BLE终端数据被读的事件
*/
@Override
public void onCharacteristicRead(BluetoothGatt gatt,final
BluetoothGattCharacteristic characteristic, int status) {
String str = BleUtils.bytesToHexString(characteristic.getValue());
Log.e("ble","onCharRead "+gatt.getDevice().getName()
+" read "
+characteristic.getUuid().toString()
+" -> "
+ BleUtils.bytesToHexString(characteristic.getValue()));
if(characteristic.getUuid().toString().equalsIgnoreCase(UUID_KEY_READ)){
int integer = Integer.parseInt(str.substring(0,4),16);
int decimal = Integer.parseInt(str.substring(4,8),16);
checkData = integer+"."+decimal;
deviceTime = Integer.parseInt(str.substring(8,12),16);
deviceStatus = Integer.parseInt(str.substring(12,14),16);
noiseValue = Integer.parseInt(str.substring(14,16),16); //(int)噪音值
temperature= Integer.parseInt(str.substring(16,18),16);
energy= Integer.parseInt(str.substring(18,20),16);
ttv_progress.setData(integer,decimal);
Log.e("hxl","deviceStatus:"+deviceStatus+"deviceTime:"+deviceTime+"checkdata:"+checkData);
if(deviceStatus == 1&&isRead==0&&checkType!=-1){
isRead = 1;
handler.post(runnable);
}
}else if(characteristic.getUuid().toString().equalsIgnoreCase(UUID_KEY_INFO)){
deviceVersion = Integer.parseInt(str.substring(0,4),16)+"";
}
}
/**
* 收到BLE终端写入数据回调
*/
@Override
public void onCharacteristicWrite(BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic, int status) {
String str = BleUtils.bytesToHexString(characteristic.getValue());
Log.e("ble","onCharRead "+gatt.getDevice().getName()
+" read "
+characteristic.getUuid().toString()
+" -> "
+BleUtils.bytesToHexString(characteristic.getValue()));
if(characteristic.getUuid().toString().equalsIgnoreCase(UUID_KEY_WRITE)) {
int mind = Integer.parseInt(str.substring(0, 2), 16);
notifyTime = Integer.parseInt(str.substring(2, 4), 16);
if(mind==1){
mBLE.readCharacteristic(readCharacteristic);
handler.post(runnable);
}
}
}
/**
* 收到BLE终端通知回调
*/
@Override
public void onCharacteristicChanged(BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic) {
String str = BleUtils.bytesToHexString(characteristic.getValue());
Log.e("ble","onCharRead "+gatt.getDevice().getName()
+" read "
+characteristic.getUuid().toString()
+" -> "
+ BleUtils.bytesToHexString(characteristic.getValue()));
if(characteristic.getUuid().toString().equalsIgnoreCase(UUID_KEY_NOTIFY)) {
int mind = Integer.parseInt(str.substring(0, 2), 16);
notifyTime = Integer.parseInt(str.substring(2, 4), 16);
if(mind == 1 ){
notifyTime = Integer.parseInt(str.substring(2, 4), 16);
if(notifyTime==0){
checkType = 1;
}else if(notifyTime>0){
checkType = 0;
}
if(isRead ==0){
mBLE.readCharacteristic(readCharacteristic);
}
}
}
}
};
private void getBLEData(){
if(mBLE!=null&&mBLE.getSupportedGattServices()!=null){
for (BluetoothGattService gattService : mBLE.getSupportedGattServices()) {
if(gattService.getUuid().toString().equalsIgnoreCase(UUID_KEY_CHARACTERISTIC)) {
for (final BluetoothGattCharacteristic gattCharacteristic : gattService.getCharacteristics()) {
if (gattCharacteristic.getUuid().toString().equalsIgnoreCase(UUID_KEY_READ)) {
readCharacteristic = gattCharacteristic;
} else if (gattCharacteristic.getUuid().toString().equalsIgnoreCase(UUID_KEY_WRITE)) {
writeCharacteristic = gattCharacteristic;
} else if (gattCharacteristic.getUuid().toString().equalsIgnoreCase(UUID_KEY_NOTIFY)) {
notifyCharacteristic = gattCharacteristic;
} else if (gattCharacteristic.getUuid().toString().equalsIgnoreCase(UUID_KEY_INFO)) {
infoCharacteristic = gattCharacteristic;
}
}
}
}
}
mBLE.readCharacteristic(readCharacteristic);
mBLE.readCharacteristic(infoCharacteristic);
mBLE.setCharacteristicNotification(notifyCharacteristic,true);
}
private View.OnClickListener click = new View.OnClickListener() {
@Override
public void onClick(View view) {
/*if (UserManager.getInstance(getContext()).getUser() == null){
showToast("您尚未登录,请先登录", new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialogInterface) {
IntentUtil.startLoginActivity(getContext(),"登录");
}
});
return;
}else{
tokenid = UserManager.getInstance(getContext()).getToken();
}*/
switch(view.getId()){
case R.id.btn_start_test:
ttv_progress.start();
//startTest(0);
break;
case R.id.btn_fly_test:
startTest(1);
break;
case R.id.btn_pause_test:
pauseTest();
break;
default:
break;
}
}
};
/**
* 开始测试
*/
private void startTest(int status){
if(isConnect){
ttv_progress.start();
isRead = 1;
checkType = status ;
ll_test.setVisibility(View.GONE);
viewTime = 0;
btn_pause_test.setVisibility(View.VISIBLE);
if(checkType == 0){
writeCharacteristic.setValue(new byte[]{01,05,01,00,00});
}else if(checkType == 1){
writeCharacteristic.setValue(new byte[]{01,00,00,00,00});
}
//往蓝牙模块写入数据
mBLE.writeCharacteristic(writeCharacteristic);
//showLoading();
mBLE.setCharacteristicNotification(notifyCharacteristic, true);
}else{
showToast("设备未连接");
// getDeviceInfo();
// handler.post(runnable);
}
}
/**
* 停止测试
*/
private void pauseTest(){
handler.removeCallbacks(runnable);
ll_test.setVisibility(View.VISIBLE);
btn_pause_test.setVisibility(View.GONE);
continueTime = viewTime;
testTime = 0;
viewTime = 0;
// ttv_progress.onProgressChanged(viewTime*60);
ttv_progress.stop();
writeCharacteristic.setValue(new byte[]{02,00,00,00,00});
//往蓝牙模块写入数据
mBLE.writeCharacteristic(writeCharacteristic);
HashMap<String,String> hm = new HashMap<String, String>();
hm.put("tokenid",tokenid);
hm.put("checkData",checkData+"");
hm.put("noiseValue",noiseValue+"");
hm.put("longitude",longitude+"");
hm.put("latitude",latitude+"");
hm.put("temperature",temperature+"");
hm.put("env",env+"");
hm.put("checkType",checkType+"");
hm.put("continueTime",continueTime+"");
hm.put("deviceVersion",deviceVersion);
hm.put("mac",mac);
hm.put("province",province);
hm.put("city",city);
hm.put("district",district);
DataManager.getInstance().setHm(hm);
IntentUtil.startChooseSettingActivity(getContext(),"选择当前测试环境");
}
/**
* 定位SDK监听函数
*/
public class MyLocationListenner implements BDLocationListener {
@Override
public void onReceiveLocation(BDLocation location) {
// map view 销毁后不在处理新接收的位置
if (location == null ) {
Log.e("hxl",latitude+""+longitude);
return;
}
latitude = location.getLatitude();
longitude = location.getLongitude();
}
public void onReceivePoi(BDLocation poiLocation) {
}
}
@Override
public void onResume() {
super.onResume();
setAnimation(whole_layout,0.3f,R.anim.layout_zero_animation);
setAnimation(rl_progress,0.3f,R.anim.layout_zero_animation);
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == 0&& resultCode == getActivity().RESULT_OK && data!=null){
getDeviceInfo();
}
}
private void getDeviceInfo(){
device = (BluetoothDevice) DataManager.getInstance().getObj();
//btn_choose_device.setText(device.getName());
if(device!=null){
mBLE.connect(device.getAddress());
mac = device.getAddress();
ttv_progress.setStatus(device.getName());
ttv_progress.start();
}
}
}