Android藍牙配對

ui5831 8年前發布 | 38K 次閱讀 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;
    }



5、根據配對的結果,進行配對

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左右時間,然后會再次消失。



 本文由用戶 ui5831 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!