Android蓝牙配对

上一篇博客介绍了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左右时间,然后会再次消失。

时间: 2024-11-08 14:20:24

Android蓝牙配对的相关文章

Android蓝牙自动配对Demo,亲测好使!!!

蓝牙自动配对,即搜索到其它蓝牙设备之后直接进行配对,不需要弹出配对确认框或者密钥输入框. 转载请注明出处http://blog.csdn.net/qq_25827845/article/details/52400782 经过最近一段时间得研究,针对网上给出的案例.总结了一个亲测好使的Demo. 说明如下: 1.本Demo用来连接蓝牙设备HC-05,如果你要连接其他蓝牙设备,注意修改相关名字以及修改设备初试pin值. 2.将Demo安装在Android手机上,点击按钮,可以实现与目标蓝牙设备的自动

android开发之蓝牙配对连接的方法

最近在做蓝牙开锁的小项目,手机去连接单片机总是出现问题,和手机的连接也不稳定,看了不少蓝牙方面的文档,做了个关于蓝牙连接的小结. 在做android蓝牙串口连接的时候一般会使用 ? 1 2 3 4 5 6 7 8 BluetoothSocket tmp = null; // Get a BluetoothSocket for a connection with the // given BluetoothDevice try {          tmp = device.createRfcom

如何实现android蓝牙开发 自动配对连接,并不弹出提示框

如何实现android蓝牙开发 自动配对连接,并不弹出提示框 之前做一个android版的蓝牙,遇到最大的难题就是自动配对. 上网查资料说是用反射createBond()和setPin(),但测试时进行配对还是会出现提示,但配对是成功了 我就开始查找怎么关闭这个蓝牙配对提示框,后面还是伟大的android源码帮助了我. 在源码 BluetoothDevice 类中还有两个隐藏方法 cancelBondProcess()和cancelPairingUserInput() 这两个方法一个是取消配对进

Android 蓝牙开发之搜索、配对、连接、通信大全

        蓝牙( Bluetooth®):是一种无线技术标准,可实现固定设备.移动设备和楼宇个人域网之间的短距离数据 交换(使用2.4-2.485GHz的ISM波段的UHF无线电波).蓝牙设备最多可以同时和7个其它蓝牙设备建立连接,进 行通信,当然并不是每一个蓝牙都可以达到最大值.下面,我们从蓝牙的基本概念开始,一步一步开始了解蓝牙. 基本概念: 安卓平台提供对蓝牙的通讯栈的支持,允许设别和其他的设备进行无线传输数据.应用程序层通过安卓API来调用蓝牙的相关功 能,这些API使程序无线连接

Android蓝牙自动配对Demo,亲测好使!!!(转)

蓝牙自动配对,即搜索到其它蓝牙设备之后直接进行配对,不需要弹出配对确认框或者密钥输入框. 转载请注明出处http://blog.csdn.net/qq_25827845/article/details/52400782 源码下载地址:https://github.com/chaohuangtianjie994/BlueTooth-AutoPair 经过最近一段时间得研究,针对网上给出的案例.总结了一个亲测好使的Demo. 说明如下: 1.本Demo用来连接蓝牙设备HC-05,如果你要连接其他蓝牙

[Android]蓝牙基本操作

蓝牙是一种支持设备短距离传输数据的无线技术.android在2.0以后提供了这方面的支持.从查找蓝牙设备到能够相互通信要经过几个基本步骤(本机做为服务器):1.设置权限在manifest中配置 Xml代码    <uses-permission android:name="android.permission.BLUETOOTH"/> <uses-permission android:name="android.permission.BLUETOOTH_AD

android蓝牙学习

学习路线 1 蓝牙权限 <uses-permission android:name="android.permission.BLUETOOTH" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCAT

[Android]蓝牙系统

1.1 蓝牙技术简介 蓝牙(Bleuetooth)原是十世纪统一了丹麦的一个国王的名字,现取其"统一"的含义,用来意在统一无线局域网通讯的标准的蓝牙技术.蓝牙技 术是爱立信,IBM,Intel等世界5家著名大公司在1998年联合推出的一项无线通讯规范.随后成立的蓝牙技术特殊兴趣组织(SIG)来负责该技术的 开发和技术协议的制定,如今全世界已有1800多家公司加盟该组织,最近微软公司也正式加盟并成为SIG组织的领导成员之一.它以低成本的近距离无线连接 为基础,为移动通信设备建立一个短程无

Android蓝牙传感应用

Android手机一般以客户端的角色主动连接SPP协议设备(接上蓝牙模块的数字传感器),连接流程是: 1.使用registerReceiver注册BroadcastReceiver来获取蓝牙状态.搜索设备等消息:2.使用BlueAdatper的搜索:3.在BroadcastReceiver的onReceive()里取得搜索所得的蓝牙设备信息(如名称,MAC,RSSI):4.通过设备的MAC地址来建立一个BluetoothDevice对象: 5.由BluetoothDevice衍生出Bluetoo