Bluetooth分析

本文章分析了android蓝牙的用法,包括蓝牙的开启关闭、设置可见、开始取消发现、配对、主动连接、反连、广播等。

1、示例演示

public class MainActivity extends Activity {
	private static final String TAG = MainActivity.class.getSimpleName();
	private BluetoothAdapter bluetoothAdapter;
	private static final int ENABLE_BLUETOOTH = 0x0;
	private static final int DISCOVER_REQUEST = 0x1;
	private List<BluetoothDevice> deviceList = new ArrayList<BluetoothDevice>();
	ArrayAdapter<String> arrayAdapter;
	BluetoothDevice bluetoothDevice;
	private BluetoothSocket transferSocket;
	/**在收到连接建立的广播后实例化InputStream和OutputStream*/
	private OutputStream os;
	private InputStream is;
	UUID uuid;
	EditText inbox;
	ListView listView;
	byte[] tmpBytes = new byte[32];
	public int count = 0;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		Log.d(TAG, "onCreate");
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		inbox = (EditText) findViewById(R.id.inbox);
		listView = (ListView) findViewById(R.id.listView);
		listView.setOnItemClickListener(mOnItemClickListener);
		arrayAdapter = new ArrayAdapter<String>(MainActivity.this,
				android.R.layout.simple_list_item_1, new ArrayList<String>());
		listView.setAdapter(arrayAdapter);
		//扁鹊飞救用的UUID号
		uuid = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");

		bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
		initBluetooth();
	}
	private void initBluetooth(){
		IntentFilter filter = new IntentFilter();
		filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
		filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
		filter.addAction(BluetoothDevice.ACTION_FOUND);
		filter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);
		filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
		registerReceiver(mReceiver, filter);
		if(!bluetoothAdapter.isEnabled()){
			startActivityForResult(new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE), ENABLE_BLUETOOTH);
		}else{
			startServerSocket();
		}
	}
	@Override
	protected void onDestroy() {
		Log.d(TAG, "onDestroy");
		super.onDestroy();
		unregisterReceiver(mReceiver);
		resetSocket();
		isRunning = false;
	}
	/**接收读取的数据,然后发指令*/
	private void receiveData(byte[] data, int len) {
		System.arraycopy(data, 0, tmpBytes, count, len);
		count += len;
		if (count == 5 && arrayEquals(tmpBytes, "READY".getBytes(), count)) {// 5 READY
			print(tmpBytes, count);
			count = 0;
			try {
				SystemClock.sleep(500);
				os.write("VER00".getBytes());// get version data
			} catch (IOException e) {
				e.printStackTrace();
			}
		} else if (count == 15 && tmpBytes[0]=='O' && checkSum(tmpBytes, 3, 14)) {// 1-9-5 receive version data
			print(tmpBytes, count);
			count = 0;
			try {
				SystemClock.sleep(500);
				os.write("GAT00".getBytes());// get automatic transmission
			} catch (IOException e) {
				e.printStackTrace();
			}
		} else if (count == 5 && tmpBytes[0]=='O' && checkSum(tmpBytes, 3, 4)) {// automatic transmission
			byte set = tmpBytes[3];
			print(tmpBytes, count);
			count = 0;
			try {
				if (set == 0x00) {//0:not;1:yes若未设置自动传输,就先设置
					SystemClock.sleep(500);
					os.write(new byte[] { 'S', 'A', 'T', '\0', 0x11, 0x11 });// set automatic transmission
					SystemClock.sleep(500);
				}
				os.write("GPD00".getBytes());// get profile data
			} catch (IOException e) {
				e.printStackTrace();
			}
		} else if (count == 14 && tmpBytes[0]=='O' && checkSum(tmpBytes, 3, 13)) {// 1-8-5 receive profile data
			print(tmpBytes, count);
			count = 0;
			try {
				SystemClock.sleep(500);
				os.write("GDN00".getBytes());// send 'get data number' command
			} catch (IOException e) {
				e.printStackTrace();
			}
		} else if (count == 8 && tmpBytes[0]=='O' && checkSum(tmpBytes, 3, 7)) {// 1-7 receive data number
			print(tmpBytes, count);
			count = 0;
			try {
				SystemClock.sleep(500);
				os.write(new byte[] { 'G', 'M', 'D', '\0', 0, 0, 0 });//send 'get measurement data' command
			} catch (IOException e) {
				e.printStackTrace();
			}
		} else if (count == 18 && tmpBytes[0]=='O' && checkSum(tmpBytes, 3, 17)) {// 1-9-8 receive measurement data
			print(tmpBytes, count);
			count = 0;
			try {
				SystemClock.sleep(500);
				os.write(new byte[]{'T','O','K',(byte) 0xff,(byte) 0xff});
			} catch (IOException e) {
				e.printStackTrace();
			}
		}else if(count == 2 && arrayEquals("OK".getBytes(), tmpBytes, count)){//发TOK会收到OK
			print(tmpBytes, count);
			count = 0;
		}
	}
	/**校验接收到的数据是否正确*/
	private boolean checkSum(byte[] data,int start,int end){
		byte check = 0;
		for(int i=start;i<=end;i++){
			check ^= data[i];
		}
		if(check==0){
			return true;
		}
		return false;
	}
	/** 判断两个byte数组是否相同
	 * <li>从两数组0到len位置依次比较 */
	private boolean arrayEquals(byte[] one, byte[] another, int len) {
		if (one == null || another == null) {
			return false;
		}
		if(len<0||len>one.length||len>another.length){
			return false;
		}
		for (int i = 0; i < len; i++) {
			if (one[i] != another[i]) {
				return false;
			}
		}
		return true;
	}
	Handler handler = new Handler();
	private void print(byte[] bytes, int len){
		final StringBuilder sb = new StringBuilder();
		for(int i=0;i<len;i++){
			sb.append(bytes[i]).append(",");
		}
		handler.post(new Runnable() {
			@Override
			public void run() {
				inbox.append(sb+"\n");
			}
		});
	}
	private boolean listening;
	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		super.onActivityResult(requestCode, resultCode, data);
		if(requestCode == ENABLE_BLUETOOTH){
			if(resultCode == RESULT_OK){
				Toast.makeText(this, "Bluetooth is enabled", Toast.LENGTH_SHORT).show();
			}
		}else if(requestCode == DISCOVER_REQUEST){
			if(resultCode == RESULT_OK){
				Toast.makeText(this, "Bluetooth is discoverable", Toast.LENGTH_SHORT).show();
			}
		}
	}
	public void onClick(View v){
		switch (v.getId()) {
		case R.id.discoverable:
			//对所有附近设备可见,反连使用
			//若蓝牙不可用则提示打开蓝牙
			startActivityForResult(new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE), DISCOVER_REQUEST);
			break;
		case R.id.discover:
			if(!bluetoothAdapter.isEnabled()){
				startActivityForResult(new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE), ENABLE_BLUETOOTH);
			}else if(!bluetoothAdapter.isDiscovering()){
				//inquiry scan of 12s,followed by a page scan of each new device
				bluetoothAdapter.startDiscovery();
			}
			break;
		case R.id.accept:
			startServerSocket();
			break;
		case R.id.clearEdit:
			inbox.setText("");
			arrayAdapter.clear();
			deviceList.clear();
		}
	}
	boolean isRunning = true;
	/**
	 * 当前设备作为server反连,监听连接请求
	 * 单开线程循环监听连接
	 */
	private void startServerSocket(){
		Toast.makeText(this, "反连过程启动", Toast.LENGTH_SHORT).show();
		try {
			final BluetoothServerSocket server = bluetoothAdapter.listenUsingInsecureRfcommWithServiceRecord("bluetoothserver", uuid);
			new Thread(new Runnable() {
				@Override
				public void run() {
					while(isRunning){
						try {
							transferSocket = server.accept();
							try {
								is = transferSocket.getInputStream();
								os = transferSocket.getOutputStream();
							} catch (IOException e) {
								e.printStackTrace();
							}
							if(mReadThread==null||!mReadThread.isAlive()){
								mReadThread = new ReadThread();
								mReadThread.start();
							}
						} catch (IOException e) {
							e.printStackTrace();
						}
					}
				}
			}).start();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	/**主动连接设备*/
	private OnItemClickListener mOnItemClickListener = new OnItemClickListener() {
		@Override
		public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
			try {
				BluetoothDevice bluetoothDevice = deviceList.get(position);
				Log.d(TAG, "before bond-"+bluetoothDevice.getBondState());
				if(bluetoothDevice.getBondState()==BluetoothDevice.BOND_BONDING){
					Toast.makeText(MainActivity.this, "正在配对...", Toast.LENGTH_SHORT).show();
					return;
				}
				if(bluetoothDevice.getBondState() == BluetoothDevice.BOND_NONE){
//					boolean retValue = bluetoothDevice.createBond();//配对or
					Method method = BluetoothDevice.class.getMethod("createBond");
					boolean retValue = (Boolean) method.invoke(bluetoothDevice);
					if(retValue){//true表示配对过程开始
						new ConnectThread(true).start();
						return;
					}
				}
				new ConnectThread(false).start();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	};
	private class ConnectThread extends Thread{
		boolean isBonding;
		public ConnectThread(boolean isBonding){
			this.isBonding = isBonding;
		}
		@Override
		public void run() {
			super.run();
			if(isBonding){
				long start = SystemClock.elapsedRealtime();
				while(bluetoothDevice.getBondState()!=BluetoothDevice.BOND_BONDED){
					//配对过程大概10s
					SystemClock.sleep(50);
				}
				Log.d(TAG, "配对成功-"+(SystemClock.elapsedRealtime()-start)+"ms");
			}

			try {
				transferSocket = bluetoothDevice.createInsecureRfcommSocketToServiceRecord(uuid);
				long start = SystemClock.elapsedRealtime();
				transferSocket.connect();//连接
				Log.d(TAG, "after connect-"+(SystemClock.elapsedRealtime()-start)+"ms");
				is = transferSocket.getInputStream();
				os = transferSocket.getOutputStream();
				if(mReadThread==null||!mReadThread.isAlive()){
					mReadThread = new ReadThread();
					mReadThread.start();
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
	/**
	 * close InputStream,OutputStream,BluetoothSocket
	 * 在Activity.onDestroy调用
	 */
	private void resetSocket(){
		Log.d(TAG, "resetSocket");
		listening = false;
		try {
			if(is!=null)
				is.close();
		} catch (IOException e1) {
			e1.printStackTrace();
		}
		try {
			if(os!=null)
				os.close();
		} catch (IOException e1) {
			e1.printStackTrace();
		}
		try {
			if(transferSocket!=null)
				transferSocket.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	private BroadcastReceiver mReceiver = new BroadcastReceiver() {
		@Override
		public void onReceive(Context context, Intent intent) {
			if(BluetoothAdapter.ACTION_DISCOVERY_STARTED.equals(intent.getAction())){
				Toast.makeText(MainActivity.this, "发现开始", Toast.LENGTH_SHORT).show();
				arrayAdapter.clear();
				deviceList.clear();
			}else if(BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(intent.getAction())){
				Toast.makeText(MainActivity.this, "发现完成", Toast.LENGTH_SHORT).show();
			}else if(BluetoothDevice.ACTION_FOUND.equals(intent.getAction())){
				//BluetoothDevice和BluetoothClass均是Parcelable子类
				BluetoothDevice remoteDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
				BluetoothClass bluetoothClass = intent.getParcelableExtra(BluetoothDevice.EXTRA_CLASS);
				if(remoteDevice!=null&&bluetoothClass!=null){
					if(bluetoothClass.getDeviceClass()==BluetoothClass.Device.HEALTH_BLOOD_PRESSURE){
						bluetoothDevice = remoteDevice;
						deviceList.add(remoteDevice);
						arrayAdapter.add(remoteDevice.getName());
						bluetoothAdapter.cancelDiscovery();//找到一个符合的设备就停止发现过程
					}
				}
			}else if(BluetoothDevice.ACTION_ACL_CONNECTED.equals(intent.getAction())){
				BluetoothDevice currentDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
				Toast.makeText(MainActivity.this, currentDevice.getName()+" 已连接", Toast.LENGTH_SHORT).show();
			}else if(BluetoothDevice.ACTION_ACL_DISCONNECTED.equals(intent.getAction())){
				BluetoothDevice remoteDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
				Toast.makeText(MainActivity.this, remoteDevice.getName()+" 已断开", Toast.LENGTH_SHORT).show();
			}else if(BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(intent.getAction())){
				int bondState = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, 0);
				if(bondState==BluetoothDevice.BOND_BONDED){
					Toast.makeText(MainActivity.this, Build.MODEL+" 绑定成功", Toast.LENGTH_SHORT).show();
				}
			}
		}
	};
	ReadThread mReadThread;
	/**收到设备连上的广播后启动此线程,执行读取远程数据并显示*/
	private class ReadThread extends Thread{
		@Override
		public void run() {
			super.run();
			try {
				byte[] buffer = new byte[32];
				int bytesRead = -1;
				listening = true;
				while(listening){
					bytesRead = is.read(buffer);//IOException
					if(bytesRead != -1){
						receiveData(buffer, bytesRead);
					}
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	};
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    xmlns:android="http://schemas.android.com/apk/res/android">
	<Button
        android:id="@+id/discoverable"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="设置当前设备可见"
        android:onClick="onClick"/>
    <Button
        android:id="@+id/discover"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="启动发现过程"
        android:onClick="onClick"/>
    <Button
        android:id="@+id/accept"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="启动反连线程"
        android:onClick="onClick"/>
    <EditText
        android:id="@+id/inbox"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
    <Button
        android:id="@+id/clearEdit"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="onClick"
        android:text="clearEdit"/>
    <ListView
        android:id="@+id/listView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
</LinearLayout>

时间: 2024-08-06 07:55:46

Bluetooth分析的相关文章

Android 4.2 Bluetooth 分析总结(二) 蓝牙enable 的整个过程

转载请标明出处:Android 4.2 Bluetooth 分析总结(二) 蓝牙enable 的整个过程 现在开始我们分析 Android4.2 Bluetooth 打开的整个过程,由于是新手,难免有很多错误,记录只是为了以后方便查找,如发错误敬请指出. 我们整个分析过程有可能有点繁琐,但请仔细阅读,读完之后必然发现还是会有一点点收获的,虽然写的不好.搜先我们上一份enable 打开蓝牙整个过程的打印:然后我们跟踪打印来窥探 Android4.2Bluetooth 工作的流程. D/Blueto

android4.3 Bluetooth分析之扫描分析

android4.3中引入了蓝牙低能耗le(low energy),相应的也有一些方法/类.不过代码里,并没有找到初始调用的地方.所以这里还是先只分析下bt普通的扫描流程(类似android 4.2),先贴出流程图 主要通过"扫描"的流程来分析下 BluetoothSettings.java::startScanning ----package LocalBluetoothAdapter.java::startScanning ----package BluetoothAdapter.

Android 4.2 Bluetooth 分析总结(一)

因为是新手,之前没有研究过蓝牙功能,也不知到Bluetooth 在android 其他版本上的情况,但是大概了解之后发现,Android4.2 之后的Bluetooth 模块和之前版本的android有很大的出入,具体表现在哪里我就不研究了,因此我是直接拿Android4.2 Bluetooth 来研究的,当然这也参考了网上很多前辈的文章:android -- 蓝牙 bluetooth (一) 入门等.在这里表示感谢!!! 一.蓝牙模块相关的代码 在Android 4.2上的分布如下: sett

Linux Bluetooth内核分析之HCI部分

关于HCI规范相关内容,请看<Bluetooth HCI介绍> 首先我们要了解,在Linux上实现的是HCI的Host部分 1. 相关数据结构 1.1 hci_dev 在Linux中hci_dev用来表示一个HCI Host(对应于一个Control) 成员 作用 char name[8] 蓝牙名称 __u8 bus HCI总线类型,有HCI_USB,HCI_PCCARD,HCI_UART,HCI_PCI等 __u8 dev_type HCI Controller类型,有HCI_BREDR,H

Android bluetooth介绍(三): 蓝牙扫描(scan)设备分析

关键词:蓝牙blueZ  A2DP.SINK.sink_connect.sink_disconnect.sink_suspend.sink_resume.sink_is_connected.sink_get_properties.AUDIO.DBUS版本号:基于android4.2之前版本号 bluez内核:linux/linux3.08系统:android/android4.1.3.4作者:xubin341719(欢迎转载.请注明作者.请尊重版权谢谢)欢迎指正错误.共同学习.共同进步!! 參考

android4.3 Bluetooth(le)分析之startLeScan分析

BluetoothAdapter.java中有low enery(le)的一些方法,android提供了这些方法,但源码中并未找到这些方法的调用之处.本文档主要分析这类方法的执行流程,来了解下le到底做了些什么. 本文主要就是分析下startLeScan方法(两个重载方法). public boolean startLeScan(LeScanCallback callback) { return startLeScan(null, callback); } public boolean star

Android4.42-Setting源码分析之蓝牙模块Bluetooth(下)

接着上一篇Android4.42-Settings源码分析之蓝牙模块Bluetooth(上) 继续蓝牙模块源码的研究 THREE,蓝牙模块功能实现 switch的分析以及本机蓝牙重命名和可见性的分析见上一篇,接下来进行第三章第三部分的介绍:关于蓝牙远程设备列表的加载.如果没有看过,建议看看上一篇关第一章蓝牙的布局,有助于理解 3>,设备列表的加载 因为这部分代码很多,所以在介绍时先说一下思路,程序首先通过底层的BluetoothAdapter的getBondedDevices()方法获取到已配对

Android bluetooth介绍(四): a2dp connect流程分析

关键词:蓝牙blueZ  A2DP.SINK.sink_connect.sink_disconnect.sink_suspend.sink_resume.sink_is_connected.sink_get_properties.AUDIO.DBUS版本:基于android4.2之前版本 bluez内核:linux/linux3.08系统:android/android4.1.3.4作者:xubin341719(欢迎转载,请注明作者,请尊重版权谢谢)欢迎指正错误,共同学习.共同进步!! Andr

Android4.42-Settings源代码分析之蓝牙模块Bluetooth总体实现(总)

本文为博主原创,转载请注明出处:http://blog.csdn.net/zrf1335348191/article/details/50995466 蓝牙相关代码已在另两篇文章中介绍,有须要的能够查看 Android4.42-Settings源代码分析之蓝牙模块Bluetooth(上) Android4.42-Setting源代码分析之蓝牙模块Bluetooth(下) ONE,SWITCH蓝牙开关 switch从创建到动作状态监听步骤例如以下 创建switch实例 Switch actionB