蓝牙4.0BLE在安卓项目中的使用详解

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();
        }
    }
}

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
蓝牙4.0BLE(低耗蓝牙)完全开发手册是一本详细介绍蓝牙4.0BLE技术以及其开发的书籍。该手册提供了全面的信息,帮助开发者理解和运用蓝牙4.0BLE技术。 在蓝牙4.0BLE完全开发手册,首先会对蓝牙技术做简要介绍,包括其发展历史、应用领域和主要特点。接下来会详细讲解蓝牙4.0BLE的原理和架构,以及与传统蓝牙的区别和优势。 然后,手册会深入介绍蓝牙4.0BLE的开发过程。首先是硬件方面,讲解了蓝牙4.0BLE芯片的选择和使用,以及与其他硬件模块的接口和连接。 接着,手册会详细介绍蓝牙4.0BLE的软件开发。从蓝牙协议栈的架构和功能开始,包括扫描、连接、传输和配置等。随后,会讲解关于蓝牙4.0BLE数据传输和安全性的技术细节,如数据格式、特征值和服务的定义等。 在软件开发的过程,手册还会介绍一些常见的开发工具和开发环境,包括蓝牙4.0BLE开发板、调试工具和开发软件的配置和操作。 最后,手册还会提供一些实际案例和应用示例,以便开发者更好地理解和运用蓝牙4.0BLE技术。同时,手册也会介绍一些开发的常见问题和解决方法,以及软件和硬件的调试技巧和注意事项。 总之,蓝牙4.0BLE完全开发手册是一本全面而实用的参考书,适合对蓝牙4.0BLE技术感兴趣的开发者和工程师,能够帮助他们深入理解蓝牙4.0BLE技术,掌握开发过程的关键技术和实践经验。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值