Android藍牙配對
來自: http://blog.csdn.net//guijiaoba/article/details/41172661
上一篇博客介紹了Android ble的一些情況。
http://blog.csdn.net/guijiaoba/article/details/41172403
藍牙如果鏈接好,能夠讀寫,基本上完成了。藍牙還有個比較煩人的東西,就是藍牙配對。
Android ble4.0使用的配對方式和原先版本的配對方式不一樣。
看了網上很多地方都是hellogv大神的方法,這個真心不錯。
http://blog.csdn.net/hellogv/article/details/6042091
本著認真的態度,我把Android系統中Settings的源碼給研究了下,發現了配對的流程,Settings的源碼大小大概有300m,考慮的攻擊
Ble4.0的配對界面有2個部分,首先的是一個請求的配對的通知,點擊了是一個確認對話框,再點擊,然后又有個通知,點擊通知后,有個輸入密碼的的對話框,輸入密碼后,點確定,稍后就會有配對的結果。
下面是Settings中的源碼
Settings的目錄是/package/app/Settings,下面是Setting的源碼url,感興趣的同學可以去研究下
http://git.omapzoom.org/ 所有的源碼網址
http://git.omapzoom.org/?p=platform/packages/apps/Settings.git;a=summary Settings的網址
git://git.omapzoom.org/platform/packages/apps/Settings.git Settings的git地址
Settings中的藍牙代碼都在/Settings/src/com/android/settings/bluetooth目錄中
主要流程看下面的文件
/Settings/src/com/android/settings/bluetooth/BluetoothPairingDialog.java
代碼中很多的類,在實際的Android應該開發中是沒有的,我這邊準備了三個jar文件,分別是framework.jar,core.jar,ext.jar,這些事Android系統編譯的時候,生產的jar。
導入到elcipse中,關聯此jar就可以。關聯的jar時放在libs中,但是有個必須注意的地方,點擊項目的屬性,在Java BuildPath類別,Order and Export標簽,Android Dependenceis必須要比Android 5.0的在上面,這樣在引用的時候,就會優先引用Android Dependceis中的jar。
下面是Setting中的BluetoothPairingDialog.java,簡單分析下,中文部分是我添加的注釋。
package com.android.settings.bluetooth; import android.bluetooth.BluetoothDevice; import android.content.BroadcastReceiver; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.IntentFilter; import android.os.Bundle; import android.text.Editable; import android.text.Html; import android.text.InputFilter; import android.text.InputType; import android.text.Spanned; import android.text.TextWatcher; import android.text.InputFilter.LengthFilter; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.CheckBox; import android.widget.CompoundButton; import android.widget.EditText; import android.widget.TextView; import com.android.internal.app.AlertActivity; import com.android.internal.app.AlertController; import com.android.settings.R; import android.view.KeyEvent; import java.util.Locale; /** * BluetoothPairingDialog asks the user to enter a PIN / Passkey / simple * confirmation for pairing with a remote Bluetooth device. It is an activity * that appears as a dialog. */ // BluetoothPairingDialog 說明這個節目是一個對話框 public final class BluetoothPairingDialog extends AlertActivity implements CompoundButton.OnCheckedChangeListener, DialogInterface.OnClickListener, TextWatcher { private static final String TAG = "BluetoothPairingDialog"; private static final int BLUETOOTH_PIN_MAX_LENGTH = 16; private static final int BLUETOOTH_PASSKEY_MAX_LENGTH = 6; private BluetoothDevice mDevice; private int mType; private String mPairingKey; private EditText mPairingView; private Button mOkButton; /** * Dismiss the dialog if the bond state changes to bonded or none, or if * pairing was canceled for {@link #mDevice}. */ private final BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(action)) { // 當設備的配對狀態改變的時候,就把對話框去掉 int bondState = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, BluetoothDevice.ERROR); if (bondState == BluetoothDevice.BOND_BONDED || bondState == BluetoothDevice.BOND_NONE) { dismiss(); } } else if (BluetoothDevice.ACTION_PAIRING_CANCEL.equals(action)) { BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); if (device == null || device.equals(mDevice)) { dismiss(); } } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 必須是ACTION_PAIRING_REQUEST,否則不運行,ACTION_PAIRING_REQUEST是一個請求的配對的廣播 Intent intent = getIntent(); if (!intent.getAction().equals(BluetoothDevice.ACTION_PAIRING_REQUEST是一個請求的配對的廣播)) { Log.e(TAG, "Error: this activity may be started only with intent " + BluetoothDevice.ACTION_PAIRING_REQUEST); finish(); return; } LocalBluetoothManager manager = LocalBluetoothManager.getInstance(this); if (manager == null) { Log.e(TAG, "Error: BluetoothAdapter not supported by system"); finish(); return; } CachedBluetoothDeviceManager deviceManager = manager.getCachedDeviceManager(); // 獲取配對的設備和配對類型,我的項目中配對類型是BluetoothDevice.PAIRING_VARIANT_PIN mDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); mType = intent.getIntExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, BluetoothDevice.ERROR); // 根據配對的類型,進行分發,我們重點關注PAIRING_VARIANT_PIN switch (mType) { case BluetoothDevice.PAIRING_VARIANT_PIN: case BluetoothDevice.PAIRING_VARIANT_PASSKEY: // 創建用戶輸入配對密碼的對話框 createUserEntryDialog(deviceManager); break; case BluetoothDevice.PAIRING_VARIANT_PASSKEY_CONFIRMATION: int passkey = intent.getIntExtra(BluetoothDevice.EXTRA_PAIRING_KEY, BluetoothDevice.ERROR); if (passkey == BluetoothDevice.ERROR) { Log.e(TAG, "Invalid Confirmation Passkey received, not showing any dialog"); return; } mPairingKey = String.format(Locale.US, "%06d", passkey); createConfirmationDialog(deviceManager); break; case BluetoothDevice.PAIRING_VARIANT_CONSENT: case BluetoothDevice.PAIRING_VARIANT_OOB_CONSENT: createConsentDialog(deviceManager); break; case BluetoothDevice.PAIRING_VARIANT_DISPLAY_PASSKEY: case BluetoothDevice.PAIRING_VARIANT_DISPLAY_PIN: int pairingKey = intent.getIntExtra(BluetoothDevice.EXTRA_PAIRING_KEY, BluetoothDevice.ERROR); if (pairingKey == BluetoothDevice.ERROR) { Log.e(TAG, "Invalid Confirmation Passkey or PIN received, not showing any dialog"); return; } if (mType == BluetoothDevice.PAIRING_VARIANT_DISPLAY_PASSKEY) { mPairingKey = String.format("%06d", pairingKey); } else { mPairingKey = String.format("%04d", pairingKey); } createDisplayPasskeyOrPinDialog(deviceManager); break; default: Log.e(TAG, "Incorrect pairing type received, not showing any dialog"); } /* * Leave this registered through pause/resume since we still want to * finish the activity in the background if pairing is canceled. */ registerReceiver(mReceiver, new IntentFilter(BluetoothDevice.ACTION_PAIRING_CANCEL)); registerReceiver(mReceiver, new IntentFilter(BluetoothDevice.ACTION_BOND_STATE_CHANGED)); } // 創建用戶輸入配對密碼的對話框 private void createUserEntryDialog(CachedBluetoothDeviceManager deviceManager) { // 創建對話框的界面, // 在看看對話框的確定的回調函數,由于本類是實現DialogInterface.OnClickListener的方法的,我們可以去看下 // public void onClick(DialogInterface dialog, int which) final AlertController.AlertParams p = mAlertParams; p.mIconId = android.R.drawable.ic_dialog_info; p.mTitle = getString(R.string.bluetooth_pairing_request); p.mView = createPinEntryView(deviceManager.getName(mDevice)); p.mPositiveButtonText = getString(android.R.string.ok); p.mPositiveButtonListener = this; p.mNegativeButtonText = getString(android.R.string.cancel); p.mNegativeButtonListener = this; setupAlert(); mOkButton = mAlert.getButton(BUTTON_POSITIVE); mOkButton.setEnabled(false); } private View createPinEntryView(String deviceName) { View view = getLayoutInflater().inflate(R.layout.bluetooth_pin_entry, null); TextView messageView = (TextView) view.findViewById(R.id.message); TextView messageView2 = (TextView) view.findViewById(R.id.message_below_pin); CheckBox alphanumericPin = (CheckBox) view.findViewById(R.id.alphanumeric_pin); mPairingView = (EditText) view.findViewById(R.id.text); mPairingView.addTextChangedListener(this); alphanumericPin.setOnCheckedChangeListener(this); int messageId1; int messageId2; int maxLength; switch (mType) { case BluetoothDevice.PAIRING_VARIANT_PIN: messageId1 = R.string.bluetooth_enter_pin_msg; messageId2 = R.string.bluetooth_enter_pin_other_device; // Maximum of 16 characters in a PIN maxLength = BLUETOOTH_PIN_MAX_LENGTH; break; case BluetoothDevice.PAIRING_VARIANT_PASSKEY: messageId1 = R.string.bluetooth_enter_passkey_msg; messageId2 = R.string.bluetooth_enter_passkey_other_device; // Maximum of 6 digits for passkey maxLength = BLUETOOTH_PASSKEY_MAX_LENGTH; alphanumericPin.setVisibility(View.GONE); break; default: Log.e(TAG, "Incorrect pairing type for createPinEntryView: " + mType); return null; } // HTML escape deviceName, Format the message string, then parse HTML style tags String messageText = getString(messageId1, Html.escapeHtml(deviceName)); messageView.setText(Html.fromHtml(messageText)); messageView2.setText(messageId2); mPairingView.setInputType(InputType.TYPE_CLASS_NUMBER); mPairingView.setFilters(new InputFilter[] { new LengthFilter(maxLength) }); return view; } private View createView(CachedBluetoothDeviceManager deviceManager) { View view = getLayoutInflater().inflate(R.layout.bluetooth_pin_confirm, null); // Escape device name to avoid HTML injection. String name = Html.escapeHtml(deviceManager.getName(mDevice)); TextView messageView = (TextView) view.findViewById(R.id.message); String messageText; // formatted string containing HTML style tags switch (mType) { case BluetoothDevice.PAIRING_VARIANT_PASSKEY_CONFIRMATION: messageText = getString(R.string.bluetooth_confirm_passkey_msg, name, mPairingKey); break; case BluetoothDevice.PAIRING_VARIANT_CONSENT: case BluetoothDevice.PAIRING_VARIANT_OOB_CONSENT: messageText = getString(R.string.bluetooth_incoming_pairing_msg, name); break; case BluetoothDevice.PAIRING_VARIANT_DISPLAY_PASSKEY: case BluetoothDevice.PAIRING_VARIANT_DISPLAY_PIN: messageText = getString(R.string.bluetooth_display_passkey_pin_msg, name, mPairingKey); break; default: Log.e(TAG, "Incorrect pairing type received, not creating view"); return null; } messageView.setText(Html.fromHtml(messageText)); return view; } private void createConfirmationDialog(CachedBluetoothDeviceManager deviceManager) { final AlertController.AlertParams p = mAlertParams; p.mIconId = android.R.drawable.ic_dialog_info; p.mTitle = getString(R.string.bluetooth_pairing_request); p.mView = createView(deviceManager); p.mPositiveButtonText = getString(R.string.bluetooth_pairing_accept); p.mPositiveButtonListener = this; p.mNegativeButtonText = getString(R.string.bluetooth_pairing_decline); p.mNegativeButtonListener = this; setupAlert(); } private void createConsentDialog(CachedBluetoothDeviceManager deviceManager) { final AlertController.AlertParams p = mAlertParams; p.mIconId = android.R.drawable.ic_dialog_info; p.mTitle = getString(R.string.bluetooth_pairing_request); p.mView = createView(deviceManager); p.mPositiveButtonText = getString(R.string.bluetooth_pairing_accept); p.mPositiveButtonListener = this; p.mNegativeButtonText = getString(R.string.bluetooth_pairing_decline); p.mNegativeButtonListener = this; setupAlert(); } private void createDisplayPasskeyOrPinDialog(CachedBluetoothDeviceManager deviceManager) { final AlertController.AlertParams p = mAlertParams; p.mIconId = android.R.drawable.ic_dialog_info; p.mTitle = getString(R.string.bluetooth_pairing_request); p.mView = createView(deviceManager); p.mNegativeButtonText = getString(android.R.string.cancel); p.mNegativeButtonListener = this; setupAlert(); // Since its only a notification, send an OK to the framework, // indicating that the dialog has been displayed. if (mType == BluetoothDevice.PAIRING_VARIANT_DISPLAY_PASSKEY) { mDevice.setPairingConfirmation(true); } else if (mType == BluetoothDevice.PAIRING_VARIANT_DISPLAY_PIN) { byte[] pinBytes = BluetoothDevice.convertPinToBytes(mPairingKey); mDevice.setPin(pinBytes); } } @Override protected void onDestroy() { super.onDestroy(); unregisterReceiver(mReceiver); } public void afterTextChanged(Editable s) { if (mOkButton != null) { mOkButton.setEnabled(s.length() > 0); } } // 進行配對 private void onPair(String value) { // 根據類型進行分發 switch (mType) { case BluetoothDevice.PAIRING_VARIANT_PIN: // 注意這里是用了轉換的方法,不是直接調用value.getBytes();方法 byte[] pinBytes = BluetoothDevice.convertPinToBytes(value); if (pinBytes == null) { return; } // 直接調用setPin方法,然后就沒有了,等到收到狀態改變的廣播后就進行dismiss,請看54行的mReceiver mDevice.setPin(pinBytes); break; case BluetoothDevice.PAIRING_VARIANT_PASSKEY: int passkey = Integer.parseInt(value); mDevice.setPasskey(passkey); break; case BluetoothDevice.PAIRING_VARIANT_PASSKEY_CONFIRMATION: case BluetoothDevice.PAIRING_VARIANT_CONSENT: mDevice.setPairingConfirmation(true); break; case BluetoothDevice.PAIRING_VARIANT_DISPLAY_PASSKEY: case BluetoothDevice.PAIRING_VARIANT_DISPLAY_PIN: // Do nothing. break; case BluetoothDevice.PAIRING_VARIANT_OOB_CONSENT: mDevice.setRemoteOutOfBandData(); break; default: Log.e(TAG, "Incorrect pairing type received"); } } private void onCancel() { mDevice.cancelPairingUserInput(); } public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK) { onCancel(); } return super.onKeyDown(keyCode, event); } // 對話框的確定的回調 public void onClick(DialogInterface dialog, int which) { switch (which) { case BUTTON_POSITIVE: // 進行配對 if (mPairingView != null) { onPair(mPairingView.getText().toString()); } else { onPair(null); } break; case BUTTON_NEGATIVE: default: onCancel(); break; } } /* Not used */ public void beforeTextChanged(CharSequence s, int start, int count, int after) { } /* Not used */ public void onTextChanged(CharSequence s, int start, int before, int count) { } public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { // change input type for soft keyboard to numeric or alphanumeric if (isChecked) { mPairingView.setInputType(InputType.TYPE_CLASS_TEXT); } else { mPairingView.setInputType(InputType.TYPE_CLASS_NUMBER); } } }
1、對話框的創建
當收到請求配對的廣播后,此對話框會顯示。
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 必須是ACTION_PAIRING_REQUEST,否則不運行,ACTION_PAIRING_REQUEST是一個請求的配對的廣播 Intent intent = getIntent(); if (!intent.getAction().equals(BluetoothDevice.ACTION_PAIRING_REQUEST是一個請求的配對的廣播)) { Log.e(TAG, "Error: this activity may be started only with intent " + BluetoothDevice.ACTION_PAIRING_REQUEST); finish(); return; } LocalBluetoothManager manager = LocalBluetoothManager.getInstance(this); if (manager == null) { Log.e(TAG, "Error: BluetoothAdapter not supported by system"); finish(); return; } CachedBluetoothDeviceManager deviceManager = manager.getCachedDeviceManager(); // 獲取配對的設備和配對類型,我的項目中配對類型是BluetoothDevice.PAIRING_VARIANT_PIN mDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); mType = intent.getIntExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, BluetoothDevice.ERROR); // 根據配對的類型,進行分發,我們重點關注PAIRING_VARIANT_PIN switch (mType) { case BluetoothDevice.PAIRING_VARIANT_PIN: case BluetoothDevice.PAIRING_VARIANT_PASSKEY: // 創建用戶輸入配對密碼的對話框 createUserEntryDialog(deviceManager); break; case BluetoothDevice.PAIRING_VARIANT_PASSKEY_CONFIRMATION: int passkey = intent.getIntExtra(BluetoothDevice.EXTRA_PAIRING_KEY, BluetoothDevice.ERROR); if (passkey == BluetoothDevice.ERROR) { Log.e(TAG, "Invalid Confirmation Passkey received, not showing any dialog"); return; } mPairingKey = String.format(Locale.US, "%06d", passkey); createConfirmationDialog(deviceManager); break; case BluetoothDevice.PAIRING_VARIANT_CONSENT: case BluetoothDevice.PAIRING_VARIANT_OOB_CONSENT: createConsentDialog(deviceManager); break; case BluetoothDevice.PAIRING_VARIANT_DISPLAY_PASSKEY: case BluetoothDevice.PAIRING_VARIANT_DISPLAY_PIN: int pairingKey = intent.getIntExtra(BluetoothDevice.EXTRA_PAIRING_KEY, BluetoothDevice.ERROR); if (pairingKey == BluetoothDevice.ERROR) { Log.e(TAG, "Invalid Confirmation Passkey or PIN received, not showing any dialog"); return; } if (mType == BluetoothDevice.PAIRING_VARIANT_DISPLAY_PASSKEY) { mPairingKey = String.format("%06d", pairingKey); } else { mPairingKey = String.format("%04d", pairingKey); } createDisplayPasskeyOrPinDialog(deviceManager); break; default: Log.e(TAG, "Incorrect pairing type received, not showing any dialog"); } /* * Leave this registered through pause/resume since we still want to * finish the activity in the background if pairing is canceled. */ // 注冊廣播 registerReceiver(mReceiver, new IntentFilter(BluetoothDevice.ACTION_PAIRING_CANCEL)); registerReceiver(mReceiver, new IntentFilter(BluetoothDevice.ACTION_BOND_STATE_CHANGED)); }
2、創建有輸入框的界面
// 創建用戶輸入配對密碼的對話框 private void createUserEntryDialog(CachedBluetoothDeviceManager deviceManager) { // 創建對話框的界面, // 在看看對話框的確定的回調函數,由于本類是實現DialogInterface.OnClickListener的方法的,我們可以去看下 // public void onClick(DialogInterface dialog, int which) final AlertController.AlertParams p = mAlertParams; p.mIconId = android.R.drawable.ic_dialog_info; p.mTitle = getString(R.string.bluetooth_pairing_request); p.mView = createPinEntryView(deviceManager.getName(mDevice)); p.mPositiveButtonText = getString(android.R.string.ok); p.mPositiveButtonListener = this; p.mNegativeButtonText = getString(android.R.string.cancel); p.mNegativeButtonListener = this; setupAlert(); mOkButton = mAlert.getButton(BUTTON_POSITIVE); mOkButton.setEnabled(false); }
3、查看輸入框的確定回調函數
// 對話框的確定的回調 public void onClick(DialogInterface dialog, int which) { switch (which) { case BUTTON_POSITIVE: // 進行配對 if (mPairingView != null) { onPair(mPairingView.getText().toString()); } else { onPair(null); } break; case BUTTON_NEGATIVE: default: onCancel(); break; } }
4、配對
// 進行配對 private void onPair(String value) { // 根據類型進行分發 switch (mType) { case BluetoothDevice.PAIRING_VARIANT_PIN: // 注意這里是用了轉換的方法,不是直接調用value.getBytes();方法 byte[] pinBytes = BluetoothDevice.convertPinToBytes(value); if (pinBytes == null) { return; } // 直接調用setPin方法,然后就沒有了,等到收到狀態改變的廣播后就進行dismiss,請看54行的mReceiver mDevice.setPin(pinBytes); break; case BluetoothDevice.PAIRING_VARIANT_PASSKEY: int passkey = Integer.parseInt(value); mDevice.setPasskey(passkey); break; case BluetoothDevice.PAIRING_VARIANT_PASSKEY_CONFIRMATION: case BluetoothDevice.PAIRING_VARIANT_CONSENT: mDevice.setPairingConfirmation(true); break; case BluetoothDevice.PAIRING_VARIANT_DISPLAY_PASSKEY: case BluetoothDevice.PAIRING_VARIANT_DISPLAY_PIN: // Do nothing. break; case BluetoothDevice.PAIRING_VARIANT_OOB_CONSENT: mDevice.setRemoteOutOfBandData(); break; default: Log.e(TAG, "Incorrect pairing type received"); } }
// 注意這里是用了轉換的方法,不是直接調用value.getBytes();方法
byte[] pinBytes = BluetoothDevice.convertPinToBytes(value);
下面是系統的中的配對密碼轉換
/** * Check that a pin is valid and convert to byte array. * * Bluetooth pin's are 1 to 16 bytes of UTF-8 characters. * @param pin pin as java String * @return the pin code as a UTF-8 byte array, or null if it is an invalid * Bluetooth pin. * @hide */ public static byte[] convertPinToBytes(String pin) { if (pin == null) { return null; } byte[] pinBytes; try { pinBytes = pin.getBytes("UTF-8"); } catch (UnsupportedEncodingException uee) { Log.e(TAG, "UTF-8 not supported?!?"); // this should not happen return null; } if (pinBytes.length <= 0 || pinBytes.length > 16) { return null; } return pinBytes; }
private final BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(action)) { // 當設備的配對狀態改變的時候,就把對話框去掉 int bondState = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, BluetoothDevice.ERROR); if (bondState == BluetoothDevice.BOND_BONDED || bondState == BluetoothDevice.BOND_NONE) { dismiss(); } } else if (BluetoothDevice.ACTION_PAIRING_CANCEL.equals(action)) { BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); if (device == null || device.equals(mDevice)) { dismiss(); } } } };
以上就是系統的設置的配對流程。
下面是自己的項目中的業務代碼
BroadcastReceiver bleReceiver = new BroadcastReceiver() { public void onReceive(Context context, Intent intent) { McLog.mByStackTrace(); String action = intent.getAction(); McLog.i("action = " + action); if (BluetoothDevice.ACTION_FOUND.equals(action)) {// 搜索設備 doDeviceSearch(intent); } else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) { //搜索結束 doDeviceSearchFinished(intent); } else if (BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(action)) { // 設備狀態改變 doStateChange(intent); } else if (BluetoothDevice.ACTION_PAIRING_REQUEST.equals(action)) {// 請求匹配 doRequestPari(intent); } } void doStateChange(Intent intent) { BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); switch (device.getBondState()) { case BluetoothDevice.BOND_NONE: McLog.i("取消配對"); break; case BluetoothDevice.BOND_BONDING: McLog.i("正在配對......"); break; case BluetoothDevice.BOND_BONDED: McLog.i("完成配對"); break; } } void doDeviceSearch(Intent intent) { BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); McLog.i("device = " + device); if (device.getBondState() == BluetoothDevice.BOND_BONDED) {// 已經配對的則跳過 } else { if (!searchDevices.contains(searchDevices)) { searchDevices.add(device); } } } void doDeviceSearchFinished(Intent intent) { McLog.i("search finished, searchDevices's size = " + searchDevices.size()); boolean isFindRightDevice = false; for (BluetoothDevice device : searchDevices) { if (isRightDevice(device)) { // 如果是我想要的設備,那么我就進行配對 doNormalPair(device); isFindRightDevice = true; break; } } if (!isFindRightDevice) { McLog.i("sorry,do't search user's device[" + bleDeviceMac + "]"); } } void doNormalPair(BluetoothDevice device) { McLog.mByStackTrace(); currentPairDevice = device; try { // 調用配對的方法,此方法是異步的,系統會觸發BluetoothDevice.ACTION_PAIRING_REQUEST的廣播 // 收到此廣播后,設置配對的密碼 ClsUtils.createBond(BluetoothDevice.class, currentPairDevice); } catch (Exception e) { e.printStackTrace(); } } void doRequestPari(Intent intent) { BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); if (btDevice.getBondState() == BluetoothDevice.BOND_BONDED) { McLog.e("已經綁定"); } else { McLog.e("沒有綁定"); if (currentPairDevice != null && btDevice.getAddress().equalsIgnoreCase(currentPairDevice.getAddress())) { try { McLog.i("invoke setpin :" + bleDeviceMac); // 設置配對的密碼 <span style="font-family: Arial, Helvetica, sans-serif;">bleDevicePasswd 設備的配對密碼</span> ClsUtils.setPin2(BluetoothDevice.class, currentPairDevice, bleDevicePasswd); } catch (Exception e) { McLog.i("e = " + e); } currentPairDevice = null; uiHandler.postDelayed(new Runnable() { public void run() { loadBleData(); // 注銷監聽 unregisterReceiver(bleReceiver); } }, 1000); } } } };
以上就能完成ble4.0的密碼自動配對,當然中間的對話框會顯示1s左右時間,然后會再次消失。