@Override
		public void onReceive(final Context context, final Intent intent) {
			final BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
			final int bondState = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, -1);
			final int previousBondState = intent.getIntExtra(BluetoothDevice.EXTRA_PREVIOUS_BOND_STATE, -1);

			// Skip other devices.
			if (bluetoothDevice == null || device == null
					|| !device.getAddress().equals(bluetoothDevice.getAddress()))
				return;


			log(Log.DEBUG, () ->
					"[Broadcast] Action received: " + BluetoothDevice.ACTION_BOND_STATE_CHANGED +
						", bond state changed to: " + ParserUtils.bondStateToString(bondState) +
						" (" + bondState + ")");

			switch (bondState) {
				case BluetoothDevice.BOND_NONE -> {
					if (previousBondState == BluetoothDevice.BOND_BONDING) {
						postCallback(c -> c.onBondingFailed(device));
						postBondingStateChange(o -> o.onBondingFailed(device));
						log(Log.WARN, () -> "Bonding failed");
						if (request != null && (
								request.type == Request.Type.CREATE_BOND ||
								request.type == Request.Type.ENSURE_BOND ||
								// The following requests may trigger bonding.
								request.type == Request.Type.WRITE ||
								request.type == Request.Type.WRITE_DESCRIPTOR ||
								request.type == Request.Type.READ ||
								request.type == Request.Type.READ_DESCRIPTOR)) {
							request.notifyFail(device, FailCallback.REASON_REQUEST_FAILED);
							request = null;
						}
						// If the device started to pair just after the connection was
						// established the services were not discovered. We may try to discover services
						// despite the fail bonding process.
						// See: https://github.com/NordicSemiconductor/Android-BLE-Library/issues/335
						if (!servicesDiscovered && !serviceDiscoveryRequested) {
							final BluetoothGatt bluetoothGatt = BleManagerHandler.this.bluetoothGatt;
							if (bluetoothGatt != null) {
								serviceDiscoveryRequested = true;
								log(Log.VERBOSE, () -> "Discovering services...");
								log(Log.DEBUG, () -> "gatt.discoverServices()");
								bluetoothGatt.discoverServices();
							}
							return;
						}
					} else if (previousBondState == BluetoothDevice.BOND_BONDED) {
						// Removing the bond will cause disconnection.
						userDisconnected = true;

						if (request != null && request.type == Request.Type.REMOVE_BOND) {
							// The device has already disconnected by now.
							log(Log.INFO, () -> "Bond information removed");
							request.notifySuccess(device);
							request = null;
						}
						// When the bond information has been removed (either with Remove Bond request
						// or in Android Settings), the BluetoothGatt object should be closed, so
						// the library won't reconnect to the device automatically.
						// See: https://github.com/NordicSemiconductor/Android-BLE-Library/issues/157
						if (!isConnected())
							close();

						// Due to https://github.com/NordicSemiconductor/Android-BLE-Library/issues/363,
						// the call to close() here has been placed behind an if statement.
						// Instead, the 'userDisconnected' flag is set to true (here and in
						// 'internalRemoveBond()'.
						// When the device gets disconnected, close() method will be called from
						// 'notifyDeviceDisconnected(...)'.
					}
				}
				case BluetoothDevice.BOND_BONDING -> {
					postCallback(c -> c.onBondingRequired(device));
					postBondingStateChange(o -> o.onBondingRequired(device));
					return;
				}
				case BluetoothDevice.BOND_BONDED -> {
					log(Log.INFO, () -> "Device bonded");
					postCallback(c -> c.onBonded(device));
					postBondingStateChange(o -> o.onBonded(device));
					if (request != null && (request.type == Request.Type.CREATE_BOND || request.type == Request.Type.ENSURE_BOND)) {
						request.notifySuccess(device);
						request = null;
						break;
					}
					// If the device started to pair just after the connection was
					// established the services were not discovered.
					if (!servicesDiscovered && !serviceDiscoveryRequested) {
						final BluetoothGatt bluetoothGatt = BleManagerHandler.this.bluetoothGatt;
						if (bluetoothGatt != null) {
							serviceDiscoveryRequested = true;
							log(Log.VERBOSE, () -> "Discovering services...");
							log(Log.DEBUG, () -> "gatt.discoverServices()");
							bluetoothGatt.discoverServices();
						}
						return;
					}
					// On older Android versions, after executing a command on secured attribute
					// of a device that is not bonded, let's say a write characteristic operation,
					// the system will start bonding. The BOND_BONDING and BOND_BONDED events will
					// be received, but the command will not be repeated automatically.
					//
					// Test results:
					// Devices that require repeating the last task:
					// - Nexus 4 with Android 5.1.1
					// - Samsung S6 with 5.0.1
					// - Samsung S8 with Android 7.0
					// - Nexus 9 with Android 7.1.1
					// Devices that repeat the request automatically:
					// - Pixel 2 with Android 8.1.0
					// - Samsung S8 with Android 8.0.0
					//
					if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
						if (request != null) {
							// Repeat the last command in that case.
							enqueueFirst(request);
							break;
						}
					}
					// No need to repeat the request.
					return;
				}
			}
			nextRequest(true);
		}
An instance of a request that waits for a notification or an indication.
There may be only a single instance of such request at a time as this is a blocking request.
ble/src/main/java/no/nordicsemi/android/ble/BleManagerHandler.java