Bluetooth分析,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;@Overrideprotected 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();}}@Overrideprotected 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 READYprint(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 dataprint(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 transmissionbyte 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 transmissionSystemClock.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 dataprint(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 numberprint(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 dataprint(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會收到OKprint(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() {@Overridepublic void run() {inbox.append(sb+"\n");}});}private boolean listening;@Overrideprotected 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 devicebluetoothAdapter.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() {@Overridepublic 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() {@Overridepublic 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();//配對orMethod 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;}@Overridepublic void run() {super.run();if(isBonding){long start = SystemClock.elapsedRealtime();while(bluetoothDevice.getBondState()!=BluetoothDevice.BOND_BONDED){//配對過程大概10sSystemClock.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() {@Overridepublic 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{@Overridepublic void run() {super.run();try {byte[] buffer = new byte[32];int bytesRead = -1;listening = true;while(listening){bytesRead = is.read(buffer);//IOExceptionif(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>