f4b197f8ae
* feat: add requestConnectionPriority - Add BleConnectionPriority enum (balanced, highPerformance, lowPower) - Add BleCapabilities.supportsConnectionPriorityApi flag - Implement on Android via BluetoothGatt.requestConnectionPriority() - Throw notSupported on iOS, macOS, Windows, Linux, and Web - Update pigeon definition and regenerate platform channel files - Bump version 1.2.0 -> 1.3.0 * fix: improve requestConnectionPriority implementation - Remove redundant BleCapabilities guard in Dart layer (native handles it) - Add BleConnectionPriority Kotlin enum mirroring Dart enum - Map to explicit Android SDK constants via when expression - Add firstOrNull with ILLEGAL_ARGUMENT for unknown priority values - Add catch (e: Exception) block for broader error handling - Fix enum doc comment (throws belongs on method, not enum) - Remove stale capability check guidance from docs and README --------- Co-authored-by: aqeel-bmec-co <aqeel@bmec.co> Co-authored-by: aqeel-bmec-co <85945830+aqeel-bmec-co@users.noreply.github.com>
229 lines
9.8 KiB
C++
229 lines
9.8 KiB
C++
#ifndef FLUTTER_PLUGIN_UNIVERSAL_BLE_PLUGIN_H_
|
|
#define FLUTTER_PLUGIN_UNIVERSAL_BLE_PLUGIN_H_
|
|
|
|
#include <flutter/method_channel.h>
|
|
#include <flutter/plugin_registrar_windows.h>
|
|
|
|
#include <windows.h>
|
|
#include <winrt/Windows.Devices.Bluetooth.Advertisement.h>
|
|
#include <winrt/Windows.Devices.Bluetooth.GenericAttributeProfile.h>
|
|
#include <winrt/Windows.Devices.Bluetooth.h>
|
|
#include <winrt/Windows.Devices.Enumeration.h>
|
|
#include <winrt/Windows.Devices.Radios.h>
|
|
#include <winrt/Windows.Foundation.Collections.h>
|
|
#include <winrt/Windows.Foundation.h>
|
|
#include <winrt/Windows.Storage.Streams.h>
|
|
#include <winrt/base.h>
|
|
|
|
#include "generated/universal_ble.g.h"
|
|
#include "helper/universal_ble_base.h"
|
|
#include "helper/universal_enum.h"
|
|
#include "helper/utils.h"
|
|
#include "ui_thread_handler.hpp"
|
|
#include "universal_ble_thread_safe.h"
|
|
#include <memory>
|
|
|
|
namespace universal_ble {
|
|
struct GattCharacteristicObject {
|
|
GattCharacteristic obj = nullptr;
|
|
std::optional<event_token> subscription_token;
|
|
};
|
|
|
|
struct GattServiceObject {
|
|
GattDeviceService obj = nullptr;
|
|
std::unordered_map<std::string, GattCharacteristicObject> characteristics;
|
|
};
|
|
|
|
struct BluetoothDeviceAgent {
|
|
BluetoothLEDevice device;
|
|
event_token connection_status_changed_token;
|
|
std::unordered_map<std::string, GattServiceObject> gatt_map;
|
|
|
|
BluetoothDeviceAgent(
|
|
const BluetoothLEDevice &device,
|
|
const event_token connection_status_changed_token,
|
|
const std::unordered_map<std::string, GattServiceObject> &gatt_map)
|
|
: device(device),
|
|
connection_status_changed_token(connection_status_changed_token),
|
|
gatt_map(gatt_map) {}
|
|
|
|
~BluetoothDeviceAgent() { device = nullptr; }
|
|
|
|
GattCharacteristicObject &
|
|
FetchCharacteristic(const std::string &service_uuid,
|
|
const std::string &characteristic_uuid) {
|
|
if (gatt_map.count(service_uuid) == 0) {
|
|
throw create_flutter_error(UniversalBleErrorCode::kServiceNotFound,
|
|
"Service not found");
|
|
}
|
|
if (gatt_map[service_uuid].characteristics.count(characteristic_uuid) ==
|
|
0) {
|
|
throw create_flutter_error(UniversalBleErrorCode::kCharacteristicNotFound,
|
|
"Characteristic not found");
|
|
}
|
|
return gatt_map[service_uuid].characteristics.at(characteristic_uuid);
|
|
}
|
|
};
|
|
|
|
class UniversalBlePlugin : public flutter::Plugin,
|
|
public UniversalBlePlatformChannel {
|
|
public:
|
|
static void RegisterWithRegistrar(flutter::PluginRegistrarWindows *registrar);
|
|
|
|
UniversalBlePlugin(flutter::PluginRegistrarWindows *registrar);
|
|
|
|
~UniversalBlePlugin();
|
|
|
|
// Disallow copy and assign.
|
|
UniversalBlePlugin(const UniversalBlePlugin &) = delete;
|
|
UniversalBlePlugin &operator=(const UniversalBlePlugin &) = delete;
|
|
|
|
private:
|
|
static void SuccessCallback() {}
|
|
static void ErrorCallback(const FlutterError &error) {
|
|
// Ignore ChannelConnection Error, This might occur because of HotReload
|
|
if (error.code() != "channel-error") {
|
|
std::cout << "ErrorCode: " << error.code()
|
|
<< " Message: " << error.message() << std::endl;
|
|
}
|
|
}
|
|
static int64_t GetCurrentTimestampMillis() {
|
|
return std::chrono::duration_cast<std::chrono::milliseconds>(
|
|
std::chrono::system_clock::now().time_since_epoch())
|
|
.count();
|
|
}
|
|
|
|
flutter::PluginRegistrarWindows *registrar_;
|
|
bool initialized_ = false;
|
|
|
|
UniversalBleUiThreadHandler ui_thread_handler_;
|
|
Radio bluetooth_radio_{nullptr};
|
|
RadioState old_radio_state_ = RadioState::Unknown;
|
|
BluetoothLEAdvertisementWatcher bluetooth_le_watcher_{nullptr};
|
|
DeviceWatcher device_watcher_{nullptr};
|
|
|
|
std::unordered_map<uint64_t, std::unique_ptr<BluetoothDeviceAgent>>
|
|
connected_devices_{};
|
|
ThreadSafeMap<std::string, DeviceInformation> device_watcher_devices_{};
|
|
ThreadSafeMap<std::string, UniversalBleScanResult> scan_results_{};
|
|
// Maps DeviceInformation.Id() -> MAC address string used as key in
|
|
// device_watcher_devices_
|
|
ThreadSafeMap<std::string, std::string> device_watcher_id_to_mac_{};
|
|
|
|
event_token bluetooth_le_watcher_received_token_;
|
|
event_token device_watcher_added_token_;
|
|
event_token device_watcher_updated_token_;
|
|
event_token device_watcher_removed_token_;
|
|
event_token device_watcher_enumeration_completed_token_;
|
|
event_token device_watcher_stopped_token_;
|
|
event_revoker<IRadio> radio_state_changed_revoker_;
|
|
|
|
fire_and_forget InitializeAsync();
|
|
fire_and_forget ConnectAsync(uint64_t bluetooth_address);
|
|
fire_and_forget SetNotifiableAsync(
|
|
const std::string &device_id, const std::string &service,
|
|
const std::string &characteristic, int64_t ble_input_property,
|
|
std::function<void(std::optional<FlutterError> reply)> result);
|
|
fire_and_forget PairAsync(const std::string &device_id,
|
|
std::function<void(ErrorOr<bool> reply)> result);
|
|
fire_and_forget
|
|
CustomPairAsync(const std::string &device_id,
|
|
std::function<void(ErrorOr<bool> reply)> result);
|
|
static fire_and_forget GetSystemDevicesAsync(
|
|
std::vector<std::string> with_services,
|
|
std::function<void(ErrorOr<flutter::EncodableList> reply)> result);
|
|
static fire_and_forget
|
|
IsPairedAsync(const std::string &device_id,
|
|
std::function<void(ErrorOr<bool> reply)> result);
|
|
fire_and_forget DiscoverServicesAsync(
|
|
const std::string &device_id, bool with_descriptors,
|
|
std::function<void(ErrorOr<flutter::EncodableList> reply)> result);
|
|
|
|
void
|
|
PairingRequestedHandler(DeviceInformationCustomPairing sender,
|
|
const DevicePairingRequestedEventArgs &event_args);
|
|
|
|
void RadioStateChanged(const Radio &sender, const IInspectable &);
|
|
void SetupDeviceWatcher();
|
|
void DisposeDeviceWatcher();
|
|
void PushUniversalScanResult(UniversalBleScanResult scan_result,
|
|
bool is_connectable);
|
|
static std::string ExpandServiceUuid(const std::vector<uint8_t>& uuid_bytes,
|
|
uint8_t uuid_type);
|
|
void BluetoothLeWatcherReceived(
|
|
const BluetoothLEAdvertisementWatcher &sender,
|
|
const BluetoothLEAdvertisementReceivedEventArgs &args);
|
|
void OnDeviceInfoReceived(const DeviceInformation &device_info);
|
|
void BluetoothLeDeviceConnectionStatusChanged(const BluetoothLEDevice &sender,
|
|
const IInspectable &args);
|
|
void NotifyConnectionChanged(uint64_t bluetooth_address, bool connected,
|
|
std::optional<std::string> error = std::nullopt);
|
|
void NotifyConnectionException(uint64_t bluetooth_address,
|
|
const std::string &error_message);
|
|
void CleanConnection(uint64_t bluetooth_address);
|
|
void ResetState();
|
|
void
|
|
DisposeServices(const std::unique_ptr<BluetoothDeviceAgent> &device_agent);
|
|
|
|
void GattCharacteristicValueChanged(const GattCharacteristic &sender,
|
|
const GattValueChangedEventArgs &args);
|
|
|
|
// UniversalBlePlatformChannel implementation.
|
|
void GetBluetoothAvailabilityState(
|
|
std::function<void(ErrorOr<int64_t> reply)> result) override;
|
|
void
|
|
EnableBluetooth(std::function<void(ErrorOr<bool> reply)> result) override;
|
|
void
|
|
DisableBluetooth(std::function<void(ErrorOr<bool> reply)> result) override;
|
|
ErrorOr<int64_t> GetConnectionState(const std::string &device_id) override;
|
|
std::optional<FlutterError>
|
|
SetLogLevel(const UniversalBleLogLevel &log_level) override;
|
|
std::optional<FlutterError>
|
|
StartScan(const UniversalScanFilter *filter, const UniversalScanConfig *config) override;
|
|
std::optional<FlutterError> StopScan() override;
|
|
ErrorOr<bool> IsScanning() override;
|
|
std::optional<FlutterError> Connect(const std::string &device_id, const bool *auto_connect) override;
|
|
std::optional<FlutterError> Disconnect(const std::string &device_id) override;
|
|
ErrorOr<bool> HasPermissions(bool with_android_fine_location) override;
|
|
void RequestPermissions(
|
|
bool with_android_fine_location,
|
|
std::function<void(std::optional<FlutterError> reply)> result) override;
|
|
void
|
|
DiscoverServices(const std::string &device_id, bool with_descriptors,
|
|
std::function<void(ErrorOr<flutter::EncodableList> reply)>
|
|
result) override;
|
|
void SetNotifiable(
|
|
const std::string &device_id, const std::string &service,
|
|
const std::string &characteristic, int64_t ble_input_property,
|
|
std::function<void(std::optional<FlutterError> reply)> result) override;
|
|
void ReadValue(
|
|
const std::string &device_id, const std::string &service,
|
|
const std::string &characteristic,
|
|
std::function<void(ErrorOr<std::vector<uint8_t>> reply)> result) override;
|
|
void WriteValue(
|
|
const std::string &device_id, const std::string &service,
|
|
const std::string &characteristic, const std::vector<uint8_t> &value,
|
|
int64_t ble_output_property,
|
|
std::function<void(std::optional<FlutterError> reply)> result) override;
|
|
void RequestMtu(const std::string &device_id, int64_t expected_mtu,
|
|
std::function<void(ErrorOr<int64_t> reply)> result) override;
|
|
void RequestConnectionPriority(
|
|
const std::string &device_id, int64_t priority,
|
|
std::function<void(std::optional<FlutterError> reply)> result) override;
|
|
void ReadRssi(const std::string &device_id,
|
|
std::function<void(ErrorOr<int64_t> reply)> result) override;
|
|
void IsPaired(const std::string &device_id,
|
|
std::function<void(ErrorOr<bool> reply)> result) override;
|
|
void Pair(const std::string &device_id,
|
|
std::function<void(ErrorOr<bool> reply)> result) override;
|
|
std::optional<FlutterError> UnPair(const std::string &device_id) override;
|
|
void
|
|
GetSystemDevices(const flutter::EncodableList &with_services,
|
|
std::function<void(ErrorOr<flutter::EncodableList> reply)>
|
|
result) override;
|
|
};
|
|
|
|
} // namespace universal_ble
|
|
|
|
#endif // FLUTTER_PLUGIN_UNIVERSAL_BLE_PLUGIN_H_
|