Android中Bluetooth的意义和用法

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

1、示例演示

public class MainActivity extends Activity {
	/**在原码有@hide标志,外面看不到*/
	private static final String ACTION_PAIRING_CANCEL ="android.bluetooth.device.action.PAIRING_CANCEL";
	private static final String DEVICE_NAME_OXYGEN = "IVT-OX03";
	/**配对不需要提供密码,不接收ACTION_PAIRING_REQUEST广播*/
	private static final String DEVICE_NAME_PRESSURE = "HEM-7081-IT";
	/**不能反连,但长连接,只要socket不关闭就可点加压按钮采集数据*/
	private static final String DEVICE_NAME_HINGMED = "Hingmed WBP";
	/**不指定手机,不指定APP*/
	private static final String DEVICE_NAME_ECG = "IVT-ECG12-500-R";
	private static final int OXYGEN_SERVICE = 0xdd0000;
	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;
	BluetoothClass bluetoothClass;
	private BluetoothSocket transferSocket;
	
	/**
	 * <li>构造器为包访问权限,蓝牙地址String作为其参数
	 * <li>在搜索到星脉血压计设备时记录其蓝牙地址,即在ACTION_FOUND赋值
	 */
	private String ADDRESS_WBP = "8C:DE:52:72:6D:AA";
	
	/**
	 * @hide
	 * 在收到连接建立的广播后实例化InputStream和OutputStream
	 */
	private OutputStream os;
	private InputStream is;
	UUID uuid;
	TextView inbox;
	ListView listView;
	TextView tv;
	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 = (TextView) findViewById(R.id.inbox);
		listView = (ListView) findViewById(R.id.listView);
		tv = (TextView) findViewById(R.id.txt);
		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);
		filter.addAction(BluetoothDevice.ACTION_PAIRING_REQUEST);
		filter.addAction(ACTION_PAIRING_CANCEL);
		filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
		filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
		registerReceiver(mReceiver, filter);
		if(!bluetoothAdapter.isEnabled()){
			startActivityForResult(new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE), ENABLE_BLUETOOTH);
		}else{
			startServerSocket();
		}
		isRunning = true;
	}
	@Override
	protected void onPause() {
		super.onPause();
		if(isFinishing()){
			try {
				os.write(new byte[]{0x5A,0x05,0x1A,0x48,-0x2D});
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	@Override
	protected void onDestroy() {
		Log.d(TAG, "onDestroy");
		super.onDestroy();
		unregisterReceiver(mReceiver);
		resetSocket();
		isRunning = false;
	}
	int[] pressures = new int[3];
	/**接收读取的数据,然后发指令*/
	private void receiveData(final byte[] data, final int len, String deviceName) {
		if(DEVICE_NAME_PRESSURE.equals(deviceName)){
			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;
			}
		}else if(DEVICE_NAME_OXYGEN.equals(deviceName)||
				(bluetoothClass.getMajorDeviceClass() == BluetoothClass.Device.Major.UNCATEGORIZED
				&&(bluetoothClass.hashCode() & 0xFFE000)==OXYGEN_SERVICE)){
//			for(int i=0;i<len;i+=6){
//				print(data, i, i+6);
//				SystemClock.sleep(5L);
//			}
			print(data, 0, 6);
		}else if(DEVICE_NAME_ECG.equals(deviceName)){
			handler.post(new Runnable() {
				@Override
				public void run() {
					StringBuilder sb = new StringBuilder();
					for(int i=0;i<len;i++){
						if(i%12==0){
							sb.append('\n');
						}
						sb.append(data[i]&0xff).append(',');
					}
					inbox.setText(sb.deleteCharAt(0).deleteCharAt(sb.length()-1));
				}
			});
		}else if(DEVICE_NAME_HINGMED.equals(deviceName)){
			try {
				if(len == 5&&arrayEquals(data, new byte[]{0x5A,0x05,0x10}, 3)){
					printHingmed(data, len, "应答连接握手:");
					//血压计应答连接握手指令
				}else if(len == 7&&arrayEquals(data, new byte[]{0x5A,0x07,0x31}, 3)){
					printHingmed(data, len, "主发电池电量:");
					//血压计主发电池电量指令
					//data[3] 电量;data[4] 状态,0未充电,1充电,2充满
					
					os.write(new byte[]{0x5A,0x05,0x31,0x57,-0x6D});
					//客户端主发设备信息指令
					os.write(new byte[]{0x5A,0x05,0x11,-0x71,-0x6E});
				}else if(len == 7&&arrayEquals(data, new byte[]{0x5A,0x07,0x11}, 3)){
					printHingmed(data, len, "应答设备信息:");
					//血压计应答设备信息指令
					
					//客户端主发同步时间指令
					os.write(new byte[]{0x5A,0x0A,0x12,0x0D,0x0B,0x14,0x0B,0x17,-0x1B,0x44});
				}else if(len == 5&&arrayEquals(data, new byte[]{0x5A,0x05,0x12}, 3)){
					printHingmed(data, len, "应答时间同步:");
					//血压计应答时间同步指令
					
					//客户端下发登录用户名指令,用户名位置3-6
					os.write(new byte[]{0x5A,0x09,0x13,0x00,0x00,0x45,0x67,0x25,0x17});
				}else if(len == 5&&arrayEquals(data, new byte[]{0x5A,0x05,0x13}, 3)){
					printHingmed(data, len, "应答登录用户名:");
					//血压计应答登录用户名指令
					
					//客户端下发最近血压记录时间指令
					os.write(new byte[]{0x5A,0x0A,0x14,0x0D,0x0B,0x14,0x0F,0x30,0x59,0x06});
				}else if(len == 5&&arrayEquals(data, new byte[]{0x5A,0x0A,0x14}, 3)){
					printHingmed(data, len, "应答最近血压记录时间:");
					//血压计应答最近血压记录时间指令
				}else if(len==18&&arrayEquals(data, new byte[]{0x5A,0x12,0x30}, 3)){
					printHingmed(data, len, "主发血压记录:");
					//血压计主发未上传的血压记录数据,若不应答,收到4条相同结果
					//data[3]-data[8]收缩压,舒张压,心率
					//data[9]-data[13]年月日时分秒
					
					//记录血压记录。显示、本地保存、上传从这里开始
					pressures[0] = (((data[3] & 0xff) << 8)+(data[4] & 0xff));
					pressures[1] = (((data[5] & 0xff) << 8)+(data[6] & 0xff));
					pressures[2] = (((data[7] & 0xff) << 8)+(data[8] & 0xff));
					Log.d(TAG, "收缩压:"+pressures[0]+",舒张压:"+pressures[1]+",心率:"+pressures[2]);
					
					//客户端应答血压记录
					os.write(new byte[]{0x5A,0x05,0x30,-0x69,0x52});
				}else if(len==5&&arrayEquals(data, new byte[]{0x5A,0x05,0x3A}, 3)){
					printHingmed(data, len, "主发上传记录完毕:");
					//血压计主发上传记录完毕,若不应答,收到4条相同结果
					
					//客户端应答上传完毕
					os.write(new byte[]{0x5A,0x05,0x3A,-0x70,-0x2E});
					//客户端主发加压指令
					//确定最近血压记录上传完毕后,立马加压开始测量;或者点击血压计上的加压按钮
					os.write(new byte[]{0x5A,0x05,0x40,0x73,0x53});
				}else if(len==6&&arrayEquals(data, new byte[]{0x5A,0x05,0x40}, 3)){
					printHingmed(data, len, "应答启动测量:");
					//血压计应答启动测量命令;若点击加压按钮测量,则客户端收不到此命令
				}else if(len==8&&arrayEquals(data, new byte[]{0x5A,0x08,0x50}, 3)){
					printHingmed(data, len, "主发袖带压力数据:");
					//血压计主发袖带压力数据,多条
				}else if(len==5&&arrayEquals(data, new byte[]{0x5A,0x05,0x1A}, 3)){
					printHingmed(data, len, "应答血压计断开连接:");
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	/**校验接收到的数据是否正确*/
	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() {
//				if(inbox.getText().length()>256){
//					inbox.setText("");
//				}
				inbox.append(sb+"\n");
			}
		});
	}
	/**
	 * 处理
	 * @param bytes
	 * @param start
	 * @param end
	 */
	private void print(final byte[] bytes, final int start, int end){
//		final StringBuilder sb = new StringBuilder();
//		for(int i=start;i<end;i++){
//			sb.append(bytes[i]&0xff).append(",");
//		}
		handler.post(new Runnable() {
			@Override
			public void run() {
//				inbox.append(sb+"\n");
				inbox.setText("血氧值:"+(bytes[start+2]&0xff)
					+"\n脉率值:"+(bytes[start+1]&0xff));
			}
		});
	}
	private void printHingmed(byte[] bs, int len, String title){
		StringBuilder sb = new StringBuilder();
		sb.append(title);
		for(int i=0;i<len;i++){
			sb.append(bs[i]&0xFF).append(',');
		}
		Log.d(TAG, sb.deleteCharAt(sb.length()-1).toString());
	}
	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
				//heavyweight procedure, asynchronous call, return immediately
				bluetoothAdapter.startDiscovery();
			}
			break;
		case R.id.clearEdit:
			inbox.setText("");
			arrayAdapter.clear();
			deviceList.clear();
			break;
		case R.id.connect:
			connectDevice();
		}
	}
	boolean isRunning;
	/**
	 * <ul><li>当前设备作为server反连,监听连接请求
	 * <li>block until a connection is established,单开线程循环监听连接
	 * <li>程序启动时,若蓝牙已开,自动启动反连;若蓝牙未开,等接收到蓝牙打开广播后再启动反连
	 */
	private void startServerSocket(){
		Log.d(TAG, "反连过程启动");
		try {
			//getBluetoothService() called with no BluetoothManagerCallback
			final BluetoothServerSocket server = bluetoothAdapter.listenUsingInsecureRfcommWithServiceRecord("bluetoothserver", uuid);
			new Thread(new Runnable() {
				@Override
				public void run() {
					while(isRunning){
						try {
							Log.d(TAG, "before accept");
							transferSocket = server.accept();
							Log.d(TAG, transferSocket.getRemoteDevice().getName()+"-after accept");
							try {
								is = transferSocket.getInputStream();
								os = transferSocket.getOutputStream();
								bluetoothDevice = transferSocket.getRemoteDevice();
								bluetoothClass = transferSocket.getRemoteDevice().getBluetoothClass();
							} catch (IOException e) {
								e.printStackTrace();
							}
							if(mReadThread==null||!mReadThread.isAlive()){
								mReadThread = new ReadThread();
								mReadThread.start();
							}
							//Broken pipe
							os.write(new byte[]{0x5A,0x05,0x10,0x4F,0x53});
						} 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);
				//分三种情况:
				//1、已经配对,直接建立连接
				//2、正在配对,不采取措施
				//3、未配对,先配对再连接
				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){
					//配对方法立即返回,但实际配对过程持续10多秒
					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();
			//等待配对成功,配对过程大概10s
			if(isBonding){
				long start = SystemClock.elapsedRealtime();
				while(bluetoothDevice.getBondState()!=BluetoothDevice.BOND_BONDED){
					SystemClock.sleep(50);
				}
				Log.d(TAG, "配对成功,耗时-"+(SystemClock.elapsedRealtime()-start)+"ms");
			}
			//建立连接
			try {
//				transferSocket = bluetoothDevice.createInsecureRfcommSocketToServiceRecord(uuid);
				Method method = BluetoothDevice.class.getMethod("createInsecureRfcommSocketToServiceRecord", new Class[]{UUID.class});
				transferSocket = (BluetoothSocket) method.invoke(bluetoothDevice, 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();
				}
				//这么写每个设备都会发
				if(transferSocket.getRemoteDevice().getName().equals(DEVICE_NAME_HINGMED)){
					os.write(new byte[]{0x5A,0x05,0x10,0x4F,0x53});
				}
			} 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) {
			String action = intent.getAction();//减少代码量及方法多次调用带来的性能损失
			if(BluetoothAdapter.ACTION_DISCOVERY_STARTED.equals(action)){
				Log.d(TAG, "发现开始");
				arrayAdapter.clear();
				deviceList.clear();
			}else if(BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)){
				Log.d(TAG, "发现结束");
			}else if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) {
				int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, 0);
				int preState = intent.getIntExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, 0);
				if(state == BluetoothAdapter.STATE_ON){
					Log.d(TAG, "蓝牙打开");
					startServerSocket();
				}else if(state == BluetoothAdapter.STATE_OFF){
					Log.d(TAG, "蓝牙关闭");
				}
			}
			BluetoothDevice remoteDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
			if(remoteDevice==null){
				return;
			}
			if(BluetoothDevice.ACTION_FOUND.equals(action)){
				//BluetoothDevice和BluetoothClass均是Parcelable子类
				//BluetoothDevice.getName()有可能为null
				Log.d(TAG, "find "+remoteDevice.getName()+"|"+remoteDevice.getAddress()
						+"|"+remoteDevice.getBondState()+"|"+remoteDevice.getType());
				BluetoothClass bluetoothClass = intent.getParcelableExtra(BluetoothDevice.EXTRA_CLASS);
				if(remoteDevice!=null&&bluetoothClass!=null){
					bluetoothDevice = remoteDevice;
					MainActivity.this.bluetoothClass = bluetoothClass;
					if(bluetoothClass.getDeviceClass()==BluetoothClass.Device.HEALTH_BLOOD_PRESSURE
							&&(bluetoothClass.getMajorDeviceClass()==BluetoothClass.Device.Major.HEALTH)){
						deviceList.add(remoteDevice);
						arrayAdapter.add(remoteDevice.getName());
						Log.d(TAG, "欧姆龙血压计-"+remoteDevice.getName()+"|"+bluetoothClass.getDeviceClass()
								+"|"+bluetoothClass.getMajorDeviceClass()+"|"+(bluetoothClass.hashCode() & 0xFFE000));
						bluetoothAdapter.cancelDiscovery();//找到一个符合的设备就停止发现过程
					}else if(DEVICE_NAME_OXYGEN.equals(remoteDevice.getName())
							||DEVICE_NAME_ECG.equals(remoteDevice.getName())){
						deviceList.add(remoteDevice);
						arrayAdapter.add(remoteDevice.getName());
						bluetoothAdapter.cancelDiscovery();
					}else if((bluetoothClass.getMajorDeviceClass() == BluetoothClass.Device.Major.UNCATEGORIZED
							&&(bluetoothClass.hashCode() & 0xFFE000)==OXYGEN_SERVICE)){
						//TODO 血氧name为null
						deviceList.add(remoteDevice);
						arrayAdapter.add(DEVICE_NAME_OXYGEN);
						bluetoothAdapter.cancelDiscovery();
					}else if("Hingmed WBP".equalsIgnoreCase(remoteDevice.getName())
							||((bluetoothClass.getDeviceClass()==BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET)
							&&(bluetoothClass.getMajorDeviceClass()==BluetoothClass.Device.Major.AUDIO_VIDEO)
							&&(bluetoothClass.hashCode() & 0xFFE000)==0x240000)){
						//没法定位血压计 service 0x240000
						Log.d(TAG, "星脉血压计-"+remoteDevice.getName()+"|"+bluetoothClass.getDeviceClass()
							+"|"+bluetoothClass.getMajorDeviceClass()+"|"+(bluetoothClass.hashCode() & 0xFFE000));
						ADDRESS_WBP = remoteDevice.getAddress();
						deviceList.add(remoteDevice);
						arrayAdapter.add(remoteDevice.getName());
						bluetoothAdapter.cancelDiscovery();
					}
				}
			}else if(BluetoothDevice.ACTION_ACL_CONNECTED.equals(action)){
				Log.d(TAG, "ACTION_ACL_CONNECTED-"+remoteDevice.getName());
				tv.setText("已连设备:"+remoteDevice.getName());
				Toast.makeText(MainActivity.this, remoteDevice.getName()+" 已连接", Toast.LENGTH_SHORT).show();
			}else if(BluetoothDevice.ACTION_ACL_DISCONNECTED.equals(action)){
				Log.d(TAG, "ACTION_ACL_DISCONNECTED-"+remoteDevice.getName());
				tv.setText("已连设备:");
				Toast.makeText(MainActivity.this, remoteDevice.getName()+" 已断开", Toast.LENGTH_SHORT).show();
			}else if(BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(action)){
				int bondState = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, 0);
				int previousBondState = intent.getIntExtra(BluetoothDevice.EXTRA_PREVIOUS_BOND_STATE, 0);
				if(bondState==BluetoothDevice.BOND_BONDED){
					Log.d(TAG, "配对成功:"+remoteDevice.getName());
				}else if(bondState == BluetoothDevice.BOND_NONE){
					Log.d(TAG, "取消配对:"+remoteDevice.getName());
				}
			}
			else if (ACTION_PAIRING_CANCEL.equals(action)) {
				Log.d(TAG, "ACTION_PAIRING_CANCEL");
			} 
			else if (BluetoothDevice.ACTION_PAIRING_REQUEST.equals(action)) {
				int type = intent.getIntExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT,BluetoothDevice.ERROR);
				Log.d(TAG, "ACTION_PAIRING_REQUEST-"+type);
				//PAIRING_VARIANT_CONSENT 3 Hingmed WBP
				if(type == BluetoothDevice.PAIRING_VARIANT_PIN){
					remoteDevice.setPin("0000".getBytes());//弹框后自动输入密码、自动确定
				}else if(type == BluetoothDevice.PAIRING_VARIANT_PASSKEY_CONFIRMATION){
					remoteDevice.setPairingConfirmation(true);
				}
			}else if(BluetoothDevice.ACTION_UUID.equals(action)){
				Log.d(TAG, "ACTION_UUID");
			}
		}
	};
	ReadThread mReadThread;
	private static final int BYTE_SIZE = 320*1024;
	/**
	 * <ul><li>仅维持一个数组。
	 * <li>供所有mobile health device使用
	 * <li>数组设置比较大用于满足不同需求
	 * <li>并多次连接多次接收数据反复使用*/
	byte[] buffer = new byte[BYTE_SIZE];
	/**
	 * 收到设备连上的广播后启动此线程,执行读取远程数据并显示
	 * 主动或反连成功,拿到BluetoothSocket及相应输入输出流后启动此线程读取数据
	 */
	private class ReadThread extends Thread{
		@Override
		public void run() {
			super.run();
			try {
				int bytesRead = -1;
				listening = true;
				while(listening){
					long start = SystemClock.elapsedRealtime();
					//bt socket closed, read return: -1
					bytesRead = is.read(buffer);//IOException
					long readTime = SystemClock.elapsedRealtime()-start;
					if(readTime<200L){
						SystemClock.sleep(200L-readTime);
					}
					if(bytesRead != -1){
						/*try {
							Log.d(TAG, "反射");//NoSuchMethodException, JDK1.7.0_51可用
							//方法名和参数类型(Class<?>)
							Method method = MainActivity.class.getMethod("receiveData", 
								new Class<?>[]{byte[].class, int.class, String.class});
							//对象和参数值
							method.invoke(this, new Object[]{buffer, bytesRead, bluetoothDevice.getName()});
						} catch (Exception e) {
							e.printStackTrace();
						}*/
						receiveData(buffer, bytesRead, bluetoothDevice.getName());
					}
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	};
	private BluetoothDevice getBluetoothDeviceByAddress(String addr){
		return bluetoothAdapter.getRemoteDevice(ADDRESS_WBP);
//		Set<BluetoothDevice> set = bluetoothAdapter.getBondedDevices();
//		Iterator<BluetoothDevice> it = set.iterator();
//		while(it.hasNext()){
//			BluetoothDevice bd = it.next();
//			if(ADDRESS_WBP.equals(bd.getAddress())){
//				return bd;
//			}
//		}
//		return null;
	}
	/**不能反连,点击按钮连接指定设备*/
	private void connectDevice(){
		//客户端发完握手指令,线程就结束
		new Thread(){
			@Override
			public void run() {
				super.run();
				bluetoothDevice = getBluetoothDeviceByAddress(ADDRESS_WBP);
				if(bluetoothDevice==null){
					//该设备未配对
					Log.d(TAG, "bluetoothDevice==null");
					return;
				}
				bluetoothClass = bluetoothDevice.getBluetoothClass();
				try {
					transferSocket = bluetoothDevice.createInsecureRfcommSocketToServiceRecord(uuid);
					Log.d(TAG, "before connect");
					//不管是否配对,getRemoteDevice立马返回
					//若未配对,connect阻塞弹配对对话框等待配对;若已配对,connect快速返回
					transferSocket.connect();//阻塞直到连接成功
					Log.d(TAG, "after connect");
					is = transferSocket.getInputStream();
					os = transferSocket.getOutputStream();
					
					if(mReadThread==null||!mReadThread.isAlive()){
						mReadThread = new ReadThread();
						mReadThread.start();
					}
					if(transferSocket.getRemoteDevice().getName().equals(DEVICE_NAME_HINGMED)){
						os.write(new byte[]{0x5A,0x05,0x10,0x4F,0x53});
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
			};
		}.start();
	}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<ScrollView 
    android:layout_width="match_parent"
    android:layout_height="match_parent"
     xmlns:android="http://schemas.android.com/apk/res/android">
    <LinearLayout
	    android:layout_width="match_parent"
	    android:layout_height="wrap_content"
	    android:orientation="vertical">
	    <TextView 
	        android:id="@+id/txt"
	        android:layout_width="match_parent"
	        android:layout_height="wrap_content"
	        android:text="已连设备:"/>
		<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"/>
	    <TextView 
	        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"/>
	    <Button 
	        android:id="@+id/connect"
	        android:layout_width="match_parent"
	        android:layout_height="wrap_content"
	        android:onClick="onClick"
	        android:text="connectSpecific"/>
	    <ListView 
	        android:id="@+id/listView"
	        android:layout_width="match_parent"
	        android:layout_height="wrap_content"/>
	</LinearLayout>
</ScrollView>

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值