2018-08-01 14:39:28 qq_42246939 阅读数 145

这一篇是代码篇之蓝牙连接,主要讲如何开启蓝牙,搜索蓝牙设备,连接蓝牙设备。

  •     大致的步骤就是,首先是权限,用到蓝牙的那些权限就那几个,但是要特别注意的是在android7.0的系统上,如果要用到蓝牙,必须加入地理位置授权(谷歌那边的规定),然后我们注册广播,来监视我们需要的广播,比如BluetoothDevice.ACTION_FOUND,这条广播就是我们开启蓝牙搜索的时候,一些被我们发现的蓝牙就会自动发送这条广播,然后我们通过监视这条广播来得到这些被发现的蓝牙。也就是说我们首先要注册蓝牙广播,然后创建一个蓝牙接收器来监视一些我们要的广播。最后我们在ListView表上选择我们要连接的蓝牙设备,点击连接,这也就是列表点击事件来处理啦。

实战部分----------------------------------------------------------------------------------------------------------

首先定义一些我们需要用到的变量(包括后面我们发送数据那一篇文章也需要用到)

private BluetoothAdapter bluetoothAdapter;    //本地蓝牙适配器
private BluetoothSocket bluetoothSocket;
private BluetoothDevice bluetoothDevice;
private BlueReceiver blueReceiver;
private Button send;
private List <String> list =new ArrayList<>();
private ListView listView;
private EditText editText;
private ArrayAdapter<String> adapter;
private final UUID MY_UUID = UUID
        .fromString("00001101-0000-1000-8000-00805F9B34FB");
private final String NAME = "Bluetooth_Socket";
private IntentFilter filter;

一:首先我们的想法是在菜单上面的蓝牙连接按钮上实现蓝牙开启,蓝牙搜索,加载布局,然后在列表上实现连接功能。

 ①:首先显示菜单

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.main,menu);
    return true;
}

②:菜单点击事件

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    if (item.getItemId() == R.id.bluetooth) {
        if (!bluetoothAdapter.isEnabled()) {
            Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            startActivityForResult(intent, 200);
            //
        }
        bluetoothPermissions();//地理位置授权
        bluetoothAdapter.startDiscovery();//蓝牙开始搜索
        setContentView(R.layout.bluetooth);//加载RecycleView布局
        listView = findViewById(R.id.list_item1);
        listView.setOnItemClickListener(this);//列表点击事件
    }
    return  true;
}

首先,我们开启蓝牙,需要各种权限,在文件中AndroidManifest.xml中加入权限,如下:

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

在这里要注意的是,在Android7.0版本后,我们蓝牙搜索的前提是要添加一个关于地理位置的权限(上面代码的bluetoothPermissions()就是地理位置授权方法 

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>

③:注册蓝牙广播

     注册蓝牙广播接收器,我们可以在onStart()方法中实现,也是在打开这个程序的时候实现蓝牙注册。代码如下: 

@Override
   protected void onStart() {
       super.onStart();
       blueReceiver  = new BlueReceiver();
       filter = new IntentFilter();
       filter.addAction(BluetoothDevice.ACTION_FOUND);//发现蓝牙动作
       filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);//搜索结束动作
       filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);//搜素开始动作
       registerReceiver(blueReceiver, filter);//注册
       Log.d("CZK", "蓝牙广播接受器注册完毕");
   }

然后我们还得在onStop()方法上取消注册:

@Override
protected void onStop() {
    super.onStop();
    unregisterReceiver(blueReceiver);
    Log.d("CZK",  "取消注册");
}

 

④:注册完毕,接下来我们需要一个广播接收器。代码如下:

/*******************************************蓝牙接收器**************************************/
public class BlueReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        //发现其他蓝牙设备,如果该蓝牙设备没有被连接,则显示在列表上。
        if (intent.getAction().equals(BluetoothDevice.ACTION_FOUND)) {
                //发现蓝牙设备
                BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                //获取该蓝牙设备
            if(device.getBondState()!=BluetoothDevice.BOND_BONDED){
                //通过getBondState获取状态,判断是否匹配
                list.add(device.getName()+":"+device.getAddress()+"\n");
                adapter = new ArrayAdapter<>(MainActivity.this,android.R.layout.simple_list_item_1,android.R.id.text1,list);
                listView.setAdapter(adapter);
                adapter.notifyDataSetChanged();
                //显示在列表上面
                Log.d("CZK", "蓝牙发现目标");
            }
        }
        if (intent.getAction().equals(BluetoothAdapter.ACTION_DISCOVERY_STARTED)) {
            setTitle("开始搜索");
            Log.d("CZK","蓝牙搜索开始");
            Toast.makeText(MainActivity.this,"开始搜素",Toast.LENGTH_SHORT).show();
        }
        if (intent.getAction().equals(BluetoothAdapter.ACTION_DISCOVERY_FINISHED)) {
            setTitle("搜索完成(请选择配对设备)");
            Log.d("CZK","蓝牙搜索结束");
            Toast.makeText(MainActivity.this,"搜素结束",Toast.LENGTH_SHORT).show();
        }
        
    }
}

⑤:地理位置授权,蓝牙可见:

*************************************蓝牙discoverable************************/
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode==200){
        Intent dis=new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
        dis.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
        startActivity(dis);
        Log.d("CZK", "discoverable");//刷新
    }
}
/*************************************地理位置授权请求************************/
private void bluetoothPermissions() {
    if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_COARSE_LOCATION)
            != PackageManager.PERMISSION_GRANTED) {
        ActivityCompat.requestPermissions(this, new String[]{
                android.Manifest.permission.ACCESS_COARSE_LOCATION}, 1);
        Log.d("CZK", "地理位置授权成功 ");
    }
}

/*************************************地理位置授权处理******************************************/
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);

    switch (requestCode){
        case 1:
            if(grantResults.length > 0&& grantResults[0]==PackageManager.PERMISSION_GRANTED){
                Toast.makeText(MainActivity.this,"地理授权成功",Toast.LENGTH_SHORT);
            }
            else {
                Toast.makeText(MainActivity.this,"地理授权失败",Toast.LENGTH_SHORT);

            }

    }
}

⑥:连接蓝牙:

@Override
/*****************************************列表点击事件**************************************/
public void onItemClick(final AdapterView<?> adapterView, View view, int i, long l) {
    if(bluetoothAdapter.isDiscovering()){
        //如果还在搜索,则停止搜索
        bluetoothAdapter.cancelDiscovery();
    }
    String s = adapter.getItem(i);
    String address = s.substring(s.indexOf(":")+1).trim();
    if (bluetoothDevice == null){
        bluetoothDevice = bluetoothAdapter.getRemoteDevice(address);
        //getRemoteDevice()得到指定蓝牙的BluetoothDevice
    }
     try {
            if (bluetoothSocket == null){
                // 获取到客户端接口(获得对象)
                bluetoothSocket = bluetoothDevice
                        .createRfcommSocketToServiceRecord(MY_UUID);
                // 向服务端发送连接
                bluetoothSocket.connect();
                Log.d("CZK", "连接成功");
            }else {
                Log.d("CZK","bluetoothSocket != null");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

总结,在这一节上,我们仅仅实现的是蓝牙连接,在后面一节中将会学到连接之后,发送数据。

2014-04-10 15:47:58 gaixm 阅读数 8741

        概述:

           手机端打开编写的蓝牙通信软件,与单片机端蓝牙串口模块连接,而后,手机通过蓝牙发送读数据命令到单片机,单片机开始读取传感器信息,

将采集到得传感器信息通过蓝牙发送到手机端,手机端软件接收到后,显示。

       整体图:

        

       

      焊接板图:

     



        本项目涉及四个部分。

   一、手机端软件

   二、单片机端编程

   三、外设电路设计

   四、手机与单片机通信

     下面对四个部分进一步叙述。

  1、手机端软件

      手机端软件为安卓软件,只需要编写一个普通的蓝牙串口调试软件即可。但在编写手机端按安卓软件时,我利用一年前做安卓手机通

过蓝牙远程控制指纹识别器的源码改进,但却始终不能接收到蓝牙串口模块发送的数据。也就是说,手机可以给下位机发送信息,下位机成功接收,

但是却接收不到下位机上传的信息。我很是疑惑,我以为是蓝牙串口模块的问题,于是换了一个,结果还是一样。我一直坚信去年的源码没有问题,

但是却查不出原因在哪里。于是,我在相应的安卓蓝牙编程的书本上,找到讲解蓝牙部分的章节,按照步骤重新编写带代码,结果双向通信可以调通。

先前的问题正在研究之中,下面是正常运行源码中的部分代码:

  (1)蓝牙连接代码

 //接收活动结果,响应startActivityForResult()
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
    	switch(requestCode){
    	case REQUEST_CONNECT_DEVICE:     //连接结果,由DeviceListActivity设置返回
    		// 响应返回结果
            if (resultCode == Activity.RESULT_OK) {   //连接成功,由DeviceListActivity设置返回
                // MAC地址,由DeviceListActivity设置返回
                String address = data.getExtras()
                                     .getString(DeviceListActivity.EXTRA_DEVICE_ADDRESS);
                // 得到蓝牙设备句柄      
                _device = _bluetooth.getRemoteDevice(address);
 
                // 用服务号得到socket
                try{
                	_socket = _device.createRfcommSocketToServiceRecord(UUID.fromString(MY_UUID));
                }catch(IOException e){
                	Toast.makeText(this, "连接失败!", Toast.LENGTH_SHORT).show();
                }
                //连接socket
            	Button btn = (Button) findViewById(R.id.Button03);
                try{
                	_socket.connect();
                	Toast.makeText(this, "连接"+_device.getName()+"成功!", Toast.LENGTH_SHORT).show();
                	btn.setText("断开");
                }catch(IOException e){
                	try{
                		Toast.makeText(this, "连接失败!", Toast.LENGTH_SHORT).show();
                		_socket.close();
                		_socket = null;
                	}catch(IOException ee){
                		Toast.makeText(this, "连接失败!", Toast.LENGTH_SHORT).show();
                	}
                	
                	return;
                }
                
                //打开接收线程
                try{
            		is = _socket.getInputStream();   //得到蓝牙数据输入流
            		}catch(IOException e){
            			Toast.makeText(this, "接收数据失败!", Toast.LENGTH_SHORT).show();
            			return;
            		}
            		if(bThread==false){
            			ReadThread.start();
            			bThread=true;
            		}else{
            			bRun = true;
            		}
            }
    		break;
    	default:break;
    	}
    }
    
 
(2)手机蓝牙发送数据代码
 //发送数据线程
    public class SendThread extends Thread{
    	public void run(){
    		int i=0;
        	int n=0;
        	try{
        		OutputStream os = _socket.getOutputStream();   //蓝牙连接输出流
        		byte[] bos = edit0.getText().toString().getBytes();
        		for(i=0;i

  (3)手机蓝牙接收数据代码
//接收数据线程
    Thread ReadThread=new Thread(){
    	
    	public void run(){
    		int num = 0;
    		byte[] buffer = new byte[1024];
    		byte[] buffer_new = new byte[1024];
    		int i = 0;
    		int n = 0;
    		bRun = true;
    		//接收线程
    		while(true){
    			try{
    				while(is.available()==0){
    					while(bRun == false){}
    				}
    				while(true){
    					num = is.read(buffer);         //读入数据
    					n=0;
    					
    					String s0 = new String(buffer,0,num);
    					fmsg+=s0;    //保存收到数据
    					for(i=0;i

   
  2、单片机端
       单片机采用Arduino开发板,因其简单易学。
       单片机端的代码比较简单,是一些对应的传感器采集数据代码和串口通讯代码。

  3、外设焊接。
    外设有两个传感器,一个蓝牙串口模块。
    蓝牙串口模块负责蓝牙通信,传感器负责采集信息。
   
  4、手机与单片机通信
    首先,约定一个命令 符,当单片机端接收到手机端发送的命令符时,即开始采集传感器信息,将采集到得信息进行加工,然后传给
安卓手机。安卓手机接收数据后,随即显示出来。

   做成此项目用了三天时间,其中两天时间纠结与蓝牙单向通信问题,一直没有眉目。
剩下一天用半天调通手机端蓝牙串口调试软件,半天焊接电路板,写Arduino端程序,连接布线等。



2017-01-06 10:42:06 u010331848 阅读数 1920

最近公司要搞一个智能硬件,通过APP连接硬件,发指令达到某些目的,对于从没有接触过蓝牙的小白,简直是两眼一抹黑,于是从网上找例子,找攻略,例子和代码都不是自己想要的,于是只能求助于谷歌API,拿着某翻译,一个个对着看,终于调试成功了,下面直接上思路及代码。

1、从谷歌官网下载一份demo(通用的),对于任何串口,只要符合规范,这个demo都能调试。

2、谷歌官方代码共有4个类,其中两个比较重要,如下:

BluetoothleService 蓝牙服务:里面有蓝牙的连接,写入命令后,蓝牙所返回的协议(这个协议是厂家给你的)

DeviceControlActivity 设备控制类:连上蓝牙后进入这个界面,会出现一大堆服务,及服务的特征

3、了解两个类,接下来我们要连上蓝牙给单片机发送指令,首先打开DeviceControlActivity类,找到如下代码:

  //如果该char可写
                        if ((charaProp | BluetoothGattCharacteristic.PROPERTY_WRITE) > 0) {
                           LayoutInflater factory = LayoutInflater.from(parent.getContext());
                            final View textEntryView = factory.inflate(R.layout.dialog, null);
                            final EditText editTextName = (EditText) textEntryView.findViewById(R.id.editTextName);
                            final EditText editTextNumEditText = (EditText)textEntryView.findViewById(R.id.editTextNum);
                            AlertDialog.Builder ad1 = new AlertDialog.Builder(parent.getContext());
                            ad1.setTitle("WriteCharacteristic");
                            ad1.setView(textEntryView);
                            ad1.setPositiveButton("确定", new DialogInterface.OnClickListener() {
                                public void onClick(DialogInterface dialog, int i) {
                                    byte[] value = new byte[20];
                                    value[0] = (byte) 0x00;
                                    if(editTextName.getText().length() > 0){
                                        //write string
                                        WriteBytes= editTextName.getText().toString().getBytes();
                                    }else if(editTextNumEditText.getText().length() > 0){
                                        WriteBytes= hex2byte(editTextNumEditText.getText().toString().getBytes());
                                    }
                                    characteristic.setValue(value[0],
                                            BluetoothGattCharacteristic.FORMAT_UINT8, 0);
                                    characteristic.setValue(WriteBytes);
                                    mBluetoothLeService.writeCharacteristic(characteristic);
                                }
                            });
                            ad1.setNegativeButton("取消", new DialogInterface.OnClickListener() {
                                public void onClick(DialogInterface dialog, int i) {


                                }
                            });
                            ad1.show();
                        }

以上这段代码就是写入命令的代码,起初我在这里栽了跟头,发现一件事,直接输入命令,此处的返回和协议文档是对不上的,于是我做了如下修改:

if ((charaProp | BluetoothGattCharacteristic.PROPERTY_WRITE) > 0) {
                            byte[] bytes = hexStringToBytes("
XXXXXXXXXXXX");
//                            characteristic.setValue(new byte[]{0x
XX,0xXX,0xXX,0xXX,0xXX, (byte) 0xB2, (byte) 0xXX});
                            characteristic.setValue(bytes);
                            boolean status = mBluetoothLeService.writeCharacteristic(characteristic);
                            Log.e("shjysoft_info","状态:"+status);
                        }

先把协议的16进制的字符串变成字节,然后放到特征里面,写进去,然后就成功了,但是没有接触过蓝牙的朋友会有疑问,给哪个服务哪个特征写,这边我也遇到 过,我跑过去问前辈们,前辈们说了一句,一个一个试,没错,你一个一个点,哪个返回正确就是哪个。

2018-08-31 17:13:57 u010898329 阅读数 6996

系列博文:

(1)安卓手机与蓝牙模块联合调试(一)——蓝牙模块的串口通讯 

(2)安卓手机与蓝牙模块联合调试(二)—— 单片机蓝牙控制LED灯亮灭(上)

(3)安卓手机与蓝牙模块联合调试(三)—— 单片机蓝牙控制LED灯亮灭(下)

本教程的项目地址:1989Jiangtao/BluetoothSCM: 安卓手机通过蓝牙与单片机通信-发送指令/接收数据​​​​​​​


继续承接上两篇文章,这一篇会写下使用STC89单片机编程,蓝牙接收数据,控制LED灯的亮灭。

安卓手机与蓝牙模块联合调试(二)—— 单片机蓝牙控制LED灯亮灭(上)

安卓手机与蓝牙模块联合调试(一)——蓝牙模块的串口通讯
 

1.首先看下使用到的工具和软件。

(1)先看下硬件工具需要哪些。

一个USB转串口下载器(CH340),蓝牙模块(先用HC-05做本次调试,下次一并讲CC2541),一块含有STC89单片机的最小板(这里我用的是自己闲时画的一块小板,含红外和OLED显示屏,还有一颗RGB灯),来个全家福。

(2)看下要使用的软件。

此次开发编译工具使用KEIL,keil需要大家自行下载安装和破解。

程序下载使用STC官方的下载工具,附上下载链接:http://www.stcmcudata.com/STCISP/stc-isp-15xx-v6.86O.zip

 

2.编程后做些简单的测试。

       其实简单来讲,蓝牙传输数据依据的就是串口通讯,如果你搞明白了单片机的串口通讯,那么编程就变得相当简单了。下面带大家开始撸代码,这一段的话仅针对单片机初级选手而言,老鸟不喜勿喷。

(1)直接使用工具自带的程序来实现串口通讯。

       先教新手偷个懒,如何使用STC-ISP来直接下载串口代码。直接上图了。

       这样下载后代码是可以直接运行的,下面我来个截图,主要是我的板子上接的是P2口,8个LED灯,直接用指示灯来指示收到的数据。

因此我在拷贝下来的代码中又改了些地方,主要是用来做指示灯的指示用的,也给大家截个图。

这个是STC-ISP自带的程序,大家可以研究下,这里的SBUF表示的是收到的数据。我就偷个懒直接改了下,主要演示用。下面看下实际的效果,由于不能上传视频,就只能用图片来做说明了。还是通过蓝牙串口发送指令,这次是直接发送的16进制指令,STC单片机接收后,通过P2口指示灯来输出显示发送的指令值。

 

(2)自己撸代码实现串口通讯。

     上面我是直接偷懒了 ,下面带大家撸代码了,单片机串口的代码其实网上有很多可以参考的,下面上代码。

/****************************************
**       蓝牙串口接收数据
** 
**   作者:江涛
**   时间:2018/08/31
**   描述:串口发送数据兼用OLED显示
****************************************/
#include "STC89C5xRC_RDP.h"
#include "string.h"     // 要使用字符串对比函数,需要引入该头文件
#include "OLED.h"       // OLED显示屏头文件

// 定义系统时钟和串口波特率
#define FOSC 11059200L      // 系统时钟
#define BAUD 9600           // 串口波特率

/******变量声明*********/ 
char RECEIVED_CMD[10] ;       // 暂定为10字节的指令
char RECEIVED_INDEX ;         // 数组指示索引,当接收到一个数据之后,索引会跟随增加
unsigned char flag = 0 ;      // 数据接收的标志位

/******命令常量*******/
code const char* LED_ON = "ON\r\n" ;
code const char* LED_OFF = "OFF\r\n" ;

/*******函数声明*********/
void Init_UART(); // 初始化串口
void UART_SendData(char dat); // 串口发送数据
void UART_SendStr(char* str); // 串口发送字符串

/*******程序入口*********/
void main() 
{

	Init_UART();  // 串口初始化
	
//	LCD_Init();  // OLED 初始化
//	LCD_CLS();   // 清屏
//	
//	LCD_P8x16Str(0 , 0 , "CODE:"); 
	
	while(1)
	{
		if(flag) // 接收数据完毕一次,就会进入中断一次
		{
			flag = 0 ; // 将标志位还原,使得串口又可以重新接收数据
			
			
			UART_SendStr(RECEIVED_CMD); // 接收到的数据通过串口发送回去
			
//			LCD_P8x16Str(6*8 , 0 , RECEIVED_CMD); // 显示接收代码
			
//			P2 = ~P2 ; // 翻转P2口的灯,用来测试接收到了数据
			if(strcmp(RECEIVED_CMD , LED_ON) == 0)
			{
				P2 = 0xFF ; // P2口全亮
			}
			else if(strcmp(RECEIVED_CMD , LED_OFF) == 0)
			{
				P2 = 0x00 ; // P2口全灭
			}
			
			// 用完之后要记得数组清零处理
      RECEIVED_INDEX = 0 ;        // 数组指引复位
      memset(RECEIVED_CMD,0,10);  // 清0数组
		}
	}
}

/******************
** 初始化串口
*******************/
void Init_UART()
{
		SCON = 0x50;                     //设置8位数据位
		TMOD = 0x20;                     //8位自动重载
		TH1 = TL1 = -(FOSC/12/32/BAUD);  //设置重载值
		TR1 = 1;                         //使能时钟
		ES = 1;                          //使能串口中断
		EA = 1;                          //开中断开关
}

/********************
** 串口中断处理
*********************/
void UART_Isr() interrupt 4 using 1
{
	// 串口接收中断处理
	if(RI) 
	{
		RI = 0 ;                              // 清除中断标志位
		RECEIVED_CMD[RECEIVED_INDEX] = SBUF ; // 保存串口接收的数据
		if(RECEIVED_CMD[RECEIVED_INDEX] == 0x0A ){ // 遇到了结束符号
			 flag = 1 ;           // 接收结束,到循环中处理接收的数据
		}else {
			 RECEIVED_INDEX ++ ;   // 继续接收数据
		}
	}

	// 串口发送中断处理
	if(TI)
	{
		TI = 0 ;  // 清发送中断标志位
	}
		
}

/**************************
** 通过串口发送一位数据
***************************/
void UART_SendData(char dat)
{
	ES = 0 ;      // 串口工作的时候禁止中断
	SBUF = dat ;  // 待发送的数据放到SBUF中
	while(!TI) ;  // 等待发送完毕
	TI = 0 ;      // 清TI中断
	ES = 1 ;      // 打开中断
}

/*****************************
**  通过串口发送字符串
******************************/
void UART_SendStr(char *str)
{
		do
		{
			UART_SendData(*str);
		}while(*str ++  != '\0' ); // 一直到字符串结束
}

本来是有一个OLED显示的,为了方便大家理解,我直接把OLED部分去掉了,代码中定义了两个命令,LED_ON 和LED_OFF, 注意事项,如果你是直接拷贝的话应该是不能运行的。因为安卓的换行对应的只有“\n”,所以拷贝后应该把命令换成如下格式,安卓调试助手才能识别开关灯的命令。

/******命令常量*******/
code const char* LED_ON = "ON\n" ;
code const char* LED_OFF = "OFF\n" ;

 看下运行后的效果,

 

3.小结。

好了,至此第一阶段单片机和蓝牙的通讯部分已经基本搞定,其实主要就是单片机的串口通讯的应用,下面的文章将围绕开发一个自己的安卓蓝牙应用为主要内容展开。

 



 

2019-09-27 13:54:40 OuNuo5280 阅读数 48

单片机连接手机应用客户端进行蓝牙通讯:

学习了!!!!分享:

package com.severn;

import java.util.ArrayList;

import android.app.Activity;
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.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

import com.severn.ui.Ble_Activity;


/**
 * @Description: TODO<MainActivity类实现打开蓝牙、扫描蓝牙>
 */
public class MainActivity extends Activity implements OnClickListener {
	// 扫描蓝牙按钮
	private Button scan_btn;
	// 蓝牙适配器
	BluetoothAdapter mBluetoothAdapter;
	// 蓝牙信号强度
	private ArrayList<Integer> rssis;
	// 自定义Adapter
	LeDeviceListAdapter mleDeviceListAdapter;
	// listview显示扫描到的蓝牙信息
	ListView lv;
	// 描述扫描蓝牙的状态
	private boolean mScanning;
	private boolean scan_flag;
	private Handler mHandler;
	int REQUEST_ENABLE_BT = 1;
	// 蓝牙扫描时间
	private static final long SCAN_PERIOD = 10000;

	@Override
	protected void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		// 初始化控件
		init();
		// 初始化蓝牙
		init_ble();
		scan_flag = true;
		// 自定义适配器
		mleDeviceListAdapter = new LeDeviceListAdapter();
		// 为listview指定适配器
		lv.setAdapter(mleDeviceListAdapter);

		/* listview点击函数 */
		lv.setOnItemClickListener(new AdapterView.OnItemClickListener()
		{

			@Override
			public void onItemClick(AdapterView<?> arg0, View v, int position,
					long id)
			{
				// TODO Auto-generated method stub
				final BluetoothDevice device = mleDeviceListAdapter
						.getDevice(position);
				if (device == null)
					return;
				final Intent intent = new Intent(MainActivity.this,
						Ble_Activity.class);
				intent.putExtra(Ble_Activity.EXTRAS_DEVICE_NAME,
						device.getName());
				intent.putExtra(Ble_Activity.EXTRAS_DEVICE_ADDRESS,
						device.getAddress());
				if (mScanning)
				{
					/* 停止扫描设备 */
					mBluetoothAdapter.stopLeScan(mLeScanCallback);
					mScanning = false;
				}

				try
				{
					// 启动Ble_Activity
					startActivity(intent);
				} catch (Exception e)
				{
					e.printStackTrace();
					// TODO: handle exception
				}

			}
		});

	}

	/**
	 * @Title: init
	 * @Description: TODO(初始化UI控件)
	 * @return void
	 * @throws
	 */
	private void init()
	{
		scan_btn =  this.findViewById(R.id.scan_dev_btn);
		scan_btn.setOnClickListener(this);
		lv =  this.findViewById(R.id.lv);
		mHandler = new Handler();
	}

	/**
	 * @Title: init_ble
	 * @Description: TODO(初始化蓝牙)
	 * @return void
	 * @throws
	 */
	private void init_ble()
	{
		// 手机硬件支持蓝牙
		if (!getPackageManager().hasSystemFeature(
				PackageManager.FEATURE_BLUETOOTH_LE))
		{
			Toast.makeText(this, "不支持BLE", Toast.LENGTH_SHORT).show();
			finish();
		}
		// Initializes Bluetooth adapter.
		// 获取手机本地的蓝牙适配器
		final BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
		mBluetoothAdapter = bluetoothManager.getAdapter();
		// 打开蓝牙权限
		if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled())
		{
			Intent enableBtIntent = new Intent(
					BluetoothAdapter.ACTION_REQUEST_ENABLE);
			startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
		}

	}

	/*
	 * 按钮响应事件
	 */
	@Override
	public void onClick(View v)
	{
		// TODO Auto-generated method stub

		if (scan_flag)
		{
			mleDeviceListAdapter = new LeDeviceListAdapter();
			lv.setAdapter(mleDeviceListAdapter);
			scanLeDevice(true);
		} else
		{

			scanLeDevice(false);
			scan_btn.setText("扫描设备");
		}
	}

	/**
	 * @Title: scanLeDevice
	 * @Description: TODO(扫描蓝牙设备 )
	 * @param enable
	 *            (扫描使能,true:扫描开始,false:扫描停止)
	 * @return void
	 * @throws
	 */
	private void scanLeDevice(final boolean enable)
	{
		if (enable)
		{
			// Stops scanning after a pre-defined scan period.
			mHandler.postDelayed(new Runnable()
			{
				@Override
				public void run()
				{
					mScanning = false;
					scan_flag = true;
					scan_btn.setText("扫描设备");
					Log.i("SCAN", "stop.....................");
					mBluetoothAdapter.stopLeScan(mLeScanCallback);
				}
			}, SCAN_PERIOD);
			/* 开始扫描蓝牙设备,带mLeScanCallback 回调函数 */
			Log.i("SCAN", "begin.....................");
			mScanning = true;
			scan_flag = false;
			scan_btn.setText("停止扫描");
			mBluetoothAdapter.startLeScan(mLeScanCallback);
		} else
		{
			Log.i("Stop", "stoping................");
			mScanning = false;
			mBluetoothAdapter.stopLeScan(mLeScanCallback);
			scan_flag = true;
		}

	}

	/**
	 * 蓝牙扫描回调函数 实现扫描蓝牙设备,回调蓝牙BluetoothDevice,可以获取name MAC等信息
	 * 
	 * **/
	private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback()
	{

		@Override
		public void onLeScan(final BluetoothDevice device, final int rssi,
				byte[] scanRecord)
		{
			// TODO Auto-generated method stub

			runOnUiThread(new Runnable()
			{
				@Override
				public void run()
				{

						/* 讲扫描到设备的信息输出到listview的适配器 */
						mleDeviceListAdapter.addDevice(device);
						mleDeviceListAdapter.notifyDataSetChanged();

				}
			});

	

		}
	};

	/**
	 * @Description: TODO<自定义适配器Adapter,作为listview的适配器>
	 * @version: V1.0
	 */
	private class LeDeviceListAdapter extends BaseAdapter {
		private ArrayList<BluetoothDevice> mLeDevices;

		private LayoutInflater mInflator;

		public LeDeviceListAdapter()
		{
			super();
			//rssis = new ArrayList();
			mLeDevices = new ArrayList();
			mInflator = 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();
			rssis.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;
		}

		/**
		 * 重写getview
		 * 
		 * **/
		@Override
		public View getView(int i, View view, ViewGroup viewGroup)
		{

			// General ListView optimization code.
			// 加载listview每一项的视图
			view = mInflator.inflate(R.layout.listitem, null);
			// 初始化三个textview显示蓝牙信息
			//TextView deviceAddress =  view
			//		.findViewById(R.id.tv_deviceAddr);
			TextView deviceName =  view
					.findViewById(R.id.tv_deviceName);
			//TextView rssi =view.findViewById(R.id.tv_rssi);

			BluetoothDevice device = mLeDevices.get(i);
			//deviceAddress.setText(device.getAddress());
			deviceName.setText(device.getName());
			//rssi.setText("" + rssis.get(i));

			return view;
		}
	}

}

main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="${relativePackage}.${activityClass}" 
    >

   <Button 
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:layout_marginLeft="20dip"
       android:layout_marginRight="20dip"
       android:layout_marginTop="30dip"
       android:text="扫描设备"
       android:id="@+id/scan_dev_btn"
       
       
       />

   <ListView
       android:id="@+id/lv"
       android:layout_marginTop="100dip"
       android:layout_marginLeft="20dip"
       android:layout_marginRight="20dip"
       android:layout_width="match_parent"
       android:layout_height="match_parent"
       android:layout_marginBottom="50dip" >
</ListView>

</RelativeLayout>

listyview.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" 
    android:background="@drawable/bg_button">

    <LinearLayout
        android:layout_width="match_parent"
        android:background="#00BA79"
        android:layout_height="wrap_content" >

        <TextView
            android:id="@+id/textView1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textColor="#ffffff"
            android:textSize="25dp"
            android:text="设备名称:" />

        <TextView
            android:id="@+id/tv_deviceName"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textColor="#ffffff"
            android:textSize="25dp"
            android:text="TextView" />

    </LinearLayout>


</LinearLayout>

Ble_activity

package com.severn.ui;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import com.severn.service.*;
import android.app.Activity;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattService;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ScrollView;
import android.widget.TextView;

import com.severn.R;
import com.severn.service.BluetoothLeService;



/** 
 * @Description:  TODO<Ble_Activity实现连接BLE,发送和接受BLE的数据> 

 */ 
public class Ble_Activity extends Activity implements OnClickListener {

	private final static String TAG = Ble_Activity.class.getSimpleName();
	//蓝牙4.0的UUID,其中0000ffe1-0000-1000-8000-00805f9b34fb是广州汇承信息科技有限公司08蓝牙模块的UUID
	public static String HEART_RATE_MEASUREMENT = "0000ffe1-0000-1000-8000-00805f9b34fb";
	public static String EXTRAS_DEVICE_NAME = "DEVICE_NAME";;
	public static String EXTRAS_DEVICE_ADDRESS = "DEVICE_ADDRESS";
	public static String EXTRAS_DEVICE_RSSI = "RSSI";
	//蓝牙连接状态
	private boolean mConnected = false;
	private String status = "disconnected";
	//蓝牙名字
	private String mDeviceName;
	//蓝牙地址
	private String mDeviceAddress;
	//蓝牙信号值
	private String mRssi;
	private Bundle b;
	private String rev_str = "";
	//蓝牙service,负责后台的蓝牙服务
	private static BluetoothLeService mBluetoothLeService;
	//文本框,显示接受的内容
	private TextView rev_tv, connect_state;
	//发送按钮
	private Button send_btn;
	//文本编辑框
	private EditText send_et;
	private ScrollView rev_sv;
	private ArrayList<ArrayList<BluetoothGattCharacteristic>> mGattCharacteristics = new ArrayList<ArrayList<BluetoothGattCharacteristic>>();
	//蓝牙特征值
	private static BluetoothGattCharacteristic target_chara = null;
	private Handler mhandler = new Handler();
	private Handler myHandler = new Handler()
	{
		// 2.重写消息处理函数
		public void handleMessage(Message msg)
		{
			switch (msg.what)
			{
			// 判断发送的消息
			case 1:
			{
				// 更新View
				String state = msg.getData().getString("connect_state");
				connect_state.setText(state);

				break;
			}

			}
			super.handleMessage(msg);
		}

	};

	@Override
	protected void onCreate(Bundle savedInstanceState)
	{
		// TODO Auto-generated method stub
		super.onCreate(savedInstanceState);
		setContentView(R.layout.ble_activity);
		b = getIntent().getExtras();
		//从意图获取显示的蓝牙信息
		mDeviceName = b.getString(EXTRAS_DEVICE_NAME);
		mDeviceAddress = b.getString(EXTRAS_DEVICE_ADDRESS);
		//mRssi = b.getString(EXTRAS_DEVICE_RSSI);

		/* 启动蓝牙service */
		Intent gattServiceIntent = new Intent(this, BluetoothLeService.class);
		bindService(gattServiceIntent, mServiceConnection, BIND_AUTO_CREATE);
		init();

	}

	@Override
	protected void onDestroy()
	{
		super.onDestroy();
        //解除广播接收器
		unregisterReceiver(mGattUpdateReceiver);
		mBluetoothLeService = null;
	}

	// Activity出来时候,绑定广播接收器,监听蓝牙连接服务传过来的事件
	@Override
	protected void onResume()
	{
		super.onResume();
		//绑定广播接收器
		registerReceiver(mGattUpdateReceiver, makeGattUpdateIntentFilter());
		if (mBluetoothLeService != null)
		{    
			//根据蓝牙地址,建立连接
			final boolean result = mBluetoothLeService.connect(mDeviceAddress);
			Log.d(TAG, "Connect request result=" + result);
		}
	}

	/** 
	* @Title: init 
	* @Description: TODO(初始化UI控件) 
	* @param  无
	* @return void    
	* @throws 
	*/ 
	private void init()
	{
		rev_sv = (ScrollView) this.findViewById(R.id.rev_sv);
		rev_tv = (TextView) this.findViewById(R.id.rev_tv);
		connect_state = (TextView) this.findViewById(R.id.connect_state);
		send_btn = (Button) this.findViewById(R.id.send_btn);
		send_et = (EditText) this.findViewById(R.id.send_et);
		connect_state.setText(status);
		send_btn.setOnClickListener(this);

	}

	/* BluetoothLeService绑定的回调函数 */
	private final ServiceConnection mServiceConnection = new ServiceConnection()
	{

		@Override
		public void onServiceConnected(ComponentName componentName,
				IBinder service)
		{
			mBluetoothLeService = ((BluetoothLeService.LocalBinder) service)
					.getService();
			if (!mBluetoothLeService.initialize())
			{
				Log.e(TAG, "Unable to initialize Bluetooth");
				finish();
			}

			// 根据蓝牙地址,连接设备
			mBluetoothLeService.connect(mDeviceAddress);

		}

		@Override
		public void onServiceDisconnected(ComponentName componentName)
		{
			mBluetoothLeService = null;
		}

	};

	/**
	 * 广播接收器,负责接收BluetoothLeService类发送的数据
	 */
	private final BroadcastReceiver mGattUpdateReceiver = new BroadcastReceiver()
	{
		@Override
		public void onReceive(Context context, Intent intent)
		{
			final String action = intent.getAction();
			if (BluetoothLeService.ACTION_GATT_CONNECTED.equals(action))//Gatt连接成功
			{
				mConnected = true;
				status = "connected";
				//更新连接状态
				updateConnectionState(status);
				System.out.println("BroadcastReceiver :" + "device connected");

			} else if (BluetoothLeService.ACTION_GATT_DISCONNECTED//Gatt连接失败
					.equals(action))
			{
				mConnected = false;
				status = "disconnected";
				//更新连接状态
				updateConnectionState(status);
				System.out.println("BroadcastReceiver :"
						+ "device disconnected");

			} else if (BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED//发现GATT服务器
					.equals(action))
			{
				// Show all the supported services and characteristics on the
				// user interface.
				//获取设备的所有蓝牙服务
				displayGattServices(mBluetoothLeService
						.getSupportedGattServices());
				System.out.println("BroadcastReceiver :"
						+ "device SERVICES_DISCOVERED");
			} else if (BluetoothLeService.ACTION_DATA_AVAILABLE.equals(action))//有效数据
			{    
				 //处理发送过来的数据
				displayData(intent.getExtras().getString(
						BluetoothLeService.EXTRA_DATA));
				System.out.println("BroadcastReceiver onData:"
						+ intent.getStringExtra(BluetoothLeService.EXTRA_DATA));
			}
		}
	};

	/* 更新连接状态 */
	private void updateConnectionState(String status)
	{
		Message msg = new Message();
		msg.what = 1;
		Bundle b = new Bundle();
		b.putString("connect_state", status);
		msg.setData(b);
		//将连接状态更新的UI的textview上
		myHandler.sendMessage(msg);
		System.out.println("connect_state:" + status);

	}

	/* 意图过滤器 */
	private static IntentFilter makeGattUpdateIntentFilter()
	{
		final IntentFilter intentFilter = new IntentFilter();
		intentFilter.addAction(BluetoothLeService.ACTION_GATT_CONNECTED);
		intentFilter.addAction(BluetoothLeService.ACTION_GATT_DISCONNECTED);
		intentFilter
				.addAction(BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED);
		intentFilter.addAction(BluetoothLeService.ACTION_DATA_AVAILABLE);
		return intentFilter;
	}

	/** 
	* @Title: displayData 
	* @Description: TODO(接收到的数据在scrollview上显示) 
	* @param @param rev_string(接受的数据)
	* @return void   
	* @throws 
	*/ 
	private void displayData(String rev_string)
	{
		rev_str += rev_string;
		runOnUiThread(new Runnable()
		{
			@Override
			public void run()
			{
				rev_tv.setText(rev_str);
				rev_sv.scrollTo(0, rev_tv.getMeasuredHeight());
				System.out.println("rev:" + rev_str);
			}
		});

	}

	/** 
	* @Title: displayGattServices 
	* @Description: TODO(处理蓝牙服务) 
	* @param 无  
	* @return void  
	* @throws 
	*/ 
	private void displayGattServices(List<BluetoothGattService> gattServices)
	{

		if (gattServices == null)
			return;
		String uuid = null;
		// 服务数据,可扩展下拉列表的第一级数据
		ArrayList<HashMap<String, String>> gattServiceData = new ArrayList<HashMap<String, String>>();

		// 特征数据(隶属于某一级服务下面的特征值集合)
		ArrayList<ArrayList<HashMap<String, String>>> gattCharacteristicData = new ArrayList<ArrayList<HashMap<String, String>>>();

		// 部分层次,所有特征值集合
		mGattCharacteristics = new ArrayList<ArrayList<BluetoothGattCharacteristic>>();

		// Loops through available GATT Services.
		for (BluetoothGattService gattService : gattServices)
		{

			// 获取服务列表
			HashMap<String, String> currentServiceData = new HashMap<String, String>();
			uuid = gattService.getUuid().toString();

			// 查表,根据该uuid获取对应的服务名称。SampleGattAttributes这个表需要自定义。

			gattServiceData.add(currentServiceData);

			System.out.println("Service uuid:" + uuid);

			ArrayList<HashMap<String, String>> gattCharacteristicGroupData = new ArrayList<HashMap<String, String>>();

			// 从当前循环所指向的服务中读取特征值列表
			List<BluetoothGattCharacteristic> gattCharacteristics = gattService
					.getCharacteristics();

			ArrayList<BluetoothGattCharacteristic> charas = new ArrayList<BluetoothGattCharacteristic>();

			// Loops through available Characteristics.
			// 对于当前循环所指向的服务中的每一个特征值
			for (final BluetoothGattCharacteristic gattCharacteristic : gattCharacteristics)
			{
				charas.add(gattCharacteristic);
				HashMap<String, String> currentCharaData = new HashMap<String, String>();
				uuid = gattCharacteristic.getUuid().toString();

				if (gattCharacteristic.getUuid().toString()
						.equals(HEART_RATE_MEASUREMENT))
				{
					// 测试读取当前Characteristic数据,会触发mOnDataAvailable.onCharacteristicRead()
					mhandler.postDelayed(new Runnable()
					{

						@Override
						public void run()
						{
							// TODO Auto-generated method stub
							mBluetoothLeService
									.readCharacteristic(gattCharacteristic);
						}
					}, 200);

					// 接受Characteristic被写的通知,收到蓝牙模块的数据后会触发mOnDataAvailable.onCharacteristicWrite()
					mBluetoothLeService.setCharacteristicNotification(
							gattCharacteristic, true);
					target_chara = gattCharacteristic;
					// 设置数据内容
					// 往蓝牙模块写入数据
					// mBluetoothLeService.writeCharacteristic(gattCharacteristic);
				}
				List<BluetoothGattDescriptor> descriptors = gattCharacteristic
						.getDescriptors();
				for (BluetoothGattDescriptor descriptor : descriptors)
				{
					System.out.println("---descriptor UUID:"
							+ descriptor.getUuid());
					// 获取特征值的描述
					mBluetoothLeService.getCharacteristicDescriptor(descriptor);
					// mBluetoothLeService.setCharacteristicNotification(gattCharacteristic,
					// true);
				}

				gattCharacteristicGroupData.add(currentCharaData);
			}
			// 按先后顺序,分层次放入特征值集合中,只有特征值
			mGattCharacteristics.add(charas);
			// 构件第二级扩展列表(服务下面的特征值)
			gattCharacteristicData.add(gattCharacteristicGroupData);

		}

	}
	/**
	 * 将数据分包
	 * 
	 * **/
	public int[] dataSeparate(int len)
	{   
		int[] lens = new int[2];
		lens[0]=len/20;
		lens[1]=len-20*lens[0];
		return lens;
	}
	
	

	/* 
	 * 发送按键的响应事件,主要发送文本框的数据
	 */
	@Override
	public void onClick(View v)
	{
		// TODO Auto-generated method stub
		byte[] buff = send_et.getText().toString().getBytes();
		int len = buff.length;
		int[] lens = dataSeparate(len);
		for(int i =0;i<lens[0];i++)
		{
		String str = new String(buff, 20*i, 20);
		target_chara.setValue(str);//只能一次发送20字节,所以这里要分包发送
		//调用蓝牙服务的写特征值方法实现发送数据
		mBluetoothLeService.writeCharacteristic(target_chara);
		}
		if(lens[1]!=0)
		{
			String str = new String(buff, 20*lens[0], lens[1]);
			target_chara.setValue(str);
			//调用蓝牙服务的写特征值方法实现发送数据
			mBluetoothLeService.writeCharacteristic(target_chara);
			
		}
	}

}

ble_activity.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >
     
    
    <LinearLayout 
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <TextView 
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="状态:"
            android:layout_marginLeft="10dip"
            />
         <TextView 
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             
             android:id="@+id/connect_state"
             />
        
    </LinearLayout>
    
    <ScrollView
          android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:id="@+id/rev_sv"
        
       >
        <TextView 
         android:layout_width="fill_parent"
        android:layout_height="wrap_content"
      android:id="@+id/rev_tv"
            />
        
        
        
    </ScrollView>

    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom"
       
        android:orientation="horizontal" >

        <EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:id="@+id/send_et"
            android:typeface="normal" 
            >

            
        </EditText>

        <Button
            android:id="@+id/send_btn"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_weight="3"
            android:text="send" 
           
            />
    </LinearLayout>
     
</LinearLayout>

BluetoothLeService.class

package com.severn.service;

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

import android.app.Service;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.content.Intent;
import android.hardware.Sensor;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;



/** 
 * @Description:  TODO<蓝牙服务,负责在后台实现蓝牙的连接,数据的发送接受> 

 */ 
public class BluetoothLeService extends Service {
	private final static String TAG = "BluetoothLeService";// luetoothLeService.class.getSimpleName();
	private List<Sensor> mEnabledSensors = new ArrayList<Sensor>();
	//蓝牙相关类
	private BluetoothManager mBluetoothManager;
	private BluetoothAdapter mBluetoothAdapter;
	private String mBluetoothDeviceAddress;
	private BluetoothGatt mBluetoothGatt;
	private int mConnectionState = STATE_DISCONNECTED;

	private static final int STATE_DISCONNECTED = 0;
	private static final int STATE_CONNECTING = 1;
	private static final int STATE_CONNECTED = 2;

	public final static String ACTION_GATT_CONNECTED = "com.hc_ble.bluetooth.le.ACTION_GATT_CONNECTED";
	public final static String ACTION_GATT_DISCONNECTED = "com.hc_ble.bluetooth.le.ACTION_GATT_DISCONNECTED";
	public final static String ACTION_GATT_SERVICES_DISCOVERED = "com.hc_ble.bluetooth.le.ACTION_GATT_SERVICES_DISCOVERED";
	public final static String ACTION_DATA_AVAILABLE = "com.hc_ble.bluetooth.le.ACTION_DATA_AVAILABLE";
	public final static String EXTRA_DATA = "com.hc_ble.bluetooth.le.EXTRA_DATA";

	// public final static UUID UUID_HEART_RATE_MEASUREMENT =zzzzzzzzzzzzz
	// UUID.fromString(SampleGattAttributes.HEART_RATE_MEASUREMENT);
	private OnDataAvailableListener mOnDataAvailableListener;

	// Implements callback methods for GATT events that the app cares about. For
	// example,
	// connection change and services discovered.

	public interface OnDataAvailableListener {
		public void onCharacteristicRead(BluetoothGatt gatt,
				BluetoothGattCharacteristic characteristic, int status);

		public void onCharacteristicWrite(BluetoothGatt gatt,
				BluetoothGattCharacteristic characteristic);

		public void onCharacteristicChanged(BluetoothGatt gatt,
				BluetoothGattCharacteristic characteristic);
	}

	public void setOnDataAvailableListener(OnDataAvailableListener l)
	{
		mOnDataAvailableListener = l;
	}

	/* 连接远程设备的回调函数 */
	private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback()
	{
		@Override
		public void onConnectionStateChange(BluetoothGatt gatt, int status,
				int newState)
		{
			String intentAction;
			if (newState == BluetoothProfile.STATE_CONNECTED)//连接成功
			{
				intentAction = ACTION_GATT_CONNECTED;
				mConnectionState = STATE_CONNECTED;
				/* 通过广播更新连接状态 */
				broadcastUpdate(intentAction);
				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)//连接失败
			{
				intentAction = ACTION_GATT_DISCONNECTED;
				mConnectionState = STATE_DISCONNECTED;
				Log.i(TAG, "Disconnected from GATT server.");
				broadcastUpdate(intentAction);
			}
		}
        /*
         * 重写onServicesDiscovered,发现蓝牙服务
         * 
         * */
		@Override
		public void onServicesDiscovered(BluetoothGatt gatt, int status)
		{
			if (status == BluetoothGatt.GATT_SUCCESS)//发现到服务
			{
				broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);
				Log.i(TAG, "--onServicesDiscovered called--");
			} else
			{
				Log.w(TAG, "onServicesDiscovered received: " + status);
				System.out.println("onServicesDiscovered received: " + status);
			}
		}
         /*
          * 特征值的读写
          * */
		@Override
		public void onCharacteristicRead(BluetoothGatt gatt,
				BluetoothGattCharacteristic characteristic, int status)
		{
			if (status == BluetoothGatt.GATT_SUCCESS)
			{
				Log.i(TAG, "--onCharacteristicRead called--");
				//从特征值读取数据
				byte[] sucString = characteristic.getValue();
				String string = new String(sucString);
				//将数据通过广播到Ble_Activity
				broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
			}
			
		}
         /*
          * 特征值的改变
          * */
		@Override
		public void onCharacteristicChanged(BluetoothGatt gatt,
				BluetoothGattCharacteristic characteristic)
		{
			
			broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
	
		}
        /*
         * 特征值的写
         * */
		@Override
		public void onCharacteristicWrite(BluetoothGatt gatt,
				BluetoothGattCharacteristic characteristic, int status)
		{
			
			
			// 以下语句实现 发送完数据或也显示到界面上
			//broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
		}
        /*
         * 读描述值
         * */
		@Override
		public void onDescriptorRead(BluetoothGatt gatt,
				BluetoothGattDescriptor descriptor, int status)
		{
			// TODO Auto-generated method stub
			// super.onDescriptorRead(gatt, descriptor, status);
			Log.w(TAG, "----onDescriptorRead status: " + status);
			byte[] desc = descriptor.getValue();
			if (desc != null)
			{
				Log.w(TAG, "----onDescriptorRead value: " + new String(desc));
			}

		}
         /*
          * 写描述值
          * */
		@Override
		public void onDescriptorWrite(BluetoothGatt gatt,
				BluetoothGattDescriptor descriptor, int status)
		{
			// TODO Auto-generated method stub
			// super.onDescriptorWrite(gatt, descriptor, status);
			Log.w(TAG, "--onDescriptorWrite--: " + status);
		}
         /*
          * 读写蓝牙信号值
          * */
		@Override
		public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status)
		{
			// TODO Auto-generated method stub
			// super.onReadRemoteRssi(gatt, rssi, status);
			Log.w(TAG, "--onReadRemoteRssi--: " + status);
			broadcastUpdate(ACTION_DATA_AVAILABLE, rssi);
		}

		@Override
		public void onReliableWriteCompleted(BluetoothGatt gatt, int status)
		{
			// TODO Auto-generated method stub
			// super.onReliableWriteCompleted(gatt, status);
			Log.w(TAG, "--onReliableWriteCompleted--: " + status);
		}

	};
    //广播意图
	private void broadcastUpdate(final String action, int rssi)
	{
		final Intent intent = new Intent(action);
		intent.putExtra(EXTRA_DATA, String.valueOf(rssi));
		sendBroadcast(intent);
	}
     //广播意图
	private void broadcastUpdate(final String action)
	{
		final Intent intent = new Intent(action);
		sendBroadcast(intent);
	}

	/* 广播远程发送过来的数据 */
	public void broadcastUpdate(final String action,
			final BluetoothGattCharacteristic characteristic)
	{
		final Intent intent = new Intent(action);
		//从特征值获取数据
		final byte[] data = characteristic.getValue();
		if (data != null && data.length > 0)
		{
			final StringBuilder stringBuilder = new StringBuilder(data.length);
			for (byte byteChar : data)
			{
				stringBuilder.append(String.format("%02X ", byteChar));

				Log.i(TAG, "***broadcastUpdate: byteChar = " + byteChar);

			}
			intent.putExtra(EXTRA_DATA, new String(data));
			System.out.println("broadcastUpdate for  read data:"
					+ new String(data));
		}
		sendBroadcast(intent);
	}

	public class LocalBinder extends Binder {
		public BluetoothLeService getService()
		{
			return BluetoothLeService.this;
		}
	}

	@Override
	public IBinder onBind(Intent intent)
	{
		return mBinder;
	}

	@Override
	public boolean onUnbind(Intent intent)
	{
		close();
		return super.onUnbind(intent);
	}

	private final IBinder mBinder = new LocalBinder();
	
	

	/**
	 * Initializes a reference to the local Bluetooth adapter.
	 * 
	 * @return Return true if the initialization is successful.
	 */
	/* service 中蓝牙初始化 */
	public boolean initialize()
	{
		// For API level 18 and above, get a reference to BluetoothAdapter
		// through
		// BluetoothManager.
		if (mBluetoothManager == null)
		{   //获取系统的蓝牙管理器
			mBluetoothManager = (BluetoothManager) 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())//连接蓝牙,其实就是调用BluetoothGatt的连接方法
			{
				mConnectionState = STATE_CONNECTING;
				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.
		/* 调用device中的connectGatt连接到远程设备 */
		mBluetoothGatt = device.connectGatt(this, false, mGattCallback);
		Log.d(TAG, "Trying to create a new connection.");
		mBluetoothDeviceAddress = address;
		mConnectionState = STATE_CONNECTING;
		System.out.println("device.getBondState==" + device.getBondState());
		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.
	 */
	/*
	 * 取消连接
	 * 
	 * */
	/** 
	* @Title: disconnect 
	* @Description: TODO(取消蓝牙连接) 
	* @param   无
	* @return void    
	* @throws 
	*/ 
	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.
	 */
	/** 
	* @Title: close 
	* @Description: TODO(关闭所有蓝牙连接) 
	* @param  无
	* @return void   
	* @throws 
	*/ 
	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.
	 */
	/** 
	* @Title: readCharacteristic 
	* @Description: TODO(读取特征值) 
	* @param @param characteristic(要读的特征值)
	* @return void    返回类型 
	* @throws 
	*/ 
	public void readCharacteristic(BluetoothGattCharacteristic characteristic)
	{
		if (mBluetoothAdapter == null || mBluetoothGatt == null)
		{
			Log.w(TAG, "BluetoothAdapter not initialized");
			return;
		}
		mBluetoothGatt.readCharacteristic(characteristic);

	}

	// 写入特征值
	public void writeCharacteristic(BluetoothGattCharacteristic characteristic)
	{
		if (mBluetoothAdapter == null || mBluetoothGatt == null)
		{
			Log.w(TAG, "BluetoothAdapter not initialized");
			return;
		}
		mBluetoothGatt.writeCharacteristic(characteristic);

	}

	// 读取RSSi
	public void readRssi()
	{
		if (mBluetoothAdapter == null || mBluetoothGatt == null)
		{
			Log.w(TAG, "BluetoothAdapter not initialized");
			return;
		}
		mBluetoothGatt.readRemoteRssi();
	}

	/**
	 * Enables or disables notification on a give characteristic.
	 * 
	 * @param characteristic
	 *            Characteristic to act on.
	 * @param enabled
	 *            If true, enable notification. False otherwise.
	 */
	/** 
	* @Title: setCharacteristicNotification 
	* @Description: TODO(设置特征值通变化通知) 
	* @param @param characteristic(特征值)
	* @param @param enabled (使能)   
	* @return void    
	* @throws 
	*/ 
	public void setCharacteristicNotification(
			BluetoothGattCharacteristic characteristic, boolean enabled)
	{
		if (mBluetoothAdapter == null || mBluetoothGatt == null)
		{
			Log.w(TAG, "BluetoothAdapter not initialized");
			return;
		}
		mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);

		BluetoothGattDescriptor clientConfig = characteristic
				.getDescriptor(UUID
						.fromString("00002902-0000-1000-8000-00805f9b34fb"));

		if (enabled)
		{
			clientConfig
					.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
		} else
		{
			clientConfig
					.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
		}
		mBluetoothGatt.writeDescriptor(clientConfig);
	}

	/** 
	* @Title: getCharacteristicDescriptor 
	* @Description: TODO(得到特征值下的描述值) 
	* @param @param 无
	* @return void   
	* @throws 
	*/ 
	public void getCharacteristicDescriptor(BluetoothGattDescriptor descriptor)
	{
		if (mBluetoothAdapter == null || mBluetoothGatt == null)
		{
			Log.w(TAG, "BluetoothAdapter not initialized");
			return;
		}

		mBluetoothGatt.readDescriptor(descriptor);
	}

	/**
	 * 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.
	 */
	/** 
	* @Title: getSupportedGattServices 
	* @Description: TODO(得到蓝牙的所有服务) 
	* @param @return    无
	* @return List<BluetoothGattService>    
	* @throws 
	*/ 
	public List<BluetoothGattService> getSupportedGattServices()
	{
		if (mBluetoothGatt == null)
			return null;
		return mBluetoothGatt.getServices();

	}

}

Androidmainfest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.severn"
    android:versionCode="1"
    android:versionName="1.2" >

    <uses-permission android:name="android.permission.BLUETOOTH"/>
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
    <uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>
    
    

    <application
        android:allowBackup="true"
        android:icon="@drawable/hc"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity 
            android:name=".ui.Ble_Activity"></activity>
        <service android:name="com.huicheng.service.BluetoothLeService" android:enabled="true"></service>
    </application>

</manifest>

没有更多推荐了,返回首页