我几乎已经做到了。它可以通过编程配对,但我无法摆脱“配对请求”通知。一些回答这个问题的人声称可以使用隐藏方法cancelPairingUserInput()
在显示后立即隐藏它,但这对我似乎不起作用。
编辑:成功!
最终我阅读了BluetoothPairingRequest
和发送配对请求广播的代码的源代码,并意识到我应该拦截ACTION_PAIRING_REQUEST
。幸运的是,这是一个有序的意图广播,所以你可以在系统之前拦截它。
以下是步骤。
- 注册接收
BluetoothDevice.ACTION_PAIRING_REQUEST
更改广播意图。使用高优先级!
- 连接设备。
- 发现服务。
- 如果你现在已经断开连接,那么很可能是因为债券信息不正确(例如外围设备清除了它)。在这种情况下,使用隐藏方法(谷歌真的很认真)删除债券信息,并重新连接。
- 尝试读取需要加密MitM保护的特性。
- 在
ACTION_PAIRING_REQUEST
广播接收器中,检查配对类型是否为BluetoothDevice.PAIRING_VARIANT_PIN
,如果是,则调用setPin()
和abortBroadcast()
。否则,你可以让系统处理它,或者显示错误或其他内容。
以下是代码。
public class ConnectActivityLogic extends Fragment
{
private BluetoothGatt mGatt;
public static class StateObservable extends Observable
{
private void notifyChanged() {
setChanged();
notifyObservers();
}
};
public final StateObservable State = new StateObservable();
public ConnectActivityLogic()
{
}
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setRetainInstance(true);
final IntentFilter pairingRequestFilter = new IntentFilter(BluetoothDevice.ACTION_PAIRING_REQUEST);
pairingRequestFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY - 1);
getActivity().getApplicationContext().registerReceiver(mPairingRequestRecevier, pairingRequestFilter);
State.notifyChanged();
connectGatt();
}
@Override
public void onDestroy()
{
super.onDestroy();
disconnectGatt();
getActivity().getApplicationContext().unregisterReceiver(mPairingRequestRecevier);
}
public ConnectionState getConnectionState()
{
return mState;
}
public enum ConnectionState
{
IDLE,
CONNECT_GATT,
DISCOVER_SERVICES,
READ_CHARACTERISTIC,
FAILED,
SUCCEEDED,
}
private ConnectionState mState = ConnectionState.IDLE;
public byte[] macAddress()
{
return getArguments().getByteArray("mac");
}
public int pinCode()
{
return getArguments().getInt("pin", -1);
}
private void connectGatt()
{
disconnectGatt();
mState = ConnectionState.CONNECT_GATT;
State.notifyChanged();
BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(macAddress());
mGatt = device.connectGatt(getActivity(), false, mBleCallback);
}
private void disconnectGatt()
{
if (mGatt != null)
{
mGatt.disconnect();
mGatt.close();
mGatt = null;
}
}
private static final int GATT_ERROR = 0x85;
private static final int GATT_AUTH_FAIL = 0x89;
private android.bluetooth.BluetoothGattCallback mBleCallback = new BluetoothGattCallback()
{
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState)
{
super.onConnectionStateChange(gatt, status, newState);
switch (newState)
{
case BluetoothProfile.STATE_CONNECTED:
if (gatt.discoverServices())
{
mState = ConnectionState.DISCOVER_SERVICES;
State.notifyChanged();
}
else
{
disconnectGatt();
mState = ConnectionState.FAILED;
State.notifyChanged();
}
break;
case BluetoothProfile.STATE_DISCONNECTED:
switch (mState)
{
case IDLE:
break;
case CONNECT_GATT:
deleteBondInformation(gatt.getDevice());
connectGatt();
break;
case DISCOVER_SERVICES:
deleteBondInformation(gatt.getDevice());
connectGatt();
break;
case READ_CHARACTERISTIC:
gatt.close();
mState = ConnectionState.FAILED;
State.notifyChanged();
break;
case FAILED:
case SUCCEEDED:
break;
}
break;
}
}
@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status)
{
super.onServicesDiscovered(gatt, status);
BluetoothGattService nameService = gatt.getService(UUIDs.NAME_SERVICE);
if (nameService == null)
{
disconnectGatt();
mState = ConnectionState.FAILED;
State.notifyChanged();
return;
}
BluetoothGattCharacteristic characteristic = nameService.getCharacteristic(UUIDs.NAME_CHARACTERISTIC);
if (characteristic == null)
{
disconnectGatt();
mState = ConnectionState.FAILED;
State.notifyChanged();
return;
}
gatt.readCharacteristic(characteristic);
mState = ConnectionState.READ_CHARACTERISTIC;
State.notifyChanged();
}
@Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status)
{
super.onCharacteristicRead(gatt, characteristic, status);
if (status == BluetoothGatt.GATT_SUCCESS)
{
if (!UUIDs.NAME_CHARACTERISTIC.equals(characteristic.getUuid()))
{
disconnectGatt();
mState = ConnectionState.FAILED;
State.notifyChanged();
return;
}
byte[] value = characteristic.getValue();
if (value == null)
{
}
disconnectGatt();
mState = ConnectionState.SUCCEEDED;
State.notifyChanged();
}
else if (status == BluetoothGatt.GATT_INSUFFICIENT_AUTHENTICATION)
{
if (gatt.getDevice().getBondState() == BluetoothDevice.BOND_NONE)
{
}
else
{
}
}
else if (status == GATT_AUTH_FAIL)
{
disconnectGatt();
mState = ConnectionState.FAILED;
State.notifyChanged();
}
else if (status == GATT_ERROR)
{
disconnectGatt();
mState = ConnectionState.FAILED;
State.notifyChanged();
}
else
{
disconnectGatt();
mState = ConnectionState.FAILED;
State.notifyChanged();
}
}
};
private final BroadcastReceiver mPairingRequestRecevier = new BroadcastReceiver()
{
@Override
public void onReceive(Context context, Intent intent)
{
if (BluetoothDevice.ACTION_PAIRING_REQUEST.equals(intent.getAction()))
{
final BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
int type = intent.getIntExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, BluetoothDevice.ERROR);
if (type == BluetoothDevice.PAIRING_VARIANT_PIN)
{
device.setPin(Util.IntToPasskey(pinCode()));
abortBroadcast();
}
else
{
L.w("Unexpected pairing type: " + type);
}
}
}
};
public static void deleteBondInformation(BluetoothDevice device)
{
try
{
Method m = device.getClass().getMethod("removeBond", (Class[]) null);
m.invoke(device, (Object[]) null);
}
catch (Exception e)
{
L.e(e.getMessage());
}
}
}
setPin()
方法,我已经让它工作了,但是“配对请求”通知仍然显示。 - Timmmm