summaryrefslogtreecommitdiffstats
path: root/src/bluetooth
diff options
context:
space:
mode:
Diffstat (limited to 'src/bluetooth')
-rw-r--r--src/bluetooth/CMakeLists.txt272
-rw-r--r--src/bluetooth/android/android.pri20
-rw-r--r--src/bluetooth/android/androidbroadcastreceiver.cpp63
-rw-r--r--src/bluetooth/android/androidbroadcastreceiver_p.h63
-rw-r--r--src/bluetooth/android/androidutils.cpp50
-rw-r--r--src/bluetooth/android/androidutils_p.h32
-rw-r--r--src/bluetooth/android/devicediscoverybroadcastreceiver.cpp292
-rw-r--r--src/bluetooth/android/devicediscoverybroadcastreceiver_p.h45
-rw-r--r--src/bluetooth/android/inputstreamthread.cpp67
-rw-r--r--src/bluetooth/android/inputstreamthread_p.h49
-rw-r--r--src/bluetooth/android/jni_android.cpp328
-rw-r--r--src/bluetooth/android/jni_android_p.h140
-rw-r--r--src/bluetooth/android/localdevicebroadcastreceiver.cpp275
-rw-r--r--src/bluetooth/android/localdevicebroadcastreceiver_p.h46
-rw-r--r--src/bluetooth/android/lowenergynotificationhub.cpp129
-rw-r--r--src/bluetooth/android/lowenergynotificationhub_p.h117
-rw-r--r--src/bluetooth/android/serveracceptancethread.cpp82
-rw-r--r--src/bluetooth/android/serveracceptancethread_p.h54
-rw-r--r--src/bluetooth/android/servicediscoverybroadcastreceiver.cpp83
-rw-r--r--src/bluetooth/android/servicediscoverybroadcastreceiver_p.h42
-rw-r--r--src/bluetooth/bluetooth.pro269
-rw-r--r--src/bluetooth/bluez/adapter.cpp26
-rw-r--r--src/bluetooth/bluez/adapter1_bluez5.cpp6
-rw-r--r--src/bluetooth/bluez/adapter1_bluez5_p.h18
-rw-r--r--src/bluetooth/bluez/adapter_p.h157
-rw-r--r--src/bluetooth/bluez/agent.cpp87
-rw-r--r--src/bluetooth/bluez/agent_p.h79
-rw-r--r--src/bluetooth/bluez/battery1.cpp6
-rw-r--r--src/bluetooth/bluez/battery1_p.h18
-rw-r--r--src/bluetooth/bluez/bluetoothmanagement.cpp70
-rw-r--r--src/bluetooth/bluez/bluetoothmanagement_p.h93
-rw-r--r--src/bluetooth/bluez/bluez.pri58
-rw-r--r--src/bluetooth/bluez/bluez5_helper.cpp141
-rw-r--r--src/bluetooth/bluez/bluez5_helper_p.h57
-rw-r--r--src/bluetooth/bluez/bluez_data.cpp10
-rw-r--r--src/bluetooth/bluez/bluez_data_p.h184
-rw-r--r--src/bluetooth/bluez/bluezperipheralapplication.cpp280
-rw-r--r--src/bluetooth/bluez/bluezperipheralapplication_p.h100
-rw-r--r--src/bluetooth/bluez/bluezperipheralconnectionmanager.cpp96
-rw-r--r--src/bluetooth/bluez/bluezperipheralconnectionmanager_p.h68
-rw-r--r--src/bluetooth/bluez/bluezperipheralobjects.cpp403
-rw-r--r--src/bluetooth/bluez/bluezperipheralobjects_p.h171
-rw-r--r--src/bluetooth/bluez/device.cpp26
-rw-r--r--src/bluetooth/bluez/device1_bluez5.cpp6
-rw-r--r--src/bluetooth/bluez/device1_bluez5_p.h24
-rw-r--r--src/bluetooth/bluez/device_p.h104
-rw-r--r--src/bluetooth/bluez/gattchar1.cpp6
-rw-r--r--src/bluetooth/bluez/gattchar1_p.h18
-rw-r--r--src/bluetooth/bluez/gattcharacteristic1adaptor.cpp108
-rw-r--r--src/bluetooth/bluez/gattcharacteristic1adaptor_p.h87
-rw-r--r--src/bluetooth/bluez/gattdesc1.cpp6
-rw-r--r--src/bluetooth/bluez/gattdesc1_p.h18
-rw-r--r--src/bluetooth/bluez/gattdescriptor1adaptor.cpp84
-rw-r--r--src/bluetooth/bluez/gattdescriptor1adaptor_p.h75
-rw-r--r--src/bluetooth/bluez/gattmanager1.cpp28
-rw-r--r--src/bluetooth/bluez/gattmanager1_p.h73
-rw-r--r--src/bluetooth/bluez/gattservice1.cpp6
-rw-r--r--src/bluetooth/bluez/gattservice1_p.h18
-rw-r--r--src/bluetooth/bluez/gattservice1adaptor.cpp58
-rw-r--r--src/bluetooth/bluez/gattservice1adaptor_p.h67
-rwxr-xr-xsrc/bluetooth/bluez/generate49
-rw-r--r--src/bluetooth/bluez/hcimanager.cpp99
-rw-r--r--src/bluetooth/bluez/hcimanager_p.h180
-rw-r--r--src/bluetooth/bluez/leadvertisement1.cpp136
-rw-r--r--src/bluetooth/bluez/leadvertisement1_p.h97
-rw-r--r--src/bluetooth/bluez/leadvertisingmanager1.cpp28
-rw-r--r--src/bluetooth/bluez/leadvertisingmanager1_p.h85
-rw-r--r--src/bluetooth/bluez/manager.cpp26
-rw-r--r--src/bluetooth/bluez/manager_p.h69
-rw-r--r--src/bluetooth/bluez/obex_agent.cpp67
-rw-r--r--src/bluetooth/bluez/obex_agent_p.h66
-rw-r--r--src/bluetooth/bluez/obex_client.cpp26
-rw-r--r--src/bluetooth/bluez/obex_client1_bluez5.cpp26
-rw-r--r--src/bluetooth/bluez/obex_client1_bluez5_p.h63
-rw-r--r--src/bluetooth/bluez/obex_client_p.h82
-rw-r--r--src/bluetooth/bluez/obex_manager.cpp26
-rw-r--r--src/bluetooth/bluez/obex_manager_p.h65
-rw-r--r--src/bluetooth/bluez/obex_objectpush1_bluez5.cpp26
-rw-r--r--src/bluetooth/bluez/obex_objectpush1_bluez5_p.h100
-rw-r--r--src/bluetooth/bluez/obex_transfer.cpp26
-rw-r--r--src/bluetooth/bluez/obex_transfer1_bluez5.cpp26
-rw-r--r--src/bluetooth/bluez/obex_transfer1_bluez5_p.h91
-rw-r--r--src/bluetooth/bluez/obex_transfer_p.h59
-rw-r--r--src/bluetooth/bluez/objectmanager.cpp6
-rw-r--r--src/bluetooth/bluez/objectmanager_p.h19
-rw-r--r--src/bluetooth/bluez/objectmanageradaptor.cpp42
-rw-r--r--src/bluetooth/bluez/objectmanageradaptor_p.h67
-rw-r--r--src/bluetooth/bluez/org.bluez.Agent.xml32
-rw-r--r--src/bluetooth/bluez/org.bluez.Client1.xml15
-rw-r--r--src/bluetooth/bluez/org.bluez.Device.xml41
-rw-r--r--src/bluetooth/bluez/org.bluez.Device1.xml4
-rw-r--r--src/bluetooth/bluez/org.bluez.GattManager1.xml14
-rw-r--r--src/bluetooth/bluez/org.bluez.LEAdvertisement1.xml29
-rw-r--r--src/bluetooth/bluez/org.bluez.LEAdvertisingManager1.xml20
-rw-r--r--src/bluetooth/bluez/org.bluez.Manager.xml25
-rw-r--r--src/bluetooth/bluez/org.bluez.Service.xml21
-rw-r--r--src/bluetooth/bluez/org.bluez.all.xml145
-rw-r--r--src/bluetooth/bluez/org.bluez.obex.ObjectPush1.xml25
-rw-r--r--src/bluetooth/bluez/org.bluez.obex.Transfer1.xml16
-rw-r--r--src/bluetooth/bluez/org.openobex.agent.xml24
-rw-r--r--src/bluetooth/bluez/org.openobex.all.xml31
-rw-r--r--src/bluetooth/bluez/org.openobex.client.xml40
-rw-r--r--src/bluetooth/bluez/org.openobex.transfer.xml19
-rw-r--r--src/bluetooth/bluez/profile1.cpp6
-rw-r--r--src/bluetooth/bluez/profile1_p.h18
-rw-r--r--src/bluetooth/bluez/profile1context.cpp42
-rw-r--r--src/bluetooth/bluez/profile1context_p.h41
-rw-r--r--src/bluetooth/bluez/profilemanager1.cpp6
-rw-r--r--src/bluetooth/bluez/profilemanager1_p.h18
-rw-r--r--src/bluetooth/bluez/properties.cpp6
-rw-r--r--src/bluetooth/bluez/properties_p.h21
-rw-r--r--src/bluetooth/bluez/propertiesadaptor.cpp56
-rw-r--r--src/bluetooth/bluez/propertiesadaptor_p.h76
-rw-r--r--src/bluetooth/bluez/remotedevicemanager.cpp52
-rw-r--r--src/bluetooth/bluez/remotedevicemanager_p.h45
-rw-r--r--src/bluetooth/bluez/service.cpp26
-rw-r--r--src/bluetooth/bluez/service_p.h81
-rw-r--r--src/bluetooth/bluez/servicemap.cpp46
-rw-r--r--src/bluetooth/bluez/servicemap_p.h49
-rw-r--r--src/bluetooth/configure.cmake76
-rw-r--r--src/bluetooth/configure.json107
-rw-r--r--src/bluetooth/darwin/btcentralmanager.mm210
-rw-r--r--src/bluetooth/darwin/btcentralmanager_p.h53
-rw-r--r--src/bluetooth/darwin/btconnectionmonitor.mm88
-rw-r--r--src/bluetooth/darwin/btconnectionmonitor_p.h46
-rw-r--r--src/bluetooth/darwin/btdelegates.cpp40
-rw-r--r--src/bluetooth/darwin/btdelegates_p.h50
-rw-r--r--src/bluetooth/darwin/btdeviceinquiry.mm121
-rw-r--r--src/bluetooth/darwin/btdeviceinquiry_p.h44
-rw-r--r--src/bluetooth/darwin/btdevicepair.mm56
-rw-r--r--src/bluetooth/darwin/btdevicepair_p.h43
-rw-r--r--src/bluetooth/darwin/btgcdtimer.mm43
-rw-r--r--src/bluetooth/darwin/btgcdtimer_p.h48
-rw-r--r--src/bluetooth/darwin/btl2capchannel.mm58
-rw-r--r--src/bluetooth/darwin/btl2capchannel_p.h45
-rw-r--r--src/bluetooth/darwin/btledeviceinquiry.mm92
-rw-r--r--src/bluetooth/darwin/btledeviceinquiry_p.h48
-rw-r--r--src/bluetooth/darwin/btnotifier.cpp3
-rw-r--r--src/bluetooth/darwin/btnotifier_p.h46
-rw-r--r--src/bluetooth/darwin/btobexsession.mm843
-rw-r--r--src/bluetooth/darwin/btobexsession_p.h138
-rw-r--r--src/bluetooth/darwin/btperipheralmanager.mm155
-rw-r--r--src/bluetooth/darwin/btperipheralmanager_p.h51
-rw-r--r--src/bluetooth/darwin/btraii.mm40
-rw-r--r--src/bluetooth/darwin/btraii_p.h46
-rw-r--r--src/bluetooth/darwin/btrfcommchannel.mm58
-rw-r--r--src/bluetooth/darwin/btrfcommchannel_p.h46
-rw-r--r--src/bluetooth/darwin/btsdpinquiry.mm208
-rw-r--r--src/bluetooth/darwin/btsdpinquiry_p.h48
-rw-r--r--src/bluetooth/darwin/btservicerecord.mm107
-rw-r--r--src/bluetooth/darwin/btservicerecord_p.h40
-rw-r--r--src/bluetooth/darwin/btsocketlistener.mm46
-rw-r--r--src/bluetooth/darwin/btsocketlistener_p.h45
-rw-r--r--src/bluetooth/darwin/btutility.mm90
-rw-r--r--src/bluetooth/darwin/btutility_p.h61
-rw-r--r--src/bluetooth/darwin/darwinbt.pri48
-rw-r--r--src/bluetooth/darwin/uistrings.cpp44
-rw-r--r--src/bluetooth/darwin/uistrings_p.h47
-rw-r--r--src/bluetooth/doc/qt6-changes.qdoc141
-rw-r--r--src/bluetooth/doc/qtbluetooth.qdocconf28
-rw-r--r--src/bluetooth/doc/snippets/CMakeLists.txt7
-rw-r--r--src/bluetooth/doc/snippets/doc_src_qtbluetooth.cpp104
-rw-r--r--src/bluetooth/doc/snippets/doc_src_qtbluetooth.qml78
-rw-r--r--src/bluetooth/doc/snippets/snippets.pro5
-rw-r--r--src/bluetooth/doc/src/bluetooth-cpp.qdoc31
-rw-r--r--src/bluetooth/doc/src/bluetooth-index.qdoc156
-rw-r--r--src/bluetooth/doc/src/bluetooth-le-overview.qdoc68
-rw-r--r--src/bluetooth/doc/src/bluetooth-overview.qdoc51
-rw-r--r--src/bluetooth/doc/src/bluetooth-qml.qdoc48
-rw-r--r--src/bluetooth/doc/src/examples.qdoc47
-rw-r--r--src/bluetooth/dummy/dummy.pri2
-rw-r--r--src/bluetooth/dummy/dummy_helper.cpp40
-rw-r--r--src/bluetooth/dummy/dummy_helper_p.h42
-rw-r--r--src/bluetooth/lecmaccalculator.cpp56
-rw-r--r--src/bluetooth/lecmaccalculator_p.h49
-rw-r--r--src/bluetooth/osx/osxbt.pri61
-rw-r--r--src/bluetooth/qbluetooth.cpp47
-rw-r--r--src/bluetooth/qbluetooth.h52
-rw-r--r--src/bluetooth/qbluetoothaddress.cpp194
-rw-r--r--src/bluetooth/qbluetoothaddress.h124
-rw-r--r--src/bluetooth/qbluetoothaddress_p.h68
-rw-r--r--src/bluetooth/qbluetoothdevicediscoveryagent.cpp131
-rw-r--r--src/bluetooth/qbluetoothdevicediscoveryagent.h58
-rw-r--r--src/bluetooth/qbluetoothdevicediscoveryagent_android.cpp332
-rw-r--r--src/bluetooth/qbluetoothdevicediscoveryagent_bluez.cpp438
-rw-r--r--src/bluetooth/qbluetoothdevicediscoveryagent_darwin.mm175
-rw-r--r--src/bluetooth/qbluetoothdevicediscoveryagent_p.cpp48
-rw-r--r--src/bluetooth/qbluetoothdevicediscoveryagent_p.h148
-rw-r--r--src/bluetooth/qbluetoothdevicediscoveryagent_win.cpp557
-rw-r--r--src/bluetooth/qbluetoothdevicediscoveryagent_winrt.cpp1345
-rw-r--r--src/bluetooth/qbluetoothdeviceinfo.cpp323
-rw-r--r--src/bluetooth/qbluetoothdeviceinfo.h105
-rw-r--r--src/bluetooth/qbluetoothdeviceinfo_p.h64
-rw-r--r--src/bluetooth/qbluetoothdevicewatcher_winrt.cpp105
-rw-r--r--src/bluetooth/qbluetoothdevicewatcher_winrt_p.h69
-rw-r--r--src/bluetooth/qbluetoothhostinfo.cpp71
-rw-r--r--src/bluetooth/qbluetoothhostinfo.h54
-rw-r--r--src/bluetooth/qbluetoothhostinfo_p.h41
-rw-r--r--src/bluetooth/qbluetoothlocaldevice.cpp140
-rw-r--r--src/bluetooth/qbluetoothlocaldevice.h57
-rw-r--r--src/bluetooth/qbluetoothlocaldevice_android.cpp306
-rw-r--r--src/bluetooth/qbluetoothlocaldevice_bluez.cpp861
-rw-r--r--src/bluetooth/qbluetoothlocaldevice_macos.mm90
-rw-r--r--src/bluetooth/qbluetoothlocaldevice_p.cpp47
-rw-r--r--src/bluetooth/qbluetoothlocaldevice_p.h168
-rw-r--r--src/bluetooth/qbluetoothlocaldevice_win.cpp260
-rw-r--r--src/bluetooth/qbluetoothlocaldevice_winrt.cpp854
-rw-r--r--src/bluetooth/qbluetoothserver.cpp75
-rw-r--r--src/bluetooth/qbluetoothserver.h50
-rw-r--r--src/bluetooth/qbluetoothserver_android.cpp82
-rw-r--r--src/bluetooth/qbluetoothserver_bluez.cpp91
-rw-r--r--src/bluetooth/qbluetoothserver_macos.mm83
-rw-r--r--src/bluetooth/qbluetoothserver_p.cpp46
-rw-r--r--src/bluetooth/qbluetoothserver_p.h66
-rw-r--r--src/bluetooth/qbluetoothserver_win.cpp240
-rw-r--r--src/bluetooth/qbluetoothserver_winrt.cpp112
-rw-r--r--src/bluetooth/qbluetoothservicediscoveryagent.cpp90
-rw-r--r--src/bluetooth/qbluetoothservicediscoveryagent.h43
-rw-r--r--src/bluetooth/qbluetoothservicediscoveryagent_android.cpp227
-rw-r--r--src/bluetooth/qbluetoothservicediscoveryagent_bluez.cpp483
-rw-r--r--src/bluetooth/qbluetoothservicediscoveryagent_macos.mm83
-rw-r--r--src/bluetooth/qbluetoothservicediscoveryagent_p.cpp42
-rw-r--r--src/bluetooth/qbluetoothservicediscoveryagent_p.h103
-rw-r--r--src/bluetooth/qbluetoothservicediscoveryagent_win.cpp437
-rw-r--r--src/bluetooth/qbluetoothservicediscoveryagent_winrt.cpp197
-rw-r--r--src/bluetooth/qbluetoothserviceinfo.cpp84
-rw-r--r--src/bluetooth/qbluetoothserviceinfo.h60
-rw-r--r--src/bluetooth/qbluetoothserviceinfo_android.cpp54
-rw-r--r--src/bluetooth/qbluetoothserviceinfo_bluez.cpp254
-rw-r--r--src/bluetooth/qbluetoothserviceinfo_macos.mm50
-rw-r--r--src/bluetooth/qbluetoothserviceinfo_p.cpp42
-rw-r--r--src/bluetooth/qbluetoothserviceinfo_p.h58
-rw-r--r--src/bluetooth/qbluetoothserviceinfo_win.cpp120
-rw-r--r--src/bluetooth/qbluetoothserviceinfo_winrt.cpp150
-rw-r--r--src/bluetooth/qbluetoothsocket.cpp203
-rw-r--r--src/bluetooth/qbluetoothsocket.h103
-rw-r--r--src/bluetooth/qbluetoothsocket_android.cpp534
-rw-r--r--src/bluetooth/qbluetoothsocket_android_p.h69
-rw-r--r--src/bluetooth/qbluetoothsocket_bluez.cpp229
-rw-r--r--src/bluetooth/qbluetoothsocket_bluez_p.h42
-rw-r--r--src/bluetooth/qbluetoothsocket_bluezdbus.cpp180
-rw-r--r--src/bluetooth/qbluetoothsocket_bluezdbus_p.h46
-rw-r--r--src/bluetooth/qbluetoothsocket_dummy.cpp58
-rw-r--r--src/bluetooth/qbluetoothsocket_dummy_p.h42
-rw-r--r--src/bluetooth/qbluetoothsocket_macos.mm243
-rw-r--r--src/bluetooth/qbluetoothsocket_macos_p.h58
-rw-r--r--src/bluetooth/qbluetoothsocket_win.cpp597
-rw-r--r--src/bluetooth/qbluetoothsocket_win_p.h118
-rw-r--r--src/bluetooth/qbluetoothsocket_winrt.cpp414
-rw-r--r--src/bluetooth/qbluetoothsocket_winrt_p.h50
-rw-r--r--src/bluetooth/qbluetoothsocketbase.cpp42
-rw-r--r--src/bluetooth/qbluetoothsocketbase_p.h56
-rw-r--r--src/bluetooth/qbluetoothtransfermanager.cpp136
-rw-r--r--src/bluetooth/qbluetoothtransfermanager.h73
-rw-r--r--src/bluetooth/qbluetoothtransferreply.cpp214
-rw-r--r--src/bluetooth/qbluetoothtransferreply.h107
-rw-r--r--src/bluetooth/qbluetoothtransferreply_bluez.cpp474
-rw-r--r--src/bluetooth/qbluetoothtransferreply_bluez_p.h136
-rw-r--r--src/bluetooth/qbluetoothtransferreply_macos.mm480
-rw-r--r--src/bluetooth/qbluetoothtransferreply_macos_p.h101
-rw-r--r--src/bluetooth/qbluetoothtransferreply_p.h70
-rw-r--r--src/bluetooth/qbluetoothtransferrequest.cpp184
-rw-r--r--src/bluetooth/qbluetoothtransferrequest.h88
-rw-r--r--src/bluetooth/qbluetoothtransferrequest_p.h72
-rw-r--r--src/bluetooth/qbluetoothutils_win.cpp94
-rw-r--r--src/bluetooth/qbluetoothutils_winrt.cpp124
-rw-r--r--src/bluetooth/qbluetoothutils_winrt_p.h57
-rw-r--r--src/bluetooth/qbluetoothuuid.cpp786
-rw-r--r--src/bluetooth/qbluetoothuuid.h138
-rw-r--r--src/bluetooth/qbluetoothuuid_darwin.mm46
-rw-r--r--src/bluetooth/qleadvertiser_bluez.cpp155
-rw-r--r--src/bluetooth/qleadvertiser_bluez_p.h (renamed from src/bluetooth/qleadvertiser_p.h)71
-rw-r--r--src/bluetooth/qleadvertiser_bluezdbus.cpp229
-rw-r--r--src/bluetooth/qleadvertiser_bluezdbus_p.h66
-rw-r--r--src/bluetooth/qlowenergyadvertisingdata.cpp84
-rw-r--r--src/bluetooth/qlowenergyadvertisingdata.h61
-rw-r--r--src/bluetooth/qlowenergyadvertisingparameters.cpp106
-rw-r--r--src/bluetooth/qlowenergyadvertisingparameters.h81
-rw-r--r--src/bluetooth/qlowenergycharacteristic.cpp195
-rw-r--r--src/bluetooth/qlowenergycharacteristic.h68
-rw-r--r--src/bluetooth/qlowenergycharacteristicdata.cpp82
-rw-r--r--src/bluetooth/qlowenergycharacteristicdata.h64
-rw-r--r--src/bluetooth/qlowenergyconnectionparameters.cpp75
-rw-r--r--src/bluetooth/qlowenergyconnectionparameters.h66
-rw-r--r--src/bluetooth/qlowenergycontroller.cpp373
-rw-r--r--src/bluetooth/qlowenergycontroller.h89
-rw-r--r--src/bluetooth/qlowenergycontroller_android.cpp579
-rw-r--r--src/bluetooth/qlowenergycontroller_android_p.h57
-rw-r--r--src/bluetooth/qlowenergycontroller_bluez.cpp1167
-rw-r--r--src/bluetooth/qlowenergycontroller_bluez_p.h100
-rw-r--r--src/bluetooth/qlowenergycontroller_bluezdbus.cpp491
-rw-r--r--src/bluetooth/qlowenergycontroller_bluezdbus_p.h117
-rw-r--r--src/bluetooth/qlowenergycontroller_darwin.mm390
-rw-r--r--src/bluetooth/qlowenergycontroller_darwin_p.h59
-rw-r--r--src/bluetooth/qlowenergycontroller_dummy.cpp49
-rw-r--r--src/bluetooth/qlowenergycontroller_dummy_p.h46
-rw-r--r--src/bluetooth/qlowenergycontroller_win.cpp1356
-rw-r--r--src/bluetooth/qlowenergycontroller_win_p.h185
-rw-r--r--src/bluetooth/qlowenergycontroller_winrt.cpp2308
-rw-r--r--src/bluetooth/qlowenergycontroller_winrt_new.cpp1703
-rw-r--r--src/bluetooth/qlowenergycontroller_winrt_new_p.h181
-rw-r--r--src/bluetooth/qlowenergycontroller_winrt_p.h123
-rw-r--r--src/bluetooth/qlowenergycontrollerbase.cpp63
-rw-r--r--src/bluetooth/qlowenergycontrollerbase_p.h83
-rw-r--r--src/bluetooth/qlowenergydescriptor.cpp123
-rw-r--r--src/bluetooth/qlowenergydescriptor.h62
-rw-r--r--src/bluetooth/qlowenergydescriptordata.cpp80
-rw-r--r--src/bluetooth/qlowenergydescriptordata.h62
-rw-r--r--src/bluetooth/qlowenergyservice.cpp208
-rw-r--r--src/bluetooth/qlowenergyservice.h87
-rw-r--r--src/bluetooth/qlowenergyservicedata.cpp74
-rw-r--r--src/bluetooth/qlowenergyservicedata.h60
-rw-r--r--src/bluetooth/qlowenergyserviceprivate.cpp59
-rw-r--r--src/bluetooth/qlowenergyserviceprivate_p.h71
-rw-r--r--src/bluetooth/qprivatelinearbuffer_p.h77
-rw-r--r--src/bluetooth/qtbluetoothglobal.h55
-rw-r--r--src/bluetooth/qtbluetoothglobal_p.h47
-rw-r--r--src/bluetooth/removed_api.cpp57
-rw-r--r--src/bluetooth/windows/qwinlowenergybluetooth_p.h231
-rw-r--r--src/bluetooth/windows/windows.pri2
320 files changed, 14339 insertions, 27848 deletions
diff --git a/src/bluetooth/CMakeLists.txt b/src/bluetooth/CMakeLists.txt
new file mode 100644
index 00000000..54e7ac02
--- /dev/null
+++ b/src/bluetooth/CMakeLists.txt
@@ -0,0 +1,272 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## Bluetooth Module:
+#####################################################################
+
+qt_internal_add_module(Bluetooth
+ SOURCES
+ lecmaccalculator_p.h
+ removed_api.cpp
+ qbluetooth.cpp qbluetooth.h
+ qbluetoothaddress.cpp qbluetoothaddress.h
+ qbluetoothdevicediscoveryagent.cpp qbluetoothdevicediscoveryagent.h qbluetoothdevicediscoveryagent_p.h
+ qbluetoothdeviceinfo.cpp qbluetoothdeviceinfo.h qbluetoothdeviceinfo_p.h
+ qbluetoothhostinfo.cpp qbluetoothhostinfo.h qbluetoothhostinfo_p.h
+ qbluetoothlocaldevice.cpp qbluetoothlocaldevice.h qbluetoothlocaldevice_p.h
+ qbluetoothserver.cpp qbluetoothserver.h qbluetoothserver_p.h
+ qbluetoothservicediscoveryagent.cpp qbluetoothservicediscoveryagent.h qbluetoothservicediscoveryagent_p.h
+ qbluetoothserviceinfo.cpp qbluetoothserviceinfo.h qbluetoothserviceinfo_p.h
+ qbluetoothsocket.cpp qbluetoothsocket.h
+ qbluetoothsocketbase.cpp qbluetoothsocketbase_p.h
+ qbluetoothuuid.cpp qbluetoothuuid.h
+ qlowenergyadvertisingdata.cpp qlowenergyadvertisingdata.h
+ qlowenergyadvertisingparameters.cpp qlowenergyadvertisingparameters.h
+ qlowenergycharacteristic.cpp qlowenergycharacteristic.h
+ qlowenergycharacteristicdata.cpp qlowenergycharacteristicdata.h
+ qlowenergyconnectionparameters.cpp qlowenergyconnectionparameters.h
+ qlowenergycontroller.cpp qlowenergycontroller.h
+ qlowenergycontrollerbase.cpp qlowenergycontrollerbase_p.h
+ qlowenergydescriptor.cpp qlowenergydescriptor.h
+ qlowenergydescriptordata.cpp qlowenergydescriptordata.h
+ qlowenergyservice.cpp qlowenergyservice.h
+ qlowenergyservicedata.cpp qlowenergyservicedata.h
+ qlowenergyserviceprivate.cpp qlowenergyserviceprivate_p.h
+ qprivatelinearbuffer_p.h
+ qtbluetoothglobal.h qtbluetoothglobal_p.h
+ DEFINES
+ QT_NO_CONTEXTLESS_CONNECT
+ LIBRARIES
+ Qt::CorePrivate
+ Qt::NetworkPrivate
+ PUBLIC_LIBRARIES
+ Qt::Core
+ Qt::Network
+ PRIVATE_MODULE_INTERFACE
+ Qt::CorePrivate
+ Qt::NetworkPrivate
+ GENERATE_CPP_EXPORTS
+)
+
+#### Keys ignored in scope 1:.:.:bluetooth.pro:<TRUE>:
+# OTHER_FILES = "doc/src/*.qdoc"
+
+## Scopes:
+#####################################################################
+
+if(QT_FEATURE_bluez)
+ qt_internal_extend_target(Bluetooth
+ SOURCES
+ bluez/adapter1_bluez5.cpp bluez/adapter1_bluez5_p.h
+ bluez/battery1.cpp bluez/battery1_p.h
+ bluez/bluetoothmanagement.cpp bluez/bluetoothmanagement_p.h
+ bluez/bluez5_helper.cpp bluez/bluez5_helper_p.h
+ bluez/bluez_data.cpp bluez/bluez_data_p.h
+ bluez/device1_bluez5.cpp bluez/device1_bluez5_p.h
+ bluez/gattchar1.cpp bluez/gattchar1_p.h
+ bluez/gattdesc1.cpp bluez/gattdesc1_p.h
+ bluez/gattservice1.cpp bluez/gattservice1_p.h
+ bluez/hcimanager.cpp bluez/hcimanager_p.h
+ bluez/objectmanager.cpp bluez/objectmanager_p.h
+ bluez/profile1.cpp bluez/profile1_p.h
+ bluez/profile1context.cpp bluez/profile1context_p.h
+ bluez/profilemanager1.cpp bluez/profilemanager1_p.h
+ bluez/properties.cpp bluez/properties_p.h
+ bluez/remotedevicemanager.cpp bluez/remotedevicemanager_p.h
+ bluez/servicemap.cpp bluez/servicemap_p.h
+ bluez/gattmanager1.cpp bluez/gattmanager1_p.h
+ bluez/leadvertisement1.cpp bluez/leadvertisement1_p.h
+ bluez/leadvertisingmanager1.cpp bluez/leadvertisingmanager1_p.h
+ bluez/objectmanageradaptor.cpp bluez/objectmanageradaptor_p.h
+ bluez/propertiesadaptor.cpp bluez/propertiesadaptor_p.h
+ bluez/gattcharacteristic1adaptor.cpp bluez/gattcharacteristic1adaptor_p.h
+ bluez/gattdescriptor1adaptor.cpp bluez/gattdescriptor1adaptor_p.h
+ bluez/gattservice1adaptor.cpp bluez/gattservice1adaptor_p.h
+ bluez/bluezperipheralapplication.cpp bluez/bluezperipheralapplication_p.h
+ bluez/bluezperipheralobjects.cpp bluez/bluezperipheralobjects_p.h
+ bluez/bluezperipheralconnectionmanager.cpp bluez/bluezperipheralconnectionmanager_p.h
+ qbluetoothdevicediscoveryagent_bluez.cpp
+ qbluetoothlocaldevice_bluez.cpp
+ qbluetoothserver_bluez.cpp
+ qbluetoothservicediscoveryagent_bluez.cpp
+ qbluetoothserviceinfo_bluez.cpp
+ qbluetoothsocket_bluez.cpp qbluetoothsocket_bluez_p.h
+ qbluetoothsocket_bluezdbus.cpp qbluetoothsocket_bluezdbus_p.h
+ PUBLIC_LIBRARIES # for Linux QEMU (gcc-armv7) on Linux Ubuntu_20_04 (gcc-x86_64)
+ Qt::DBus
+ )
+
+ if(QT_FEATURE_bluez_le)
+ qt_internal_extend_target(Bluetooth
+ SOURCES
+ lecmaccalculator.cpp
+ qleadvertiser_bluez.cpp qleadvertiser_bluez_p.h
+ qleadvertiser_bluezdbus.cpp qleadvertiser_bluezdbus_p.h
+ qlowenergycontroller_bluez.cpp qlowenergycontroller_bluez_p.h
+ qlowenergycontroller_bluezdbus.cpp qlowenergycontroller_bluezdbus_p.h
+ )
+
+ if(QT_FEATURE_linux_crypto_api)
+ qt_internal_extend_target(Bluetooth
+ DEFINES
+ CONFIG_LINUX_CRYPTO_API
+ )
+ endif()
+ else()
+ qt_internal_extend_target(Bluetooth
+ SOURCES
+ dummy/dummy_helper.cpp dummy/dummy_helper_p.h
+ qlowenergycontroller_dummy.cpp qlowenergycontroller_dummy_p.h
+ DEFINES
+ QT_BLUEZ_NO_BTLE
+ )
+ endif()
+
+elseif(ANDROID AND NOT ANDROID_EMBEDDED)
+ set_property(TARGET Bluetooth APPEND PROPERTY QT_ANDROID_BUNDLED_JAR_DEPENDENCIES
+ jar/Qt${QtConnectivity_VERSION_MAJOR}AndroidBluetooth.jar:org.qtproject.qt.android.bluetooth.QtBluetoothBroadcastReceiver
+ )
+ set_property(TARGET Bluetooth APPEND PROPERTY QT_ANDROID_PERMISSIONS
+ android.permission.ACCESS_FINE_LOCATION
+ android.permission.BLUETOOTH
+ android.permission.BLUETOOTH_ADMIN
+ # Android 12 / SDK 31+
+ android.permission.BLUETOOTH_SCAN
+ android.permission.BLUETOOTH_ADVERTISE
+ android.permission.BLUETOOTH_CONNECT
+ )
+
+ qt_internal_extend_target(Bluetooth
+ SOURCES
+ android/androidbroadcastreceiver.cpp android/androidbroadcastreceiver_p.h
+ android/devicediscoverybroadcastreceiver.cpp android/devicediscoverybroadcastreceiver_p.h
+ android/inputstreamthread.cpp android/inputstreamthread_p.h
+ android/jni_android.cpp android/jni_android_p.h
+ android/localdevicebroadcastreceiver.cpp android/localdevicebroadcastreceiver_p.h
+ android/lowenergynotificationhub.cpp android/lowenergynotificationhub_p.h
+ android/serveracceptancethread.cpp android/serveracceptancethread_p.h
+ android/servicediscoverybroadcastreceiver.cpp android/servicediscoverybroadcastreceiver_p.h
+ android/androidutils.cpp android/androidutils_p.h
+ qbluetoothdevicediscoveryagent_android.cpp
+ qbluetoothlocaldevice_android.cpp
+ qbluetoothserver_android.cpp
+ qbluetoothservicediscoveryagent_android.cpp
+ qbluetoothserviceinfo_android.cpp
+ qbluetoothsocket_android.cpp qbluetoothsocket_android_p.h
+ qlowenergycontroller_android.cpp qlowenergycontroller_android_p.h
+ DEFINES
+ QT_ANDROID_BLUETOOTH
+ LIBRARIES
+ Qt::CorePrivate
+ PRIVATE_MODULE_INTERFACE
+ Qt::CorePrivate
+ )
+elseif(MACOS)
+ qt_internal_extend_target(Bluetooth
+ SOURCES
+ darwin/btcentralmanager.mm darwin/btcentralmanager_p.h
+ darwin/btconnectionmonitor.mm darwin/btconnectionmonitor_p.h
+ darwin/btdelegates.cpp darwin/btdelegates_p.h
+ darwin/btdeviceinquiry.mm darwin/btdeviceinquiry_p.h
+ darwin/btdevicepair.mm darwin/btdevicepair_p.h
+ darwin/btgcdtimer.mm darwin/btgcdtimer_p.h
+ darwin/btl2capchannel.mm darwin/btl2capchannel_p.h
+ darwin/btledeviceinquiry.mm darwin/btledeviceinquiry_p.h
+ darwin/btnotifier.cpp darwin/btnotifier_p.h
+ darwin/btperipheralmanager.mm darwin/btperipheralmanager_p.h
+ darwin/btraii.mm darwin/btraii_p.h
+ darwin/btrfcommchannel.mm darwin/btrfcommchannel_p.h
+ darwin/btsdpinquiry.mm darwin/btsdpinquiry_p.h
+ darwin/btservicerecord.mm darwin/btservicerecord_p.h
+ darwin/btsocketlistener.mm darwin/btsocketlistener_p.h
+ darwin/btutility.mm darwin/btutility_p.h
+ darwin/uistrings.cpp darwin/uistrings_p.h
+ qbluetoothdevicediscoveryagent_darwin.mm
+ qbluetoothlocaldevice_macos.mm
+ qbluetoothserver_macos.mm
+ qbluetoothservicediscoveryagent_macos.mm
+ qbluetoothserviceinfo_macos.mm
+ qbluetoothsocket_macos.mm qbluetoothsocket_macos_p.h
+ qlowenergycontroller_darwin.mm qlowenergycontroller_darwin_p.h
+ qbluetoothuuid_darwin.mm
+ DEFINES
+ QT_OSX_BLUETOOTH
+ LIBRARIES
+ Qt::CorePrivate
+ ${FWFoundation}
+ ${FWIOBluetooth}
+ )
+elseif(IOS)
+ qt_internal_extend_target(Bluetooth
+ SOURCES
+ darwin/btcentralmanager.mm darwin/btcentralmanager_p.h
+ darwin/btdelegates.cpp darwin/btdelegates_p.h
+ darwin/btgcdtimer.mm darwin/btgcdtimer_p.h
+ darwin/btledeviceinquiry.mm darwin/btledeviceinquiry_p.h
+ darwin/btnotifier.cpp darwin/btnotifier_p.h
+ darwin/btraii.mm darwin/btraii_p.h
+ darwin/btutility.mm darwin/btutility_p.h
+ darwin/uistrings.cpp darwin/uistrings_p.h
+ qbluetoothdevicediscoveryagent_darwin.mm
+ qbluetoothlocaldevice_p.cpp
+ qbluetoothserver_p.cpp
+ qbluetoothservicediscoveryagent_p.cpp
+ qbluetoothserviceinfo_p.cpp
+ qbluetoothsocket_dummy.cpp qbluetoothsocket_dummy_p.h
+ qlowenergycontroller_darwin.mm qlowenergycontroller_darwin_p.h
+ darwin/btperipheralmanager.mm darwin/btperipheralmanager_p.h
+ qbluetoothuuid_darwin.mm
+ DEFINES
+ QT_IOS_BLUETOOTH
+ LIBRARIES
+ Qt::CorePrivate
+ ${FWCoreBluetooth}
+ ${FWFoundation}
+ )
+elseif(QT_FEATURE_winrt_bt)
+ qt_internal_extend_target(Bluetooth
+ SOURCES
+ qbluetoothdevicediscoveryagent_winrt.cpp
+ qbluetoothlocaldevice_winrt.cpp
+ qbluetoothserver_winrt.cpp
+ qbluetoothservicediscoveryagent_winrt.cpp
+ qbluetoothserviceinfo_winrt.cpp
+ qbluetoothsocket_winrt.cpp qbluetoothsocket_winrt_p.h
+ qbluetoothutils_winrt.cpp qbluetoothutils_winrt_p.h
+ qlowenergycontroller_winrt.cpp qlowenergycontroller_winrt_p.h
+ qbluetoothdevicewatcher_winrt.cpp qbluetoothdevicewatcher_winrt_p.h
+ NO_UNITY_BUILD_SOURCES
+ qbluetoothdevicediscoveryagent_winrt.cpp
+ qbluetoothdevicewatcher_winrt.cpp
+ qbluetoothlocaldevice_winrt.cpp
+ DEFINES
+ QT_WINRT_BLUETOOTH
+ LIBRARIES
+ Qt::CorePrivate
+ PUBLIC_LIBRARIES
+ Qt::Core
+ runtimeobject
+ user32
+ PRIVATE_MODULE_INTERFACE
+ Qt::CorePrivate
+ )
+else()
+ qt_internal_extend_target(Bluetooth
+ SOURCES
+ dummy/dummy_helper.cpp dummy/dummy_helper_p.h
+ qbluetoothdevicediscoveryagent_p.cpp
+ qbluetoothlocaldevice_p.cpp
+ qbluetoothserver_p.cpp
+ qbluetoothservicediscoveryagent_p.cpp
+ qbluetoothserviceinfo_p.cpp
+ qbluetoothsocket_dummy.cpp qbluetoothsocket_dummy_p.h
+ qlowenergycontroller_dummy.cpp qlowenergycontroller_dummy_p.h
+ )
+endif()
+qt_update_ignore_pch_source(Bluetooth removed_api.cpp)
+
+qt_internal_add_docs(Bluetooth
+ doc/qtbluetooth.qdocconf
+)
+
diff --git a/src/bluetooth/android/android.pri b/src/bluetooth/android/android.pri
deleted file mode 100644
index af39a6d7..00000000
--- a/src/bluetooth/android/android.pri
+++ /dev/null
@@ -1,20 +0,0 @@
-HEADERS += \
- android/inputstreamthread_p.h \
- android/devicediscoverybroadcastreceiver_p.h \
- android/servicediscoverybroadcastreceiver_p.h \
- android/androidbroadcastreceiver_p.h \
- android/localdevicebroadcastreceiver_p.h \
- android/serveracceptancethread_p.h \
- android/jni_android_p.h \
- android/lowenergynotificationhub_p.h
-
-
-SOURCES += \
- android/inputstreamthread.cpp \
- android/devicediscoverybroadcastreceiver.cpp \
- android/servicediscoverybroadcastreceiver.cpp \
- android/jni_android.cpp \
- android/androidbroadcastreceiver.cpp \
- android/localdevicebroadcastreceiver.cpp \
- android/serveracceptancethread.cpp \
- android/lowenergynotificationhub.cpp
diff --git a/src/bluetooth/android/androidbroadcastreceiver.cpp b/src/bluetooth/android/androidbroadcastreceiver.cpp
index c64e61ff..da551be2 100644
--- a/src/bluetooth/android/androidbroadcastreceiver.cpp
+++ b/src/bluetooth/android/androidbroadcastreceiver.cpp
@@ -1,49 +1,13 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Lauri Laanmets (Proekspert AS) <lauri.laanmets@eesti.ee>
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 Lauri Laanmets (Proekspert AS) <lauri.laanmets@eesti.ee>
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <android/log.h>
+#include <android/jni_android_p.h>
#include "android/androidbroadcastreceiver_p.h"
#include <QtCore/QLoggingCategory>
-#include <QtCore/private/qjnihelpers_p.h>
+#include <QtCore/qnativeinterface.h>
#include <QtGui/QGuiApplication>
-#include <QtAndroidExtras/QAndroidJniEnvironment>
QT_BEGIN_NAMESPACE
@@ -54,14 +18,14 @@ AndroidBroadcastReceiver::AndroidBroadcastReceiver(QObject* parent)
: QObject(parent), valid(false)
{
// get Qt Context
- contextObject = QAndroidJniObject(QtAndroidPrivate::context());
+ contextObject = QJniObject(QNativeInterface::QAndroidApplication::context());
- broadcastReceiverObject = QAndroidJniObject("org/qtproject/qt5/android/bluetooth/QtBluetoothBroadcastReceiver");
+ broadcastReceiverObject = QJniObject::construct<QtJniTypes::QtBtBroadcastReceiver>();
if (!broadcastReceiverObject.isValid())
return;
broadcastReceiverObject.setField<jlong>("qtObject", reinterpret_cast<long>(this));
- intentFilterObject = QAndroidJniObject("android/content/IntentFilter");
+ intentFilterObject = QJniObject::construct<QtJniTypes::IntentFilter>();
if (!intentFilterObject.isValid())
return;
@@ -85,18 +49,17 @@ void AndroidBroadcastReceiver::unregisterReceiver()
broadcastReceiverObject.callMethod<void>("unregisterReceiver");
}
-void AndroidBroadcastReceiver::addAction(const QAndroidJniObject &action)
+void AndroidBroadcastReceiver::addAction(const QJniObject &action)
{
if (!valid || !action.isValid())
return;
- intentFilterObject.callMethod<void>("addAction", "(Ljava/lang/String;)V", action.object<jstring>());
+ intentFilterObject.callMethod<void>("addAction", action.object<jstring>());
- contextObject.callObjectMethod(
+ contextObject.callMethod<QtJniTypes::Intent>(
"registerReceiver",
- "(Landroid/content/BroadcastReceiver;Landroid/content/IntentFilter;)Landroid/content/Intent;",
- broadcastReceiverObject.object<jobject>(),
- intentFilterObject.object<jobject>());
+ broadcastReceiverObject.object<QtJniTypes::BroadcastReceiver>(),
+ intentFilterObject.object<QtJniTypes::IntentFilter>());
}
QT_END_NAMESPACE
diff --git a/src/bluetooth/android/androidbroadcastreceiver_p.h b/src/bluetooth/android/androidbroadcastreceiver_p.h
index 49aa63c0..08ecd5fc 100644
--- a/src/bluetooth/android/androidbroadcastreceiver_p.h
+++ b/src/bluetooth/android/androidbroadcastreceiver_p.h
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Lauri Laanmets (Proekspert AS) <lauri.laanmets@eesti.ee>
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 Lauri Laanmets (Proekspert AS) <lauri.laanmets@eesti.ee>
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef JNIBROADCASTRECEIVER_H
#define JNIBROADCASTRECEIVER_H
@@ -54,12 +18,15 @@
#include <jni.h>
#include <QtCore/QObject>
+#include <QtCore/private/qglobal_p.h>
#include <android/log.h>
-#include <QtAndroidExtras/QAndroidJniObject>
+#include <android/jni_android_p.h>
+#include <QtCore/QJniObject>
QT_BEGIN_NAMESPACE
-void QtBroadcastReceiver_jniOnReceive(JNIEnv *, jobject, jlong, jobject, jobject);
+void QtBroadcastReceiver_jniOnReceive(JNIEnv *, jobject, jlong,
+ QtJniTypes::Context, QtJniTypes::Intent);
class AndroidBroadcastReceiver: public QObject
{
@@ -68,20 +35,22 @@ public:
AndroidBroadcastReceiver(QObject* parent = nullptr);
virtual ~AndroidBroadcastReceiver();
- void addAction(const QAndroidJniObject &filter);
+ void addAction(const QJniObject &filter);
bool isValid() const;
void unregisterReceiver();
protected:
- friend void QtBroadcastReceiver_jniOnReceive(JNIEnv *, jobject, jlong, jobject, jobject);
+ friend void QtBroadcastReceiver_jniOnReceive(JNIEnv *, jobject, jlong, QtJniTypes::Context,
+ QtJniTypes::Intent);
virtual void onReceive(JNIEnv *env, jobject context, jobject intent) = 0;
- friend void QtBluetoothLE_leScanResult(JNIEnv *, jobject, jlong, jobject, jint, jbyteArray);
+ friend void QtBluetoothLE_leScanResult(JNIEnv *, jobject, jlong, QtJniTypes::BluetoothDevice,
+ jint, jbyteArray);
virtual void onReceiveLeScan(JNIEnv *env, jobject jBluetoothDevice, jint rssi, jbyteArray scanRecord) = 0;
- QAndroidJniObject contextObject;
- QAndroidJniObject intentFilterObject;
- QAndroidJniObject broadcastReceiverObject;
+ QJniObject contextObject;
+ QJniObject intentFilterObject;
+ QJniObject broadcastReceiverObject;
bool valid;
};
diff --git a/src/bluetooth/android/androidutils.cpp b/src/bluetooth/android/androidutils.cpp
new file mode 100644
index 00000000..22160ab7
--- /dev/null
+++ b/src/bluetooth/android/androidutils.cpp
@@ -0,0 +1,50 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "androidutils_p.h"
+#include "jni_android_p.h"
+
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qloggingcategory.h>
+#include <QtCore/private/qandroidextras_p.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_LOGGING_CATEGORY(QT_BT_ANDROID)
+
+bool ensureAndroidPermission(QBluetoothPermission::CommunicationModes modes)
+{
+ QBluetoothPermission permission;
+ permission.setCommunicationModes(modes);
+
+ if (qApp->checkPermission(permission) == Qt::PermissionStatus::Granted)
+ return true;
+
+ qCWarning(QT_BT_ANDROID) << "Permissions not authorized for a specified mode:" << modes;
+ return false;
+}
+
+QJniObject getDefaultBluetoothAdapter()
+{
+ QJniObject service = QJniObject::getStaticField<QtJniTypes::AndroidContext, jstring>(
+ "BLUETOOTH_SERVICE");
+ QJniObject context = QNativeInterface::QAndroidApplication::context();
+ QJniObject manager =
+ context.callMethod<jobject>("getSystemService", service.object<jstring>());
+ QJniObject adapter;
+ if (manager.isValid())
+ adapter = manager.callMethod<QtJniTypes::BluetoothAdapter>("getAdapter");
+
+ // ### Qt 7 check if the below double-get of the adapter can be removed.
+ // It is a workaround for QTBUG-57489, fixed in 2016. According to the bug it occurred on
+ // a certain device running Android 6.0.1 (Qt 6 supports Android 6.0 as the minimum).
+ // For completeness: the original workaround was for the deprecated getDefaultAdapter()
+ // method, and it is thus unclear if this is needed even in Qt 6 anymore. In addition the
+ // impacted device is updateable to Android 8 which may also have fixed the issue.
+ if (!adapter.isValid())
+ adapter = manager.callMethod<QtJniTypes::BluetoothAdapter>("getAdapter");
+
+ return adapter;
+}
+
+QT_END_NAMESPACE
diff --git a/src/bluetooth/android/androidutils_p.h b/src/bluetooth/android/androidutils_p.h
new file mode 100644
index 00000000..5c83fc61
--- /dev/null
+++ b/src/bluetooth/android/androidutils_p.h
@@ -0,0 +1,32 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QANDROIDBLUETOOTHUTILS_H
+#define QANDROIDBLUETOOTHUTILS_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <qglobal.h>
+#include <QtCore/QJniObject>
+#include <QtCore/QPermission>
+
+QT_BEGIN_NAMESPACE
+
+// Checks if a permssion is already authorized or not
+bool ensureAndroidPermission(QBluetoothPermission::CommunicationModes modes);
+
+// Returns the default bluetooth adapter, or an invalid object if not available
+QJniObject getDefaultBluetoothAdapter();
+
+QT_END_NAMESPACE
+
+#endif // QANDROIDBLUETOOTHUTILS_H
diff --git a/src/bluetooth/android/devicediscoverybroadcastreceiver.cpp b/src/bluetooth/android/devicediscoverybroadcastreceiver.cpp
index 19023efe..34f1082d 100644
--- a/src/bluetooth/android/devicediscoverybroadcastreceiver.cpp
+++ b/src/bluetooth/android/devicediscoverybroadcastreceiver.cpp
@@ -1,51 +1,15 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Lauri Laanmets (Proekspert AS) <lauri.laanmets@eesti.ee>
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 Lauri Laanmets (Proekspert AS) <lauri.laanmets@eesti.ee>
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "android/devicediscoverybroadcastreceiver_p.h"
+#include <QCoreApplication>
#include <QtCore/QtEndian>
#include <QtCore/QLoggingCategory>
#include <QtBluetooth/QBluetoothAddress>
#include <QtBluetooth/QBluetoothDeviceInfo>
#include <QtBluetooth/QBluetoothUuid>
#include "android/jni_android_p.h"
-#include <QtCore/private/qjnihelpers_p.h>
#include <QtCore/QHash>
#include <QtCore/qbitarray.h>
#include <algorithm>
@@ -64,7 +28,7 @@ Q_GLOBAL_STATIC(JCachedMinorTypes, cachedMinorTypes)
static QBitArray initializeMinorCaches()
{
- const int numberOfMajorDeviceClasses = 11; // count QBluetoothDeviceInfo::MajorDeviceClass values
+ const qsizetype numberOfMajorDeviceClasses = 11; // count QBluetoothDeviceInfo::MajorDeviceClass values
// switch below used to ensure that we notice additions to MajorDeviceClass enum
const QBluetoothDeviceInfo::MajorDeviceClass classes = QBluetoothDeviceInfo::ComputerDevice;
@@ -92,23 +56,24 @@ Q_GLOBAL_STATIC_WITH_ARGS(QBitArray, initializedCacheTracker, (initializeMinorCa
// class names
-static const char * const javaBluetoothDeviceClassName = "android/bluetooth/BluetoothDevice";
-static const char * const javaBluetoothClassDeviceMajorClassName = "android/bluetooth/BluetoothClass$Device$Major";
-static const char * const javaBluetoothClassDeviceClassName = "android/bluetooth/BluetoothClass$Device";
+static const char javaBluetoothDeviceClassName[] = "android/bluetooth/BluetoothDevice";
+static const char javaBluetoothClassDeviceMajorClassName[] = "android/bluetooth/BluetoothClass$Device$Major";
+static const char javaBluetoothClassDeviceClassName[] = "android/bluetooth/BluetoothClass$Device";
// field names device type (LE vs classic)
-static const char * const javaDeviceTypeClassic = "DEVICE_TYPE_CLASSIC";
-static const char * const javaDeviceTypeDual = "DEVICE_TYPE_DUAL";
-static const char * const javaDeviceTypeLE = "DEVICE_TYPE_LE";
-static const char * const javaDeviceTypeUnknown = "DEVICE_TYPE_UNKNOWN";
+static const char javaDeviceTypeClassic[] = "DEVICE_TYPE_CLASSIC";
+static const char javaDeviceTypeDual[] = "DEVICE_TYPE_DUAL";
+static const char javaDeviceTypeLE[] = "DEVICE_TYPE_LE";
+static const char javaDeviceTypeUnknown[] = "DEVICE_TYPE_UNKNOWN";
struct MajorClassJavaToQtMapping
{
- char const * javaFieldName;
- QBluetoothDeviceInfo::MajorDeviceClass qtMajor;
+ const char javaFieldName[14];
+ QBluetoothDeviceInfo::MajorDeviceClass qtMajor : 16;
};
+static_assert(sizeof(MajorClassJavaToQtMapping) == 16);
-static const MajorClassJavaToQtMapping majorMappings[] = {
+static constexpr MajorClassJavaToQtMapping majorMappings[] = {
{ "AUDIO_VIDEO", QBluetoothDeviceInfo::AudioVideoDevice },
{ "COMPUTER", QBluetoothDeviceInfo::ComputerDevice },
{ "HEALTH", QBluetoothDeviceInfo::HealthDevice },
@@ -120,12 +85,11 @@ static const MajorClassJavaToQtMapping majorMappings[] = {
{ "TOY", QBluetoothDeviceInfo::ToyDevice },
{ "UNCATEGORIZED", QBluetoothDeviceInfo::UncategorizedDevice },
{ "WEARABLE", QBluetoothDeviceInfo::WearableDevice },
- { nullptr, QBluetoothDeviceInfo::UncategorizedDevice } //end of list
};
// QBluetoothDeviceInfo::MajorDeviceClass value plus 1 matches index
// UncategorizedDevice shifts to index 0
-static const int minorIndexSizes[] = {
+static constexpr quint8 minorIndexSizes[] = {
64, // QBluetoothDevice::UncategorizedDevice
61, // QBluetoothDevice::MiscellaneousDevice
18, // QBluetoothDevice::ComputerDevice
@@ -237,7 +201,10 @@ static const MinorClassJavaToQtMapping minorMappings[] = {
{ nullptr, 0 }, // index 64 & separator
};
-/* Advertising Data Type (AD type) for LE scan records, as defined in Bluetooth CSS v6. */
+/*
+ Advertising Data Type (AD type) for LE scan records, as defined in
+ https://www.bluetooth.com/specifications/assigned-numbers/generic-access-profile
+*/
enum ADType {
ADType16BitUuidIncomplete = 0x02,
ADType16BitUuidComplete = 0x03,
@@ -245,50 +212,40 @@ enum ADType {
ADType32BitUuidComplete = 0x05,
ADType128BitUuidIncomplete = 0x06,
ADType128BitUuidComplete = 0x07,
+ ADTypeShortenedLocalName = 0x08,
+ ADTypeCompleteLocalName = 0x09,
+ ADTypeServiceData16Bit = 0x16,
+ ADTypeServiceData32Bit = 0x20,
+ ADTypeServiceData128Bit = 0x21,
ADTypeManufacturerSpecificData = 0xff,
// .. more will be added when required
};
-// Endianness conversion for quint128 doesn't (yet) exist in qtendian.h
-template <>
-inline quint128 qbswap<quint128>(const quint128 src)
-{
- quint128 dst;
- for (int i = 0; i < 16; i++)
- dst.data[i] = src.data[15 - i];
- return dst;
-}
-
QBluetoothDeviceInfo::CoreConfigurations qtBtTypeForJavaBtType(jint javaType)
{
const JCachedBtTypes::iterator it = cachedBtTypes()->find(javaType);
if (it == cachedBtTypes()->end()) {
- QAndroidJniEnvironment env;
- if (javaType == QAndroidJniObject::getStaticField<jint>(
+ if (javaType == QJniObject::getStaticField<jint>(
javaBluetoothDeviceClassName, javaDeviceTypeClassic)) {
cachedBtTypes()->insert(javaType,
QBluetoothDeviceInfo::BaseRateCoreConfiguration);
return QBluetoothDeviceInfo::BaseRateCoreConfiguration;
- } else if (javaType == QAndroidJniObject::getStaticField<jint>(
+ } else if (javaType == QJniObject::getStaticField<jint>(
javaBluetoothDeviceClassName, javaDeviceTypeLE)) {
cachedBtTypes()->insert(javaType,
QBluetoothDeviceInfo::LowEnergyCoreConfiguration);
return QBluetoothDeviceInfo::LowEnergyCoreConfiguration;
- } else if (javaType == QAndroidJniObject::getStaticField<jint>(
+ } else if (javaType == QJniObject::getStaticField<jint>(
javaBluetoothDeviceClassName, javaDeviceTypeDual)) {
cachedBtTypes()->insert(javaType,
QBluetoothDeviceInfo::BaseRateAndLowEnergyCoreConfiguration);
return QBluetoothDeviceInfo::BaseRateAndLowEnergyCoreConfiguration;
- } else if (javaType == QAndroidJniObject::getStaticField<jint>(
+ } else if (javaType == QJniObject::getStaticField<jint>(
javaBluetoothDeviceClassName, javaDeviceTypeUnknown)) {
cachedBtTypes()->insert(javaType,
QBluetoothDeviceInfo::UnknownCoreConfiguration);
} else {
- if (env->ExceptionCheck()) {
- env->ExceptionDescribe();
- env->ExceptionClear();
- }
qCWarning(QT_BT_ANDROID) << "Unknown Bluetooth device type value";
}
@@ -300,33 +257,28 @@ QBluetoothDeviceInfo::CoreConfigurations qtBtTypeForJavaBtType(jint javaType)
QBluetoothDeviceInfo::MajorDeviceClass resolveAndroidMajorClass(jint javaType)
{
- QAndroidJniEnvironment env;
-
const JCachedMajorTypes::iterator it = cachedMajorTypes()->find(javaType);
if (it == cachedMajorTypes()->end()) {
- QAndroidJniEnvironment env;
+ QJniEnvironment env;
// precache all major device class fields
- int i = 0;
jint fieldValue;
QBluetoothDeviceInfo::MajorDeviceClass result = QBluetoothDeviceInfo::UncategorizedDevice;
- while (majorMappings[i].javaFieldName != nullptr) {
- fieldValue = QAndroidJniObject::getStaticField<jint>(
- javaBluetoothClassDeviceMajorClassName, majorMappings[i].javaFieldName);
- if (env->ExceptionCheck()) {
+ auto clazz = env->FindClass(javaBluetoothClassDeviceMajorClassName);
+ for (const auto &majorMapping : majorMappings) {
+ auto fieldId = env->GetStaticFieldID(clazz, majorMapping.javaFieldName, "I");
+ if (!env->ExceptionCheck())
+ fieldValue = env->GetStaticIntField(clazz, fieldId);
+ if (env.checkAndClearExceptions()) {
qCWarning(QT_BT_ANDROID) << "Unknown BluetoothClass.Device.Major field" << javaType;
- env->ExceptionDescribe();
- env->ExceptionClear();
// add fallback value because field not readable
cachedMajorTypes()->insert(javaType, QBluetoothDeviceInfo::UncategorizedDevice);
} else {
- cachedMajorTypes()->insert(fieldValue, majorMappings[i].qtMajor);
+ cachedMajorTypes()->insert(fieldValue, majorMapping.qtMajor);
}
if (fieldValue == javaType)
- result = majorMappings[i].qtMajor;
-
- i++;
+ result = majorMapping.qtMajor;
}
return result;
@@ -357,16 +309,11 @@ void triggerCachingOfMinorsForMajor(QBluetoothDeviceInfo::MajorDeviceClass major
{
//qCDebug(QT_BT_ANDROID) << "Caching minor values for major" << major;
int mappingIndex = mappingIndexForMajor(major);
- int sizeIndex = minorIndexSizes[mappingIndex];
- QAndroidJniEnvironment env;
+ quint8 sizeIndex = minorIndexSizes[mappingIndex];
while (minorMappings[sizeIndex].javaFieldName != nullptr) {
- jint fieldValue = QAndroidJniObject::getStaticField<jint>(
+ jint fieldValue = QJniObject::getStaticField<jint>(
javaBluetoothClassDeviceClassName, minorMappings[sizeIndex].javaFieldName);
- if (env->ExceptionCheck()) { // field lookup failed? skip it
- env->ExceptionDescribe();
- env->ExceptionClear();
- }
Q_ASSERT(fieldValue >= 0);
cachedMinorTypes()->insert(fieldValue, minorMappings[sizeIndex].qtMinor);
@@ -400,49 +347,50 @@ quint8 resolveAndroidMinorClass(QBluetoothDeviceInfo::MajorDeviceClass major, ji
DeviceDiscoveryBroadcastReceiver::DeviceDiscoveryBroadcastReceiver(QObject* parent): AndroidBroadcastReceiver(parent)
{
- addAction(valueForStaticField(JavaNames::BluetoothDevice, JavaNames::ActionFound));
- addAction(valueForStaticField(JavaNames::BluetoothAdapter, JavaNames::ActionDiscoveryStarted));
- addAction(valueForStaticField(JavaNames::BluetoothAdapter, JavaNames::ActionDiscoveryFinished));
+ addAction(QJniObject::fromString(
+ valueForStaticField<QtJniTypes::BluetoothDevice, JavaNames::ActionFound>()));
+ addAction(QJniObject::fromString(
+ valueForStaticField<QtJniTypes::BluetoothAdapter, JavaNames::ActionDiscoveryStarted>()));
+ addAction(QJniObject::fromString(
+ valueForStaticField<QtJniTypes::BluetoothAdapter, JavaNames::ActionDiscoveryFinished>()));
}
// Runs in Java thread
void DeviceDiscoveryBroadcastReceiver::onReceive(JNIEnv *env, jobject context, jobject intent)
{
- Q_UNUSED(context);
- Q_UNUSED(env);
+ Q_UNUSED(context)
+ Q_UNUSED(env)
- QAndroidJniObject intentObject(intent);
- const QString action = intentObject.callObjectMethod("getAction", "()Ljava/lang/String;").toString();
+ QJniObject intentObject(intent);
+ const QString action = intentObject.callMethod<jstring>("getAction").toString();
qCDebug(QT_BT_ANDROID) << "DeviceDiscoveryBroadcastReceiver::onReceive() - event:" << action;
- if (action == valueForStaticField(JavaNames::BluetoothAdapter,
- JavaNames::ActionDiscoveryFinished).toString()) {
+ if (action == valueForStaticField<QtJniTypes::BluetoothAdapter,
+ JavaNames::ActionDiscoveryFinished>()) {
emit finished();
- } else if (action == valueForStaticField(JavaNames::BluetoothAdapter,
- JavaNames::ActionDiscoveryStarted).toString()) {
-
- } else if (action == valueForStaticField(JavaNames::BluetoothDevice,
- JavaNames::ActionFound).toString()) {
+ } else if (action == valueForStaticField<QtJniTypes::BluetoothAdapter,
+ JavaNames::ActionDiscoveryStarted>()) {
+ emit discoveryStarted();
+ } else if (action == valueForStaticField<QtJniTypes::BluetoothDevice,
+ JavaNames::ActionFound>()) {
//get BluetoothDevice
- QAndroidJniObject keyExtra = valueForStaticField(JavaNames::BluetoothDevice,
- JavaNames::ExtraDevice);
- const QAndroidJniObject bluetoothDevice =
- intentObject.callObjectMethod("getParcelableExtra",
- "(Ljava/lang/String;)Landroid/os/Parcelable;",
- keyExtra.object<jstring>());
+ QJniObject keyExtra =
+ QJniObject::fromString(valueForStaticField<QtJniTypes::BluetoothDevice,
+ JavaNames::ExtraDevice>());
+ const QJniObject bluetoothDevice =
+ intentObject.callMethod<QtJniTypes::Parcelable>("getParcelableExtra",
+ keyExtra.object<jstring>());
if (!bluetoothDevice.isValid())
return;
- keyExtra = valueForStaticField(JavaNames::BluetoothDevice,
- JavaNames::ExtraRssi);
+ keyExtra = QJniObject::fromString(valueForStaticField<QtJniTypes::BluetoothDevice,
+ JavaNames::ExtraRssi>());
int rssi = intentObject.callMethod<jshort>("getShortExtra",
- "(Ljava/lang/String;S)S",
- keyExtra.object<jstring>(),
- 0);
+ keyExtra.object<jstring>(), jshort(0));
- const QBluetoothDeviceInfo info = retrieveDeviceInfo(env, bluetoothDevice, rssi);
+ const QBluetoothDeviceInfo info = retrieveDeviceInfo(bluetoothDevice, rssi);
if (info.isValid())
emit deviceDiscovered(info, false);
}
@@ -450,24 +398,25 @@ void DeviceDiscoveryBroadcastReceiver::onReceive(JNIEnv *env, jobject context, j
// Runs in Java thread
void DeviceDiscoveryBroadcastReceiver::onReceiveLeScan(
- JNIEnv *env, jobject jBluetoothDevice, jint rssi, jbyteArray scanRecord)
+ JNIEnv */*env*/, jobject jBluetoothDevice, jint rssi, jbyteArray scanRecord)
{
- const QAndroidJniObject bluetoothDevice(jBluetoothDevice);
+ const QJniObject bluetoothDevice(jBluetoothDevice);
if (!bluetoothDevice.isValid())
return;
- const QBluetoothDeviceInfo info = retrieveDeviceInfo(env, bluetoothDevice, rssi, scanRecord);
+ const QBluetoothDeviceInfo info = retrieveDeviceInfo(bluetoothDevice, rssi, scanRecord);
if (info.isValid())
emit deviceDiscovered(info, true);
}
-QBluetoothDeviceInfo DeviceDiscoveryBroadcastReceiver::retrieveDeviceInfo(JNIEnv *env, const QAndroidJniObject &bluetoothDevice, int rssi, jbyteArray scanRecord)
+QBluetoothDeviceInfo DeviceDiscoveryBroadcastReceiver::retrieveDeviceInfo(const QJniObject &bluetoothDevice, int rssi, jbyteArray scanRecord)
{
- const QString deviceName = bluetoothDevice.callObjectMethod<jstring>("getName").toString();
- const QBluetoothAddress deviceAddress(bluetoothDevice.callObjectMethod<jstring>("getAddress").toString());
+ const QString deviceName = bluetoothDevice.callMethod<jstring>("getName").toString();
+ const QBluetoothAddress deviceAddress(
+ bluetoothDevice.callMethod<jstring>("getAddress").toString());
+ const QJniObject bluetoothClass =
+ bluetoothDevice.callMethod<QtJniTypes::BluetoothClass>("getBluetoothClass");
- const QAndroidJniObject bluetoothClass = bluetoothDevice.callObjectMethod("getBluetoothClass",
- "()Landroid/bluetooth/BluetoothClass;");
if (!bluetoothClass.isValid())
return QBluetoothDeviceInfo();
@@ -482,24 +431,22 @@ QBluetoothDeviceInfo DeviceDiscoveryBroadcastReceiver::retrieveDeviceInfo(JNIEnv
// minor device class is 6 bits from index 2 - 7
classType |= ((quint32(minorDeviceType) & 0x3f) << 2);
- static QList<quint32> services;
- if (services.count() == 0)
- services << QBluetoothDeviceInfo::PositioningService
- << QBluetoothDeviceInfo::NetworkingService
- << QBluetoothDeviceInfo::RenderingService
- << QBluetoothDeviceInfo::CapturingService
- << QBluetoothDeviceInfo::ObjectTransferService
- << QBluetoothDeviceInfo::AudioService
- << QBluetoothDeviceInfo::TelephonyService
- << QBluetoothDeviceInfo::InformationService;
+ static constexpr quint32 services[] = {
+ QBluetoothDeviceInfo::PositioningService,
+ QBluetoothDeviceInfo::NetworkingService,
+ QBluetoothDeviceInfo::RenderingService,
+ QBluetoothDeviceInfo::CapturingService,
+ QBluetoothDeviceInfo::ObjectTransferService,
+ QBluetoothDeviceInfo::AudioService,
+ QBluetoothDeviceInfo::TelephonyService,
+ QBluetoothDeviceInfo::InformationService,
+ };
// Matching BluetoothClass.Service values
quint32 serviceResult = 0;
- quint32 current = 0;
- for (int i = 0; i < services.count(); i++) {
- current = services.at(i);
+ for (quint32 current : services) {
int androidId = (current << 16); // Android values shift by 2 bytes compared to Qt enums
- if (bluetoothClass.callMethod<jboolean>("hasService", "(I)Z", androidId))
+ if (bluetoothClass.callMethod<jboolean>("hasService", androidId))
serviceResult |= current;
}
@@ -508,18 +455,19 @@ QBluetoothDeviceInfo DeviceDiscoveryBroadcastReceiver::retrieveDeviceInfo(JNIEnv
QBluetoothDeviceInfo info(deviceAddress, deviceName, classType);
info.setRssi(rssi);
-
+ QJniEnvironment env;
if (scanRecord != nullptr) {
// Parse scan record
jboolean isCopy;
jbyte *elems = env->GetByteArrayElements(scanRecord, &isCopy);
const char *scanRecordBuffer = reinterpret_cast<const char *>(elems);
- const int scanRecordLength = env->GetArrayLength(scanRecord);
+ const jsize scanRecordLength = env->GetArrayLength(scanRecord);
- QVector<QBluetoothUuid> serviceUuids;
- int i = 0;
+ QList<QBluetoothUuid> serviceUuids;
+ jsize i = 0;
// Spec 4.2, Vol 3, Part C, Chapter 11
+ QString localName;
while (i < scanRecordLength) {
// sizeof(EIR Data) = sizeof(Length) + sizeof(EIR data Type) + sizeof(EIR Data)
// Length = sizeof(EIR data Type) + sizeof(EIR Data)
@@ -528,7 +476,7 @@ QBluetoothDeviceInfo DeviceDiscoveryBroadcastReceiver::retrieveDeviceInfo(JNIEnv
if (nBytes == 0)
break;
- if ((i + nBytes) >= scanRecordLength)
+ if (i >= scanRecordLength - nBytes)
break;
const int adType = scanRecordBuffer[i+1];
@@ -547,7 +495,26 @@ QBluetoothDeviceInfo DeviceDiscoveryBroadcastReceiver::retrieveDeviceInfo(JNIEnv
case ADType128BitUuidIncomplete:
case ADType128BitUuidComplete:
foundService =
- QBluetoothUuid(qToBigEndian<quint128>(qFromLittleEndian<quint128>(dataPtr)));
+ QBluetoothUuid(qToBigEndian<QUuid::Id128Bytes>(qFromLittleEndian<QUuid::Id128Bytes>(dataPtr)));
+ break;
+ case ADTypeServiceData16Bit:
+ if (nBytes >= 3) {
+ info.setServiceData(QBluetoothUuid(qFromLittleEndian<quint16>(dataPtr)),
+ QByteArray(dataPtr + 2, nBytes - 3));
+ }
+ break;
+ case ADTypeServiceData32Bit:
+ if (nBytes >= 5) {
+ info.setServiceData(QBluetoothUuid(qFromLittleEndian<quint32>(dataPtr)),
+ QByteArray(dataPtr + 4, nBytes - 5));
+ }
+ break;
+ case ADTypeServiceData128Bit:
+ if (nBytes >= 17) {
+ info.setServiceData(QBluetoothUuid(qToBigEndian<QUuid::Id128Bytes>(
+ qFromLittleEndian<QUuid::Id128Bytes>(dataPtr))),
+ QByteArray(dataPtr + 16, nBytes - 17));
+ }
break;
case ADTypeManufacturerSpecificData:
if (nBytes >= 3) {
@@ -555,9 +522,19 @@ QBluetoothDeviceInfo DeviceDiscoveryBroadcastReceiver::retrieveDeviceInfo(JNIEnv
QByteArray(dataPtr + 2, nBytes - 3));
}
break;
+ // According to Spec 5.0, Vol 3, Part C, Chapter 12.1
+ // the device's local name is utf8 encoded
+ case ADTypeShortenedLocalName:
+ if (localName.isEmpty())
+ localName = QString::fromUtf8(dataPtr, nBytes - 1);
+ break;
+ case ADTypeCompleteLocalName:
+ localName = QString::fromUtf8(dataPtr, nBytes - 1);
+ break;
default:
+ // qWarning() << "Unhandled AD Type" << Qt::hex << adType;
// no other types supported yet and therefore skipped
- // https://www.bluetooth.org/en-us/specification/assigned-numbers/generic-access-profile
+ // https://www.bluetooth.com/specifications/assigned-numbers/generic-access-profile
break;
}
@@ -567,24 +544,21 @@ QBluetoothDeviceInfo DeviceDiscoveryBroadcastReceiver::retrieveDeviceInfo(JNIEnv
serviceUuids.append(foundService);
}
+ if (info.name().isEmpty())
+ info.setName(localName);
+
info.setServiceUuids(serviceUuids);
env->ReleaseByteArrayElements(scanRecord, elems, JNI_ABORT);
}
- if (QtAndroidPrivate::androidSdkVersion() >= 18) {
- jint javaBtType = bluetoothDevice.callMethod<jint>("getType");
-
- if (env->ExceptionCheck()) {
- env->ExceptionDescribe();
- env->ExceptionClear();
- } else {
- info.setCoreConfigurations(qtBtTypeForJavaBtType(javaBtType));
- }
+ auto methodId = env.findMethod(bluetoothDevice.objectClass(), "getType", "()I");
+ jint javaBtType = env->CallIntMethod(bluetoothDevice.object(), methodId);
+ if (!env.checkAndClearExceptions()) {
+ info.setCoreConfigurations(qtBtTypeForJavaBtType(javaBtType));
}
return info;
}
QT_END_NAMESPACE
-
diff --git a/src/bluetooth/android/devicediscoverybroadcastreceiver_p.h b/src/bluetooth/android/devicediscoverybroadcastreceiver_p.h
index 0302971d..ba677acc 100644
--- a/src/bluetooth/android/devicediscoverybroadcastreceiver_p.h
+++ b/src/bluetooth/android/devicediscoverybroadcastreceiver_p.h
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Lauri Laanmets (Proekspert AS) <lauri.laanmets@eesti.ee>
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 Lauri Laanmets (Proekspert AS) <lauri.laanmets@eesti.ee>
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef DEVICEDISCOVERYBROADCASTRECEIVER_H
#define DEVICEDISCOVERYBROADCASTRECEIVER_H
@@ -70,10 +34,11 @@ public:
signals:
void deviceDiscovered(const QBluetoothDeviceInfo &info, bool isLeScanResult);
+ void discoveryStarted();
void finished();
private:
- QBluetoothDeviceInfo retrieveDeviceInfo(JNIEnv *env, const QAndroidJniObject& bluetoothDevice,
+ QBluetoothDeviceInfo retrieveDeviceInfo(const QJniObject& bluetoothDevice,
int rssi, jbyteArray scanRecord = nullptr);
};
diff --git a/src/bluetooth/android/inputstreamthread.cpp b/src/bluetooth/android/inputstreamthread.cpp
index 1cc353a3..14fab8b9 100644
--- a/src/bluetooth/android/inputstreamthread.cpp
+++ b/src/bluetooth/android/inputstreamthread.cpp
@@ -1,47 +1,12 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Lauri Laanmets (Proekspert AS) <lauri.laanmets@eesti.ee>
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 Lauri Laanmets (Proekspert AS) <lauri.laanmets@eesti.ee>
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtCore/QLoggingCategory>
-#include <QtAndroidExtras/QAndroidJniEnvironment>
+#include <QtCore/QJniEnvironment>
#include "android/inputstreamthread_p.h"
+#include "android/jni_android_p.h"
#include "qbluetoothsocket_android_p.h"
QT_BEGIN_NAMESPACE
@@ -57,12 +22,12 @@ bool InputStreamThread::run()
{
QMutexLocker lock(&m_mutex);
- javaInputStreamThread = QAndroidJniObject("org/qtproject/qt5/android/bluetooth/QtBluetoothInputStreamThread");
+ javaInputStreamThread = QJniObject::construct<QtJniTypes::QtBtInputStreamThread>();
if (!javaInputStreamThread.isValid() || !m_socket_p->inputStream.isValid())
return false;
- javaInputStreamThread.callMethod<void>("setInputStream", "(Ljava/io/InputStream;)V",
- m_socket_p->inputStream.object<jobject>());
+ javaInputStreamThread.callMethod<void>("setInputStream",
+ m_socket_p->inputStream.object<QtJniTypes::InputStream>());
javaInputStreamThread.setField<jlong>("qtObject", reinterpret_cast<long>(this));
javaInputStreamThread.setField<jboolean>("logEnabled", QT_BT_ANDROID().isDebugEnabled());
@@ -74,21 +39,21 @@ bool InputStreamThread::run()
qint64 InputStreamThread::bytesAvailable() const
{
QMutexLocker locker(&m_mutex);
- return m_socket_p->buffer.size();
+ return m_socket_p->rxBuffer.size();
}
bool InputStreamThread::canReadLine() const
{
QMutexLocker locker(&m_mutex);
- return m_socket_p->buffer.canReadLine();
+ return m_socket_p->rxBuffer.canReadLine();
}
qint64 InputStreamThread::readData(char *data, qint64 maxSize)
{
QMutexLocker locker(&m_mutex);
- if (!m_socket_p->buffer.isEmpty())
- return m_socket_p->buffer.read(data, maxSize);
+ if (!m_socket_p->rxBuffer.isEmpty())
+ return m_socket_p->rxBuffer.read(data, maxSize);
return 0;
}
@@ -99,18 +64,18 @@ void InputStreamThread::javaThreadErrorOccurred(int errorCode)
QMutexLocker lock(&m_mutex);
if (!expectClosure)
- emit error(errorCode);
+ emit errorOccurred(errorCode);
else
- emit error(-1); //magic error, -1 means error was expected due to expected close()
+ emit errorOccurred(-1); // magic error, -1 means error was expected due to expected close()
}
//inside the java thread
void InputStreamThread::javaReadyRead(jbyteArray buffer, int bufferLength)
{
- QAndroidJniEnvironment env;
+ QJniEnvironment env;
QMutexLocker lock(&m_mutex);
- char *writePtr = m_socket_p->buffer.reserve(bufferLength);
+ char *writePtr = m_socket_p->rxBuffer.reserve(bufferLength);
env->GetByteArrayRegion(buffer, 0, bufferLength, reinterpret_cast<jbyte*>(writePtr));
emit dataAvailable();
}
diff --git a/src/bluetooth/android/inputstreamthread_p.h b/src/bluetooth/android/inputstreamthread_p.h
index 060b2acf..7aa8e695 100644
--- a/src/bluetooth/android/inputstreamthread_p.h
+++ b/src/bluetooth/android/inputstreamthread_p.h
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Lauri Laanmets (Proekspert AS) <lauri.laanmets@eesti.ee>
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 Lauri Laanmets (Proekspert AS) <lauri.laanmets@eesti.ee>
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef INPUTSTREAMTHREAD_H
#define INPUTSTREAMTHREAD_H
@@ -54,7 +18,8 @@
#include <QtCore/QObject>
#include <QtCore/QMutex>
-#include <QtAndroidExtras/QAndroidJniObject>
+#include <QtCore/QJniObject>
+#include <QtCore/private/qglobal_p.h>
#include <jni.h>
QT_BEGIN_NAMESPACE
@@ -79,11 +44,11 @@ public:
signals:
void dataAvailable();
- void error(int errorCode);
+ void errorOccurred(int errorCode);
private:
QBluetoothSocketPrivateAndroid *m_socket_p;
- QAndroidJniObject javaInputStreamThread;
+ QJniObject javaInputStreamThread;
mutable QMutex m_mutex;
bool expectClosure;
};
diff --git a/src/bluetooth/android/jni_android.cpp b/src/bluetooth/android/jni_android.cpp
index 0688c869..90641b6c 100644
--- a/src/bluetooth/android/jni_android.cpp
+++ b/src/bluetooth/android/jni_android.cpp
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Lauri Laanmets (Proekspert AS) <lauri.laanmets@eesti.ee>
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 Lauri Laanmets (Proekspert AS) <lauri.laanmets@eesti.ee>
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <jni.h>
#include <android/log.h>
@@ -48,261 +12,182 @@
#include "android/inputstreamthread_p.h"
#include "android/lowenergynotificationhub_p.h"
+QT_BEGIN_NAMESPACE
+
Q_DECLARE_LOGGING_CATEGORY(QT_BT_ANDROID)
-typedef QHash<QByteArray, QAndroidJniObject> JCachedStringFields;
+typedef QHash<QByteArray, QString> JCachedStringFields;
Q_GLOBAL_STATIC(JCachedStringFields, cachedStringFields)
-
-//Java class names
-static const char * const javaBluetoothAdapterClassName = "android/bluetooth/BluetoothAdapter";
-static const char * const javaBluetoothDeviceClassName = "android/bluetooth/BluetoothDevice" ;
-
-//Java field names
-static const char * const javaActionAclConnected = "ACTION_ACL_CONNECTED";
-static const char * const javaActionAclDisconnected = "ACTION_ACL_DISCONNECTED";
-static const char * const javaActionBondStateChanged = "ACTION_BOND_STATE_CHANGED";
-static const char * const javaActionDiscoveryStarted = "ACTION_DISCOVERY_STARTED";
-static const char * const javaActionDiscoveryFinished = "ACTION_DISCOVERY_FINISHED";
-static const char * const javaActionFound = "ACTION_FOUND";
-static const char * const javaActionPairingRequest = "ACTION_PAIRING_REQUEST";
-static const char * const javaActionScanModeChanged = "ACTION_SCAN_MODE_CHANGED";
-static const char * const javaActionUuid = "ACTION_UUID";
-static const char * const javaExtraBondState = "EXTRA_BOND_STATE";
-static const char * const javaExtraDevice = "EXTRA_DEVICE";
-static const char * const javaExtraPairingKey = "EXTRA_PAIRING_KEY";
-static const char * const javaExtraPairingVariant = "EXTRA_PAIRING_VARIANT";
-static const char * const javaExtraRssi = "EXTRA_RSSI";
-static const char * const javaExtraScanMode = "EXTRA_SCAN_MODE";
-static const char * const javaExtraUuid = "EXTRA_UUID";
+Q_GLOBAL_STATIC(QMutex, stringCacheMutex);
/*
* This function operates on the assumption that each
* field is of type java/lang/String.
*/
-QAndroidJniObject valueForStaticField(JavaNames javaName, JavaNames javaFieldName)
+QString valueFromStaticFieldCache(const char *key, const char *className, const char *fieldName)
{
- //construct key
- //the switch statements are used to reduce the number of duplicated strings
- //in the library
-
- const char* className;
- switch (javaName) {
- case JavaNames::BluetoothAdapter:
- className = javaBluetoothAdapterClassName; break;
- case JavaNames::BluetoothDevice:
- className = javaBluetoothDeviceClassName; break;
- default:
- qCWarning(QT_BT_ANDROID) << "Unknown java class name passed to valueForStaticField():" << javaName;
- return QAndroidJniObject();
- }
-
- const char *fieldName;
- switch (javaFieldName) {
- case JavaNames::ActionAclConnected:
- fieldName = javaActionAclConnected; break;
- case JavaNames::ActionAclDisconnected:
- fieldName = javaActionAclDisconnected; break;
- case JavaNames::ActionBondStateChanged:
- fieldName = javaActionBondStateChanged; break;
- case JavaNames::ActionDiscoveryStarted:
- fieldName = javaActionDiscoveryStarted; break;
- case JavaNames::ActionDiscoveryFinished:
- fieldName = javaActionDiscoveryFinished; break;
- case JavaNames::ActionFound:
- fieldName = javaActionFound; break;
- case JavaNames::ActionPairingRequest:
- fieldName = javaActionPairingRequest; break;
- case JavaNames::ActionScanModeChanged:
- fieldName = javaActionScanModeChanged; break;
- case JavaNames::ActionUuid:
- fieldName = javaActionUuid; break;
- case JavaNames::ExtraBondState:
- fieldName = javaExtraBondState; break;
- case JavaNames::ExtraDevice:
- fieldName = javaExtraDevice; break;
- case JavaNames::ExtraPairingKey:
- fieldName = javaExtraPairingKey; break;
- case JavaNames::ExtraPairingVariant:
- fieldName = javaExtraPairingVariant; break;
- case JavaNames::ExtraRssi:
- fieldName = javaExtraRssi; break;
- case JavaNames::ExtraScanMode:
- fieldName = javaExtraScanMode; break;
- case JavaNames::ExtraUuid:
- fieldName = javaExtraUuid; break;
- default:
- qCWarning(QT_BT_ANDROID) << "Unknown java field name passed to valueForStaticField():" << javaFieldName;
- return QAndroidJniObject();
- }
-
- int offset_class = qstrlen(className);
- int offset_field = qstrlen(fieldName);
- QByteArray key(offset_class + offset_field, Qt::Uninitialized);
- memcpy(key.data(), className, offset_class);
- memcpy(key.data()+offset_class, fieldName, offset_field);
-
+ QMutexLocker lock(stringCacheMutex());
JCachedStringFields::iterator it = cachedStringFields()->find(key);
if (it == cachedStringFields()->end()) {
- QAndroidJniEnvironment env;
- QAndroidJniObject fieldValue = QAndroidJniObject::getStaticObjectField(
+ QJniEnvironment env;
+ QJniObject fieldValue = QJniObject::getStaticObjectField(
className, fieldName, "Ljava/lang/String;");
- if (env->ExceptionCheck()) {
- env->ExceptionDescribe();
- env->ExceptionClear();
- cachedStringFields()->insert(key, QAndroidJniObject());
- return QAndroidJniObject();
+ if (!fieldValue.isValid()) {
+ cachedStringFields()->insert(key, {});
+ return {};
}
-
- cachedStringFields()->insert(key, fieldValue);
- return fieldValue;
+ const QString string = fieldValue.toString();
+ cachedStringFields()->insert(key, string);
+ return string;
} else {
return it.value();
}
}
void QtBroadcastReceiver_jniOnReceive(JNIEnv *env, jobject /*javaObject*/,
- jlong qtObject, jobject context, jobject intent)
+ jlong qtObject, QtJniTypes::Context context,
+ QtJniTypes::Intent intent)
{
- reinterpret_cast<AndroidBroadcastReceiver*>(qtObject)->onReceive(env, context, intent);
+ reinterpret_cast<AndroidBroadcastReceiver*>(qtObject)->onReceive(env, context.object(), intent.object());
}
+Q_DECLARE_JNI_NATIVE_METHOD(QtBroadcastReceiver_jniOnReceive, jniOnReceive)
static void QtBluetoothSocketServer_errorOccurred(JNIEnv */*env*/, jobject /*javaObject*/,
jlong qtObject, jint errorCode)
{
reinterpret_cast<ServerAcceptanceThread*>(qtObject)->javaThreadErrorOccurred(errorCode);
}
+Q_DECLARE_JNI_NATIVE_METHOD(QtBluetoothSocketServer_errorOccurred, errorOccurred)
static void QtBluetoothSocketServer_newSocket(JNIEnv */*env*/, jobject /*javaObject*/,
- jlong qtObject, jobject socket)
+ jlong qtObject, QtJniTypes::BluetoothSocket socket)
{
- reinterpret_cast<ServerAcceptanceThread*>(qtObject)->javaNewSocket(socket);
+ reinterpret_cast<ServerAcceptanceThread*>(qtObject)->javaNewSocket(socket.object());
}
+Q_DECLARE_JNI_NATIVE_METHOD(QtBluetoothSocketServer_newSocket, newSocket)
static void QtBluetoothInputStreamThread_errorOccurred(JNIEnv */*env*/, jobject /*javaObject*/,
jlong qtObject, jint errorCode)
{
reinterpret_cast<InputStreamThread*>(qtObject)->javaThreadErrorOccurred(errorCode);
}
+Q_DECLARE_JNI_NATIVE_METHOD(QtBluetoothInputStreamThread_errorOccurred, errorOccurred)
static void QtBluetoothInputStreamThread_readyData(JNIEnv */*env*/, jobject /*javaObject*/,
jlong qtObject, jbyteArray buffer, jint bufferLength)
{
reinterpret_cast<InputStreamThread*>(qtObject)->javaReadyRead(buffer, bufferLength);
}
+Q_DECLARE_JNI_NATIVE_METHOD(QtBluetoothInputStreamThread_readyData, readyData)
-void QtBluetoothLE_leScanResult(JNIEnv *env, jobject, jlong qtObject, jobject bluetoothDevice,
- jint rssi, jbyteArray scanRecord)
+void QtBluetoothLE_leScanResult(JNIEnv *env, jobject, jlong qtObject,
+ QtJniTypes::BluetoothDevice bluetoothDevice, jint rssi,
+ jbyteArray scanRecord)
{
if (Q_UNLIKELY(qtObject == 0))
return;
reinterpret_cast<AndroidBroadcastReceiver*>(qtObject)->onReceiveLeScan(
- env, bluetoothDevice, rssi,
+ env, bluetoothDevice.object(), rssi,
scanRecord);
}
-
-
-static JNINativeMethod methods[] = {
- {"jniOnReceive", "(JLandroid/content/Context;Landroid/content/Intent;)V",
- (void *) QtBroadcastReceiver_jniOnReceive},
-};
-
-static JNINativeMethod methods_le[] = {
- {"leScanResult", "(JLandroid/bluetooth/BluetoothDevice;I[B)V",
- (void *) QtBluetoothLE_leScanResult},
- {"leConnectionStateChange", "(JII)V",
- (void *) LowEnergyNotificationHub::lowEnergy_connectionChange},
- {"leServicesDiscovered", "(JILjava/lang/String;)V",
- (void *) LowEnergyNotificationHub::lowEnergy_servicesDiscovered},
- {"leServiceDetailDiscoveryFinished", "(JLjava/lang/String;II)V",
- (void *) LowEnergyNotificationHub::lowEnergy_serviceDetailsDiscovered},
- {"leCharacteristicRead", "(JLjava/lang/String;ILjava/lang/String;I[B)V",
- (void *) LowEnergyNotificationHub::lowEnergy_characteristicRead},
- {"leDescriptorRead", "(JLjava/lang/String;Ljava/lang/String;ILjava/lang/String;[B)V",
- (void *) LowEnergyNotificationHub::lowEnergy_descriptorRead},
- {"leCharacteristicWritten", "(JI[BI)V",
- (void *) LowEnergyNotificationHub::lowEnergy_characteristicWritten},
- {"leDescriptorWritten", "(JI[BI)V",
- (void *) LowEnergyNotificationHub::lowEnergy_descriptorWritten},
- {"leCharacteristicChanged", "(JI[B)V",
- (void *) LowEnergyNotificationHub::lowEnergy_characteristicChanged},
- {"leServiceError", "(JII)V",
- (void *) LowEnergyNotificationHub::lowEnergy_serviceError},
-};
-
-static JNINativeMethod methods_leServer[] = {
- {"leServerConnectionStateChange", "(JII)V",
- (void *) LowEnergyNotificationHub::lowEnergy_connectionChange},
- {"leServerAdvertisementError", "(JI)V",
- (void *) LowEnergyNotificationHub::lowEnergy_advertisementError},
- {"leServerCharacteristicChanged", "(JLandroid/bluetooth/BluetoothGattCharacteristic;[B)V",
- (void *) LowEnergyNotificationHub::lowEnergy_serverCharacteristicChanged},
- {"leServerDescriptorWritten", "(JLandroid/bluetooth/BluetoothGattDescriptor;[B)V",
- (void *) LowEnergyNotificationHub::lowEnergy_serverDescriptorWritten},
-};
-
-static JNINativeMethod methods_server[] = {
- {"errorOccurred", "(JI)V",
- (void *) QtBluetoothSocketServer_errorOccurred},
- {"newSocket", "(JLandroid/bluetooth/BluetoothSocket;)V",
- (void *) QtBluetoothSocketServer_newSocket},
-};
-
-static JNINativeMethod methods_inputStream[] = {
- {"errorOccurred", "(JI)V",
- (void *) QtBluetoothInputStreamThread_errorOccurred},
- {"readyData", "(J[BI)V",
- (void *) QtBluetoothInputStreamThread_readyData},
-};
+Q_DECLARE_JNI_NATIVE_METHOD(QtBluetoothLE_leScanResult, leScanResult)
static const char logTag[] = "QtBluetooth";
static const char classErrorMsg[] = "Can't find class \"%s\"";
-#define FIND_AND_CHECK_CLASS(CLASS_NAME) \
-clazz = env->FindClass(CLASS_NAME); \
-if (!clazz) { \
- __android_log_print(ANDROID_LOG_FATAL, logTag, classErrorMsg, CLASS_NAME); \
- return JNI_FALSE; \
-}
+#define FIND_AND_CHECK_CLASS(CLASS_NAME) \
+clazz = env.findClass<CLASS_NAME>(); \
+if (!clazz) { \
+ __android_log_print(ANDROID_LOG_FATAL, logTag, classErrorMsg, \
+ QtJniTypes::Traits<CLASS_NAME>::className().data()); \
+ return JNI_FALSE; \
+} \
+
+#define LEHUB_SCOPED_METHOD(Method) Q_JNI_NATIVE_SCOPED_METHOD(Method, LowEnergyNotificationHub)
-static bool registerNatives(JNIEnv *env)
+static bool registerNatives()
{
jclass clazz;
- FIND_AND_CHECK_CLASS("org/qtproject/qt5/android/bluetooth/QtBluetoothBroadcastReceiver");
-
- if (env->RegisterNatives(clazz, methods, sizeof(methods) / sizeof(methods[0])) < 0) {
- __android_log_print(ANDROID_LOG_FATAL, logTag, "RegisterNatives for BroadcastReceiver failed");
+ QJniEnvironment env;
+
+ FIND_AND_CHECK_CLASS(QtJniTypes::QtBtBroadcastReceiver);
+ if (!env.registerNativeMethods(clazz,
+ {
+ Q_JNI_NATIVE_METHOD(QtBroadcastReceiver_jniOnReceive)
+ }))
+ {
+ __android_log_print(ANDROID_LOG_FATAL, logTag,
+ "registerNativeMethods for BroadcastReceiver failed");
return false;
}
- FIND_AND_CHECK_CLASS("org/qtproject/qt5/android/bluetooth/QtBluetoothLE");
- if (env->RegisterNatives(clazz, methods_le, sizeof(methods_le) / sizeof(methods_le[0])) < 0) {
- __android_log_print(ANDROID_LOG_FATAL, logTag, "RegisterNatives for QBLuetoothLE failed");
+ FIND_AND_CHECK_CLASS(QtJniTypes::QtBtLECentral);
+ if (!env.registerNativeMethods(clazz,
+ {
+ Q_JNI_NATIVE_METHOD(QtBluetoothLE_leScanResult),
+ LEHUB_SCOPED_METHOD(lowEnergy_connectionChange),
+ LEHUB_SCOPED_METHOD(lowEnergy_mtuChanged),
+ LEHUB_SCOPED_METHOD(lowEnergy_servicesDiscovered),
+ LEHUB_SCOPED_METHOD(lowEnergy_serviceDetailsDiscovered),
+ LEHUB_SCOPED_METHOD(lowEnergy_characteristicRead),
+ LEHUB_SCOPED_METHOD(lowEnergy_descriptorRead),
+ LEHUB_SCOPED_METHOD(lowEnergy_characteristicWritten),
+ LEHUB_SCOPED_METHOD(lowEnergy_descriptorWritten),
+ LEHUB_SCOPED_METHOD(lowEnergy_characteristicChanged),
+ LEHUB_SCOPED_METHOD(lowEnergy_serviceError),
+ LEHUB_SCOPED_METHOD(lowEnergy_remoteRssiRead)
+ }))
+ {
+ __android_log_print(ANDROID_LOG_FATAL, logTag,
+ "registerNativeMethods for QBLuetoothLE failed");
return false;
}
- FIND_AND_CHECK_CLASS("org/qtproject/qt5/android/bluetooth/QtBluetoothLEServer");
- if (env->RegisterNatives(clazz, methods_leServer, sizeof(methods_leServer) / sizeof(methods_leServer[0])) < 0) {
- __android_log_print(ANDROID_LOG_FATAL, logTag, "RegisterNatives for QBLuetoothLEServer failed");
+ FIND_AND_CHECK_CLASS(QtJniTypes::QtBtLEServer);
+ if (!env.registerNativeMethods(clazz,
+ {
+ LEHUB_SCOPED_METHOD(lowEnergy_connectionChange),
+ LEHUB_SCOPED_METHOD(lowEnergy_mtuChanged),
+ LEHUB_SCOPED_METHOD(lowEnergy_advertisementError),
+ LEHUB_SCOPED_METHOD(lowEnergy_serverCharacteristicChanged),
+ LEHUB_SCOPED_METHOD(lowEnergy_serverDescriptorWritten)
+ }))
+ {
+ __android_log_print(ANDROID_LOG_FATAL, logTag,
+ "registerNativeMethods for QBLuetoothLEServer failed");
return false;
}
- FIND_AND_CHECK_CLASS("org/qtproject/qt5/android/bluetooth/QtBluetoothSocketServer");
- if (env->RegisterNatives(clazz, methods_server, sizeof(methods_server) / sizeof(methods_server[0])) < 0) {
- __android_log_print(ANDROID_LOG_FATAL, logTag, "RegisterNatives for SocketServer failed");
+ FIND_AND_CHECK_CLASS(QtJniTypes::QtBtSocketServer);
+ if (!env.registerNativeMethods(clazz,
+ {
+ Q_JNI_NATIVE_METHOD(QtBluetoothSocketServer_errorOccurred),
+ Q_JNI_NATIVE_METHOD(QtBluetoothSocketServer_newSocket)
+ }))
+ {
+ __android_log_print(ANDROID_LOG_FATAL, logTag,
+ "registerNativeMethods for SocketServer failed");
return false;
}
- FIND_AND_CHECK_CLASS("org/qtproject/qt5/android/bluetooth/QtBluetoothInputStreamThread");
- if (env->RegisterNatives(clazz, methods_inputStream,
- sizeof(methods_inputStream) / sizeof(methods_inputStream[0])) < 0) {
- __android_log_print(ANDROID_LOG_FATAL, logTag, "RegisterNatives for InputStreamThread failed");
+ FIND_AND_CHECK_CLASS(QtJniTypes::QtBtInputStreamThread);
+ if (!env.registerNativeMethods(clazz,
+ {
+ Q_JNI_NATIVE_METHOD(QtBluetoothInputStreamThread_errorOccurred),
+ Q_JNI_NATIVE_METHOD(QtBluetoothInputStreamThread_readyData)
+ }))
+ {
+ __android_log_print(ANDROID_LOG_FATAL, logTag,
+ "registerNativeMethods for InputStreamThread failed");
return false;
}
return true;
}
+QT_END_NAMESPACE
+
Q_BLUETOOTH_EXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* /*reserved*/)
{
static bool initialized = false;
@@ -318,13 +203,12 @@ Q_BLUETOOTH_EXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* /*reserved*/)
UnionJNIEnvToVoid uenv;
uenv.venv = 0;
- if (vm->GetEnv(&uenv.venv, JNI_VERSION_1_4) != JNI_OK) {
+ if (vm->GetEnv(&uenv.venv, JNI_VERSION_1_6) != JNI_OK) {
__android_log_print(ANDROID_LOG_FATAL, logTag, "GetEnv failed");
return -1;
}
- JNIEnv *env = uenv.nativeEnvironment;
- if (!registerNatives(env)) {
+ if (!registerNatives()) {
__android_log_print(ANDROID_LOG_FATAL, logTag, "registerNatives failed");
return -1;
}
@@ -332,5 +216,5 @@ Q_BLUETOOTH_EXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* /*reserved*/)
if (QT_BT_ANDROID().isDebugEnabled())
__android_log_print(ANDROID_LOG_INFO, logTag, "Bluetooth start");
- return JNI_VERSION_1_4;
+ return JNI_VERSION_1_6;
}
diff --git a/src/bluetooth/android/jni_android_p.h b/src/bluetooth/android/jni_android_p.h
index 79aa43c3..b94a847e 100644
--- a/src/bluetooth/android/jni_android_p.h
+++ b/src/bluetooth/android/jni_android_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef JNI_ANDROID_P_H
#define JNI_ANDROID_P_H
@@ -51,11 +15,61 @@
// We mean it.
//
-#include <QtAndroidExtras/QAndroidJniEnvironment>
-#include <QtAndroidExtras/QAndroidJniObject>
+#include "qbluetooth.h"
+#include <QtCore/QJniObject>
+#include <QtCore/private/qglobal_p.h>
+#include <QtCore/qcoreapplication_platform.h>
QT_BEGIN_NAMESPACE
+// CLASS declaration implies also TYPE declaration
+Q_DECLARE_JNI_CLASS(QtBtBroadcastReceiver,
+ "org/qtproject/qt/android/bluetooth/QtBluetoothBroadcastReceiver");
+Q_DECLARE_JNI_CLASS(QtBtGattCharacteristic,
+ "org/qtproject/qt/android/bluetooth/QtBluetoothGattCharacteristic");
+Q_DECLARE_JNI_CLASS(QtBtGattDescriptor,
+ "org/qtproject/qt/android/bluetooth/QtBluetoothGattDescriptor");
+Q_DECLARE_JNI_CLASS(QtBtInputStreamThread,
+ "org/qtproject/qt/android/bluetooth/QtBluetoothInputStreamThread")
+Q_DECLARE_JNI_CLASS(QtBtSocketServer, "org/qtproject/qt/android/bluetooth/QtBluetoothSocketServer")
+Q_DECLARE_JNI_CLASS(QtBtLEServer, "org/qtproject/qt/android/bluetooth/QtBluetoothLEServer")
+Q_DECLARE_JNI_CLASS(QtBtLECentral, "org/qtproject/qt/android/bluetooth/QtBluetoothLE")
+Q_DECLARE_JNI_CLASS(BluetoothAdapter, "android/bluetooth/BluetoothAdapter")
+Q_DECLARE_JNI_CLASS(ParcelUuid, "android/os/ParcelUuid")
+Q_DECLARE_JNI_CLASS(AdvertiseDataBuilder, "android/bluetooth/le/AdvertiseData$Builder")
+Q_DECLARE_JNI_CLASS(AdvertiseSettingsBuilder, "android/bluetooth/le/AdvertiseSettings$Builder")
+Q_DECLARE_JNI_CLASS(BluetoothGattService, "android/bluetooth/BluetoothGattService")
+Q_DECLARE_JNI_CLASS(BluetoothGattDescriptor, "android/bluetooth/BluetoothGattDescriptor")
+Q_DECLARE_JNI_CLASS(BluetoothGattCharacteristic, "android/bluetooth/BluetoothGattCharacteristic")
+Q_DECLARE_JNI_CLASS(BluetoothDevice, "android/bluetooth/BluetoothDevice")
+Q_DECLARE_JNI_CLASS(IntentFilter, "android/content/IntentFilter")
+Q_DECLARE_JNI_CLASS(AndroidContext, "android/content/Context")
+Q_DECLARE_JNI_CLASS(UUID, "java/util/UUID")
+
+Q_DECLARE_JNI_TYPE(ParcelableArray, "[Landroid/os/Parcelable;")
+Q_DECLARE_JNI_TYPE(ParcelUuidArray, "[Landroid/os/ParcelUuid;")
+Q_DECLARE_JNI_TYPE(StringArray, "[Ljava/lang/String;")
+
+Q_DECLARE_JNI_CLASS(BluetoothManager, "android/bluetooth/BluetoothManager")
+Q_DECLARE_JNI_CLASS(AdvertiseData, "android/bluetooth/le/AdvertiseData")
+Q_DECLARE_JNI_CLASS(AdvertiseSettings, "android/bluetooth/le/AdvertiseSettings")
+Q_DECLARE_JNI_CLASS(InputStream, "java/io/InputStream")
+Q_DECLARE_JNI_CLASS(OutputStream, "java/io/OutputStream")
+Q_DECLARE_JNI_CLASS(BluetoothSocket, "android/bluetooth/BluetoothSocket")
+Q_DECLARE_JNI_CLASS(BroadcastReceiver, "android/content/BroadcastReceiver")
+Q_DECLARE_JNI_CLASS(BluetoothClass, "android/bluetooth/BluetoothClass")
+Q_DECLARE_JNI_CLASS(Parcelable, "android/os/Parcelable")
+Q_DECLARE_JNI_CLASS(Intent, "android/content/Intent")
+Q_DECLARE_JNI_CLASS(Bundle, "android/os/Bundle")
+Q_DECLARE_JNI_CLASS(List, "java/util/List")
+
+// QLowEnergyHandle is a quint16, ensure it is interpreted as jint
+template<>
+constexpr auto QtJniTypes::Traits<QLowEnergyHandle>::signature()
+{
+ return QtJniTypes::Traits<jint>::signature();
+}
+
enum JavaNames {
BluetoothAdapter = 0,
BluetoothDevice,
@@ -65,7 +79,6 @@ enum JavaNames {
ActionDiscoveryStarted,
ActionDiscoveryFinished,
ActionFound,
- ActionPairingRequest,
ActionScanModeChanged,
ActionUuid,
ExtraBondState,
@@ -77,7 +90,50 @@ enum JavaNames {
ExtraUuid
};
-QAndroidJniObject valueForStaticField(JavaNames javaName, JavaNames javaFieldName);
+QString valueFromStaticFieldCache(const char *key, const char *className, const char *fieldName);
+
+
+template<typename Klass, JavaNames Field>
+QString valueForStaticField()
+{
+ constexpr auto className = QtJniTypes::Traits<Klass>::className();
+ constexpr auto fieldName = []() -> auto {
+ if constexpr (Field == JavaNames::ActionAclConnected)
+ return QtJniTypes::CTString("ACTION_ACL_CONNECTED");
+ else if constexpr (Field == ActionAclDisconnected)
+ return QtJniTypes::CTString("ACTION_ACL_DISCONNECTED");
+ else if constexpr (Field == ActionBondStateChanged)
+ return QtJniTypes::CTString("ACTION_BOND_STATE_CHANGED");
+ else if constexpr (Field == ActionDiscoveryStarted)
+ return QtJniTypes::CTString("ACTION_DISCOVERY_STARTED");
+ else if constexpr (Field == ActionDiscoveryFinished)
+ return QtJniTypes::CTString("ACTION_DISCOVERY_FINISHED");
+ else if constexpr (Field == ActionFound)
+ return QtJniTypes::CTString("ACTION_FOUND");
+ else if constexpr (Field == ActionScanModeChanged)
+ return QtJniTypes::CTString("ACTION_SCAN_MODE_CHANGED");
+ else if constexpr (Field == ActionUuid)
+ return QtJniTypes::CTString("ACTION_UUID");
+ else if constexpr (Field == ExtraBondState)
+ return QtJniTypes::CTString("EXTRA_BOND_STATE");
+ else if constexpr (Field == ExtraDevice)
+ return QtJniTypes::CTString("EXTRA_DEVICE");
+ else if constexpr (Field == ExtraPairingKey)
+ return QtJniTypes::CTString("EXTRA_PAIRING_KEY");
+ else if constexpr (Field == ExtraPairingVariant)
+ return QtJniTypes::CTString("EXTRA_PAIRING_VARIANT");
+ else if constexpr (Field == ExtraRssi)
+ return QtJniTypes::CTString("EXTRA_RSSI");
+ else if constexpr (Field == ExtraScanMode)
+ return QtJniTypes::CTString("EXTRA_SCAN_MODE");
+ else if constexpr (Field == ExtraUuid)
+ return QtJniTypes::CTString("EXTRA_UUID");
+ else
+ static_assert(QtPrivate::value_dependent_false<Field>());
+ }();
+
+ return valueFromStaticFieldCache(className + fieldName, className.data(), fieldName.data());
+}
QT_END_NAMESPACE
diff --git a/src/bluetooth/android/localdevicebroadcastreceiver.cpp b/src/bluetooth/android/localdevicebroadcastreceiver.cpp
index 78aecc12..b1b78377 100644
--- a/src/bluetooth/android/localdevicebroadcastreceiver.cpp
+++ b/src/bluetooth/android/localdevicebroadcastreceiver.cpp
@@ -1,44 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtCore/QLoggingCategory>
-#include <QtCore/private/qjnihelpers_p.h>
#include <QtCore/qrandom.h>
#include "localdevicebroadcastreceiver_p.h"
#include "android/jni_android_p.h"
@@ -53,36 +16,27 @@ const char *bondModes[] = {"BOND_NONE", "BOND_BONDING", "BOND_BONDED"};
LocalDeviceBroadcastReceiver::LocalDeviceBroadcastReceiver(QObject *parent) :
AndroidBroadcastReceiver(parent), previousScanMode(0)
{
- addAction(valueForStaticField(JavaNames::BluetoothDevice, JavaNames::ActionBondStateChanged));
- addAction(valueForStaticField(JavaNames::BluetoothAdapter, JavaNames::ActionScanModeChanged));
- addAction(valueForStaticField(JavaNames::BluetoothDevice, JavaNames::ActionAclConnected));
- addAction(valueForStaticField(JavaNames::BluetoothDevice, JavaNames::ActionAclDisconnected));
- if (QtAndroidPrivate::androidSdkVersion() >= 15)
- addAction(valueForStaticField(JavaNames::BluetoothDevice, JavaNames::ActionPairingRequest)); //API 15
+ addAction(QJniObject::fromString(
+ valueForStaticField<QtJniTypes::BluetoothDevice, JavaNames::ActionBondStateChanged>()));
+ addAction(QJniObject::fromString(
+ valueForStaticField<QtJniTypes::BluetoothAdapter, JavaNames::ActionScanModeChanged>()));
+ addAction(QJniObject::fromString(
+ valueForStaticField<QtJniTypes::BluetoothDevice, JavaNames::ActionAclConnected>()));
+ addAction(QJniObject::fromString(
+ valueForStaticField<QtJniTypes::BluetoothDevice, JavaNames::ActionAclDisconnected>()));
//cache integer values for host & bonding mode
//don't use the java fields directly but refer to them by name
- QAndroidJniEnvironment env;
for (uint i = 0; i < (sizeof(hostModePreset)/sizeof(hostModePreset[0])); i++) {
- hostModePreset[i] = QAndroidJniObject::getStaticField<jint>(
- "android/bluetooth/BluetoothAdapter",
- scanModes[i]);
- if (env->ExceptionCheck()) {
- env->ExceptionDescribe();
- env->ExceptionClear();
- hostModePreset[i] = 0;
- }
+ hostModePreset[i] = QJniObject::getStaticField<jint>(
+ QtJniTypes::Traits<QtJniTypes::BluetoothAdapter>::className(),
+ scanModes[i]);
}
for (uint i = 0; i < (sizeof(bondingModePreset)/sizeof(bondingModePreset[0])); i++) {
- bondingModePreset[i] = QAndroidJniObject::getStaticField<jint>(
- "android/bluetooth/BluetoothDevice",
- bondModes[i]);
- if (env->ExceptionCheck()) {
- env->ExceptionDescribe();
- env->ExceptionClear();
- bondingModePreset[i] = 0;
- }
+ bondingModePreset[i] = QJniObject::getStaticField<jint>(
+ QtJniTypes::Traits<QtJniTypes::BluetoothDevice>::className(),
+ bondModes[i]);
}
}
@@ -91,21 +45,20 @@ void LocalDeviceBroadcastReceiver::onReceive(JNIEnv *env, jobject context, jobje
Q_UNUSED(context);
Q_UNUSED(env);
- QAndroidJniObject intentObject(intent);
- const QString action = intentObject.callObjectMethod("getAction", "()Ljava/lang/String;").toString();
+ QJniObject intentObject(intent);
+ const QString action = intentObject.callMethod<jstring>("getAction").toString();
qCDebug(QT_BT_ANDROID) << QStringLiteral("LocalDeviceBroadcastReceiver::onReceive() - event: %1").arg(action);
- if (action == valueForStaticField(JavaNames::BluetoothAdapter,
- JavaNames::ActionScanModeChanged).toString()) {
+ if (action == valueForStaticField<QtJniTypes::BluetoothAdapter,
+ JavaNames::ActionScanModeChanged>()) {
- const QAndroidJniObject extrasBundle =
- intentObject.callObjectMethod("getExtras","()Landroid/os/Bundle;");
- const QAndroidJniObject keyExtra = valueForStaticField(JavaNames::BluetoothAdapter,
- JavaNames::ExtraScanMode);
+ const QJniObject extrasBundle =
+ intentObject.callMethod<QtJniTypes::Bundle>("getExtras");
+ const QJniObject keyExtra =
+ QJniObject::fromString(valueForStaticField<QtJniTypes::BluetoothAdapter,
+ JavaNames::ExtraScanMode>());
- int extra = extrasBundle.callMethod<jint>("getInt",
- "(Ljava/lang/String;)I",
- keyExtra.object<jstring>());
+ int extra = extrasBundle.callMethod<jint>("getInt", keyExtra.object<jstring>());
if (previousScanMode != extra) {
previousScanMode = extra;
@@ -119,25 +72,24 @@ void LocalDeviceBroadcastReceiver::onReceive(JNIEnv *env, jobject context, jobje
else
qCWarning(QT_BT_ANDROID) << "Unknown Host State";
}
- } else if (action == valueForStaticField(JavaNames::BluetoothDevice,
- JavaNames::ActionBondStateChanged).toString()) {
+ } else if (action == valueForStaticField<QtJniTypes::BluetoothDevice,
+ JavaNames::ActionBondStateChanged>()) {
//get BluetoothDevice
- QAndroidJniObject keyExtra = valueForStaticField(JavaNames::BluetoothDevice,
- JavaNames::ExtraDevice);
- const QAndroidJniObject bluetoothDevice =
- intentObject.callObjectMethod("getParcelableExtra",
- "(Ljava/lang/String;)Landroid/os/Parcelable;",
- keyExtra.object<jstring>());
+ QJniObject keyExtra = QJniObject::fromString(
+ valueForStaticField<QtJniTypes::BluetoothDevice,
+ JavaNames::ExtraDevice>());
+ const QJniObject bluetoothDevice =
+ intentObject.callMethod<QtJniTypes::Parcelable>("getParcelableExtra",
+ keyExtra.object<jstring>());
//get new bond state
- keyExtra = valueForStaticField(JavaNames::BluetoothDevice, JavaNames::ExtraBondState);
- const QAndroidJniObject extrasBundle =
- intentObject.callObjectMethod("getExtras","()Landroid/os/Bundle;");
- int bondState = extrasBundle.callMethod<jint>("getInt",
- "(Ljava/lang/String;)I",
- keyExtra.object<jstring>());
+ keyExtra = QJniObject::fromString(valueForStaticField<QtJniTypes::BluetoothDevice,
+ JavaNames::ExtraBondState>());
+ const QJniObject extrasBundle =
+ intentObject.callMethod<QtJniTypes::Bundle>("getExtras");
+ int bondState = extrasBundle.callMethod<jint>("getInt", keyExtra.object<jstring>());
- QBluetoothAddress address(bluetoothDevice.callObjectMethod<jstring>("getAddress").toString());
+ QBluetoothAddress address(bluetoothDevice.callMethod<jstring>("getAddress").toString());
if (address.isNull())
return;
@@ -150,149 +102,30 @@ void LocalDeviceBroadcastReceiver::onReceive(JNIEnv *env, jobject context, jobje
else
qCWarning(QT_BT_ANDROID) << "Unknown BOND_STATE_CHANGED value:" << bondState;
- } else if (action == valueForStaticField(JavaNames::BluetoothDevice,
- JavaNames::ActionAclConnected).toString() ||
- action == valueForStaticField(JavaNames::BluetoothDevice,
- JavaNames::ActionAclDisconnected).toString()) {
+ } else if (action == valueForStaticField<QtJniTypes::BluetoothDevice,
+ JavaNames::ActionAclConnected>() ||
+ action == valueForStaticField<QtJniTypes::BluetoothDevice,
+ JavaNames::ActionAclDisconnected>()) {
- const QString connectEvent = valueForStaticField(JavaNames::BluetoothDevice,
- JavaNames::ActionAclConnected).toString();
+ const QString connectEvent = valueForStaticField<QtJniTypes::BluetoothDevice,
+ JavaNames::ActionAclConnected>();
const bool isConnectEvent =
action == connectEvent ? true : false;
//get BluetoothDevice
- const QAndroidJniObject keyExtra = valueForStaticField(JavaNames::BluetoothDevice,
- JavaNames::ExtraDevice);
- QAndroidJniObject bluetoothDevice =
- intentObject.callObjectMethod("getParcelableExtra",
- "(Ljava/lang/String;)Landroid/os/Parcelable;",
- keyExtra.object<jstring>());
-
- QBluetoothAddress address(bluetoothDevice.callObjectMethod<jstring>("getAddress").toString());
+ const QJniObject keyExtra =
+ QJniObject::fromString(valueForStaticField<QtJniTypes::BluetoothDevice,
+ JavaNames::ExtraDevice>());
+ QJniObject bluetoothDevice =
+ intentObject.callMethod<QtJniTypes::Parcelable>("getParcelableExtra",
+ keyExtra.object<jstring>());
+
+ QBluetoothAddress address(bluetoothDevice.callMethod<jstring>("getAddress").toString());
if (address.isNull())
return;
emit connectDeviceChanges(address, isConnectEvent);
- } else if (action == valueForStaticField(JavaNames::BluetoothDevice,
- JavaNames::ActionPairingRequest).toString()) {
-
- QAndroidJniObject keyExtra = valueForStaticField(JavaNames::BluetoothDevice,
- JavaNames::ExtraPairingVariant);
- int variant = intentObject.callMethod<jint>("getIntExtra",
- "(Ljava/lang/String;I)I",
- keyExtra.object<jstring>(),
- -1);
-
- int key = -1;
- switch (variant) {
- case -1: //ignore -> no pairing variant set
- return;
- case 0: //BluetoothDevice.PAIRING_VARIANT_PIN
- {
- qCDebug(QT_BT_ANDROID) << "Pairing : PAIRING_VARIANT_PIN -> use Android default handling";
-
- // The section below is disabled because this Android pairing variant
- // requires the user to enter a pin. Since QBluetoothLocalDevice does
- // not have a setPin() equivalent which might be used to return the user's value.
- // For now we ignore this request. If an app ignores such requests,
- // Android shows a "fall-back" pin code entry form.
- /*
- //generate a random key
- const QString pin = QStringLiteral("%1").arg(QRandomGenerator::global()->bounded(1000000),
- 6, 10, QLatin1Char('0'));
- const QAndroidJniObject javaPin = QAndroidJniObject::fromString(pin);
-
- //get BluetoothDevice
- keyExtra = valueForStaticField(JavaNames::BluetoothDevice, JavaNames::ExtraDevice);
- QAndroidJniObject bluetoothDevice =
- intentObject.callObjectMethod("getParcelableExtra",
- "(Ljava/lang/String;)Landroid/os/Parcelable;",
- keyExtra.object<jstring>());
- if (!bluetoothDevice.isValid())
- return;
-
- QAndroidJniObject bytePin = QAndroidJniObject::callStaticObjectMethod("android/bluetooth/BluetoothDevice",
- "convertPinToBytes",
- "(Ljava/lang/String;)[B",
- javaPin.object<jstring>());
- if (!bytePin.isValid()) {
- if (env->ExceptionCheck()) {
- env->ExceptionDescribe();
- env->ExceptionClear();
- }
- return;
- }
-
- jboolean result = bluetoothDevice.callMethod<jboolean>("setPin", "([B)Z", bytePin.object<jbyteArray>());
- if (!result) {
- if (env->ExceptionCheck()) {
- env->ExceptionDescribe();
- env->ExceptionClear();
- }
- return;
- }
-
- const QBluetoothAddress address(bluetoothDevice.callObjectMethod<jstring>("getAddress").toString());
- emit pairingDisplayPinCode(address, pin);*/
- break;
- }
- case 2: //BluetoothDevice.PAIRING_VARIANT_PASSKEY_CONFIRMATION
- {
- qCDebug(QT_BT_ANDROID) << "Pairing : PAIRING_VARIANT_PASSKEY_CONFIRMATION";
- keyExtra = valueForStaticField(JavaNames::BluetoothDevice,
- JavaNames::ExtraPairingKey);
- key = intentObject.callMethod<jint>("getIntExtra",
- "(Ljava/lang/String;I)I",
- keyExtra.object<jstring>(),
- -1);
- if (key == -1)
- return;
-
- keyExtra = valueForStaticField(JavaNames::BluetoothDevice, JavaNames::ExtraDevice);
- QAndroidJniObject bluetoothDevice =
- intentObject.callObjectMethod("getParcelableExtra",
- "(Ljava/lang/String;)Landroid/os/Parcelable;",
- keyExtra.object<jstring>());
-
- if (!bluetoothDevice.isValid())
- return;
-
- //we need to keep a reference around in case the user confirms later on
- pairingDevice = bluetoothDevice;
-
- QBluetoothAddress address(bluetoothDevice.callObjectMethod<jstring>("getAddress").toString());
-
- //User has choice to confirm or not. If no confirmation is happening
- //the OS default pairing dialog can be used or timeout occurs.
- emit pairingDisplayConfirmation(address, QString::number(key));
- break;
- }
- default:
- qCWarning(QT_BT_ANDROID) << "Unknown pairing variant: " << variant;
- return;
- }
- }
-}
-
-bool LocalDeviceBroadcastReceiver::pairingConfirmation(bool accept)
-{
- if (!pairingDevice.isValid())
- return false;
-
- // setPairingConfirmation() is likely to throw SecurityException for BLUETOOTH_PRIVILEGED
- // as this permission is not obtainable for 3rdparties
- // Note: Normally it would not have been added to Qt API but it used to be BLUETOOTH_ADMIN
- QAndroidJniEnvironment env;
- bool success = pairingDevice.callMethod<jboolean>("setPairingConfirmation",
- "(Z)Z", accept);
- if (success) {
- if (env->ExceptionCheck()) {
- env->ExceptionDescribe();
- env->ExceptionClear();
- }
}
- pairingDevice = QAndroidJniObject();
- return success;
}
QT_END_NAMESPACE
diff --git a/src/bluetooth/android/localdevicebroadcastreceiver_p.h b/src/bluetooth/android/localdevicebroadcastreceiver_p.h
index 09e50fb1..9f0f40d4 100644
--- a/src/bluetooth/android/localdevicebroadcastreceiver_p.h
+++ b/src/bluetooth/android/localdevicebroadcastreceiver_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "android/androidbroadcastreceiver_p.h"
#include <QtBluetooth/QBluetoothAddress>
@@ -65,17 +29,15 @@ public:
virtual ~LocalDeviceBroadcastReceiver() {}
virtual void onReceive(JNIEnv *env, jobject context, jobject intent);
virtual void onReceiveLeScan(JNIEnv *, jobject, jint, jbyteArray) {}
- bool pairingConfirmation(bool accept);
signals:
void hostModeStateChanged(QBluetoothLocalDevice::HostMode state);
void pairingStateChanged(const QBluetoothAddress &address, QBluetoothLocalDevice::Pairing pairing);
void connectDeviceChanges(const QBluetoothAddress &address, bool isConnectEvent);
- void pairingDisplayConfirmation(const QBluetoothAddress &address, const QString& pin);
- void pairingDisplayPinCode(const QBluetoothAddress &address, const QString& pin);
+
private:
int previousScanMode;
- QAndroidJniObject pairingDevice;
+ QJniObject pairingDevice;
int bondingModePreset[3];
int hostModePreset[3];
diff --git a/src/bluetooth/android/lowenergynotificationhub.cpp b/src/bluetooth/android/lowenergynotificationhub.cpp
index b37e3e0c..cf79059e 100644
--- a/src/bluetooth/android/lowenergynotificationhub.cpp
+++ b/src/bluetooth/android/lowenergynotificationhub.cpp
@@ -1,48 +1,14 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "lowenergynotificationhub_p.h"
+#include "android/jni_android_p.h"
+#include <QCoreApplication>
#include <QtCore/QHash>
#include <QtCore/QLoggingCategory>
#include <QtCore/QRandomGenerator>
-#include <QtAndroidExtras/QAndroidJniEnvironment>
+#include <QtCore/QJniEnvironment>
QT_BEGIN_NAMESPACE
@@ -57,28 +23,21 @@ LowEnergyNotificationHub::LowEnergyNotificationHub(const QBluetoothAddress &remo
bool isPeripheral, QObject *parent)
: QObject(parent), javaToCtoken(0)
{
- QAndroidJniEnvironment env;
+ QJniEnvironment env;
if (isPeripheral) {
qCDebug(QT_BT_ANDROID) << "Creating Android Peripheral/Server support for BTLE";
- jBluetoothLe = QAndroidJniObject("org/qtproject/qt5/android/bluetooth/QtBluetoothLEServer",
- "(Landroid/content/Context;)V", QtAndroidPrivate::context());
+ jBluetoothLe = QJniObject::construct<QtJniTypes::QtBtLEServer>(
+ QNativeInterface::QAndroidApplication::context());
} else {
qCDebug(QT_BT_ANDROID) << "Creating Android Central/Client support for BTLE";
- const QAndroidJniObject address =
- QAndroidJniObject::fromString(remote.toString());
- jBluetoothLe = QAndroidJniObject("org/qtproject/qt5/android/bluetooth/QtBluetoothLE",
- "(Ljava/lang/String;Landroid/content/Context;)V",
- address.object<jstring>(),
- QtAndroidPrivate::context());
+ const QJniObject address =
+ QJniObject::fromString(remote.toString());
+ jBluetoothLe = QJniObject::construct<QtJniTypes::QtBtLECentral>(
+ address.object<jstring>(), QNativeInterface::QAndroidApplication::context());
}
- if (env->ExceptionCheck() || !jBluetoothLe.isValid()) {
- env->ExceptionDescribe();
- env->ExceptionClear();
- jBluetoothLe = QAndroidJniObject();
- return;
- }
+ if (!jBluetoothLe.isValid()) return;
// register C++ class pointer in Java
lock.lockForWrite();
@@ -118,8 +77,34 @@ void LowEnergyNotificationHub::lowEnergy_connectionChange(JNIEnv *, jobject, jlo
(QLowEnergyController::Error)errorCode));
}
+void LowEnergyNotificationHub::lowEnergy_mtuChanged(
+ JNIEnv *, jobject, jlong qtObject, jint mtu)
+{
+ lock.lockForRead();
+ LowEnergyNotificationHub *hub = hubMap()->value(qtObject);
+ lock.unlock();
+ if (!hub)
+ return;
+
+ QMetaObject::invokeMethod(hub, "mtuChanged", Qt::QueuedConnection, Q_ARG(int, mtu));
+}
+
+void LowEnergyNotificationHub::lowEnergy_remoteRssiRead(JNIEnv *, jobject, jlong qtObject,
+ int rssi, bool success)
+{
+ lock.lockForRead();
+ LowEnergyNotificationHub *hub = hubMap()->value(qtObject);
+ lock.unlock();
+ if (!hub)
+ return;
+
+ QMetaObject::invokeMethod(hub, "remoteRssiRead", Qt::QueuedConnection,
+ Q_ARG(int, rssi), Q_ARG(bool, success));
+}
+
+
void LowEnergyNotificationHub::lowEnergy_servicesDiscovered(
- JNIEnv *, jobject, jlong qtObject, jint errorCode, jobject uuidList)
+ JNIEnv *, jobject, jlong qtObject, jint errorCode, jstring uuidList)
{
lock.lockForRead();
LowEnergyNotificationHub *hub = hubMap()->value(qtObject);
@@ -127,7 +112,7 @@ void LowEnergyNotificationHub::lowEnergy_servicesDiscovered(
if (!hub)
return;
- const QString uuids = QAndroidJniObject(uuidList).toString();
+ const QString uuids = QJniObject(uuidList).toString();
QMetaObject::invokeMethod(hub, "servicesDiscovered", Qt::QueuedConnection,
Q_ARG(QLowEnergyController::Error,
(QLowEnergyController::Error)errorCode),
@@ -135,7 +120,7 @@ void LowEnergyNotificationHub::lowEnergy_servicesDiscovered(
}
void LowEnergyNotificationHub::lowEnergy_serviceDetailsDiscovered(
- JNIEnv *, jobject, jlong qtObject, jobject uuid, jint startHandle,
+ JNIEnv *, jobject, jlong qtObject, jstring uuid, jint startHandle,
jint endHandle)
{
lock.lockForRead();
@@ -144,7 +129,7 @@ void LowEnergyNotificationHub::lowEnergy_serviceDetailsDiscovered(
if (!hub)
return;
- const QString serviceUuid = QAndroidJniObject(uuid).toString();
+ const QString serviceUuid = QJniObject(uuid).toString();
QMetaObject::invokeMethod(hub, "serviceDetailsDiscoveryFinished",
Qt::QueuedConnection,
Q_ARG(QString, serviceUuid),
@@ -153,8 +138,8 @@ void LowEnergyNotificationHub::lowEnergy_serviceDetailsDiscovered(
}
void LowEnergyNotificationHub::lowEnergy_characteristicRead(
- JNIEnv *env, jobject, jlong qtObject, jobject sUuid, jint handle,
- jobject cUuid, jint properties, jbyteArray data)
+ JNIEnv *env, jobject, jlong qtObject, jstring sUuid, jint handle,
+ jstring cUuid, jint properties, jbyteArray data)
{
lock.lockForRead();
LowEnergyNotificationHub *hub = hubMap()->value(qtObject);
@@ -162,11 +147,11 @@ void LowEnergyNotificationHub::lowEnergy_characteristicRead(
if (!hub)
return;
- const QBluetoothUuid serviceUuid(QAndroidJniObject(sUuid).toString());
+ const QBluetoothUuid serviceUuid(QJniObject(sUuid).toString());
if (serviceUuid.isNull())
return;
- const QBluetoothUuid charUuid(QAndroidJniObject(cUuid).toString());
+ const QBluetoothUuid charUuid(QJniObject(cUuid).toString());
if (charUuid.isNull())
return;
@@ -188,8 +173,8 @@ void LowEnergyNotificationHub::lowEnergy_characteristicRead(
}
void LowEnergyNotificationHub::lowEnergy_descriptorRead(
- JNIEnv *env, jobject, jlong qtObject, jobject sUuid, jobject cUuid,
- jint handle, jobject dUuid, jbyteArray data)
+ JNIEnv *env, jobject, jlong qtObject, jstring sUuid, jstring cUuid,
+ jint handle, jstring dUuid, jbyteArray data)
{
lock.lockForRead();
LowEnergyNotificationHub *hub = hubMap()->value(qtObject);
@@ -197,12 +182,12 @@ void LowEnergyNotificationHub::lowEnergy_descriptorRead(
if (!hub)
return;
- const QBluetoothUuid serviceUuid(QAndroidJniObject(sUuid).toString());
+ const QBluetoothUuid serviceUuid(QJniObject(sUuid).toString());
if (serviceUuid.isNull())
return;
- const QBluetoothUuid charUuid(QAndroidJniObject(cUuid).toString());
- const QBluetoothUuid descUuid(QAndroidJniObject(dUuid).toString());
+ const QBluetoothUuid charUuid(QJniObject(cUuid).toString());
+ const QBluetoothUuid descUuid(QJniObject(dUuid).toString());
if (charUuid.isNull() || descUuid.isNull())
return;
@@ -273,7 +258,8 @@ void LowEnergyNotificationHub::lowEnergy_descriptorWritten(
}
void LowEnergyNotificationHub::lowEnergy_serverDescriptorWritten(
- JNIEnv *env, jobject, jlong qtObject, jobject descriptor, jbyteArray newValue)
+ JNIEnv *env, jobject, jlong qtObject, QtJniTypes::BluetoothGattDescriptor descriptor,
+ jbyteArray newValue)
{
lock.lockForRead();
LowEnergyNotificationHub *hub = hubMap()->value(qtObject);
@@ -290,7 +276,7 @@ void LowEnergyNotificationHub::lowEnergy_serverDescriptorWritten(
}
QMetaObject::invokeMethod(hub, "serverDescriptorWritten", Qt::QueuedConnection,
- Q_ARG(QAndroidJniObject, descriptor),
+ Q_ARG(QJniObject, descriptor),
Q_ARG(QByteArray, payload));
}
@@ -316,7 +302,8 @@ void LowEnergyNotificationHub::lowEnergy_characteristicChanged(
}
void LowEnergyNotificationHub::lowEnergy_serverCharacteristicChanged(
- JNIEnv *env, jobject, jlong qtObject, jobject characteristic, jbyteArray newValue)
+ JNIEnv *env, jobject, jlong qtObject,
+ QtJniTypes::BluetoothGattCharacteristic characteristic, jbyteArray newValue)
{
lock.lockForRead();
LowEnergyNotificationHub *hub = hubMap()->value(qtObject);
@@ -333,7 +320,7 @@ void LowEnergyNotificationHub::lowEnergy_serverCharacteristicChanged(
}
QMetaObject::invokeMethod(hub, "serverCharacteristicChanged", Qt::QueuedConnection,
- Q_ARG(QAndroidJniObject, characteristic),
+ Q_ARG(QJniObject, characteristic),
Q_ARG(QByteArray, payload));
}
diff --git a/src/bluetooth/android/lowenergynotificationhub_p.h b/src/bluetooth/android/lowenergynotificationhub_p.h
index 27016bc5..238590a6 100644
--- a/src/bluetooth/android/lowenergynotificationhub_p.h
+++ b/src/bluetooth/android/lowenergynotificationhub_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef LOWENERGYNOTIFICATIONHUB_H
#define LOWENERGYNOTIFICATIONHUB_H
@@ -53,11 +17,12 @@
#include <QtCore/QObject>
#include <QtCore/QReadWriteLock>
-#include <QtCore/private/qjnihelpers_p.h>
-#include <QtAndroidExtras/QAndroidJniObject>
+#include <QtCore/QJniObject>
#include <QtBluetooth/QBluetoothAddress>
#include <QtBluetooth/QLowEnergyController>
#include <QtBluetooth/QLowEnergyService>
+#include <QtCore/private/qglobal_p.h>
+#include "android/jni_android_p.h"
#include <jni.h>
#include <QtBluetooth/QLowEnergyCharacteristic>
@@ -74,36 +39,77 @@ public:
static void lowEnergy_connectionChange(JNIEnv*, jobject, jlong qtObject,
jint errorCode, jint newState);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(lowEnergy_connectionChange,
+ leConnectionStateChange)
+
+ static void lowEnergy_mtuChanged(JNIEnv*, jobject, jlong qtObject, jint mtu);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(lowEnergy_mtuChanged, leMtuChanged)
+
static void lowEnergy_servicesDiscovered(JNIEnv*, jobject, jlong qtObject,
- jint errorCode, jobject uuidList);
+ jint errorCode, jstring uuidList);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(lowEnergy_servicesDiscovered,
+ leServicesDiscovered)
+
static void lowEnergy_serviceDetailsDiscovered(JNIEnv *, jobject,
- jlong qtObject, jobject uuid,
+ jlong qtObject, jstring uuid,
jint startHandle, jint endHandle);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(lowEnergy_serviceDetailsDiscovered,
+ leServiceDetailDiscoveryFinished)
+
static void lowEnergy_characteristicRead(JNIEnv*env, jobject, jlong qtObject,
- jobject serviceUuid,
- jint handle, jobject charUuid,
+ jstring serviceUuid,
+ jint handle, jstring charUuid,
jint properties, jbyteArray data);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(lowEnergy_characteristicRead,
+ leCharacteristicRead)
+
static void lowEnergy_descriptorRead(JNIEnv *env, jobject, jlong qtObject,
- jobject sUuid, jobject cUuid,
- jint handle, jobject dUuid, jbyteArray data);
+ jstring sUuid, jstring cUuid,
+ jint handle, jstring dUuid, jbyteArray data);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(lowEnergy_descriptorRead, leDescriptorRead)
+
static void lowEnergy_characteristicWritten(JNIEnv *, jobject, jlong qtObject,
jint charHandle, jbyteArray data,
jint errorCode);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(lowEnergy_characteristicWritten,
+ leCharacteristicWritten)
+
static void lowEnergy_descriptorWritten(JNIEnv *, jobject, jlong qtObject,
jint descHandle, jbyteArray data,
jint errorCode);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(lowEnergy_descriptorWritten,
+ leDescriptorWritten)
+
static void lowEnergy_serverDescriptorWritten(JNIEnv *, jobject, jlong qtObject,
- jobject descriptor, jbyteArray newValue);
+ QtJniTypes::BluetoothGattDescriptor descriptor,
+ jbyteArray newValue);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(lowEnergy_serverDescriptorWritten,
+ leServerDescriptorWritten)
+
static void lowEnergy_characteristicChanged(JNIEnv *, jobject, jlong qtObject,
jint charHandle, jbyteArray data);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(lowEnergy_characteristicChanged,
+ leCharacteristicChanged)
+
static void lowEnergy_serverCharacteristicChanged(JNIEnv *, jobject, jlong qtObject,
- jobject characteristic, jbyteArray newValue);
+ QtJniTypes::BluetoothGattCharacteristic characteristic,
+ jbyteArray newValue);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(lowEnergy_serverCharacteristicChanged,
+ leServerCharacteristicChanged)
+
static void lowEnergy_serviceError(JNIEnv *, jobject, jlong qtObject,
jint attributeHandle, int errorCode);
- static void lowEnergy_advertisementError(JNIEnv *, jobject, jlong qtObject,
- jint status);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(lowEnergy_serviceError, leServiceError)
+
+ static void lowEnergy_advertisementError(JNIEnv *, jobject, jlong qtObject, jint status);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(lowEnergy_advertisementError,
+ leServerAdvertisementError)
+
+ static void lowEnergy_remoteRssiRead(JNIEnv *, jobject, jlong qtObject, int rssi,
+ bool success);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(lowEnergy_remoteRssiRead, leRemoteRssiRead);
- QAndroidJniObject javaObject()
+ QJniObject javaObject()
{
return jBluetoothLe;
}
@@ -111,6 +117,8 @@ public:
signals:
void connectionUpdated(QLowEnergyController::ControllerState newState,
QLowEnergyController::Error errorCode);
+ void mtuChanged(int mtu);
+ void remoteRssiRead(int rssi, bool success);
void servicesDiscovered(QLowEnergyController::Error errorCode, const QString &uuids);
void serviceDetailsDiscoveryFinished(const QString& serviceUuid,
int startHandle, int endHandle);
@@ -123,17 +131,16 @@ signals:
QLowEnergyService::ServiceError errorCode);
void descriptorWritten(int descHandle, const QByteArray &data,
QLowEnergyService::ServiceError errorCode);
- void serverDescriptorWritten(const QAndroidJniObject &descriptor, const QByteArray &newValue);
+ void serverDescriptorWritten(const QJniObject &descriptor, const QByteArray &newValue);
void characteristicChanged(int charHandle, const QByteArray &data);
- void serverCharacteristicChanged(const QAndroidJniObject &characteristic, const QByteArray &newValue);
+ void serverCharacteristicChanged(const QJniObject &characteristic, const QByteArray &newValue);
void serviceError(int attributeHandle, QLowEnergyService::ServiceError errorCode);
void advertisementError(int status);
-public slots:
private:
static QReadWriteLock lock;
- QAndroidJniObject jBluetoothLe;
+ QJniObject jBluetoothLe;
long javaToCtoken;
};
diff --git a/src/bluetooth/android/serveracceptancethread.cpp b/src/bluetooth/android/serveracceptancethread.cpp
index 0354d0c5..55f0f4db 100644
--- a/src/bluetooth/android/serveracceptancethread.cpp
+++ b/src/bluetooth/android/serveracceptancethread.cpp
@@ -1,46 +1,13 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtCore/QLoggingCategory>
-#include <QtAndroidExtras/QAndroidJniEnvironment>
+#include <QtCore/QJniEnvironment>
#include "android/serveracceptancethread_p.h"
+#include "android/jni_android_p.h"
+
+QT_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(QT_BT_ANDROID)
@@ -70,7 +37,7 @@ void ServerAcceptanceThread::setServiceDetails(const QBluetoothUuid &uuid,
bool ServerAcceptanceThread::hasPendingConnections() const
{
QMutexLocker lock(&m_mutex);
- return (pendingSockets.count() > 0);
+ return !pendingSockets.isEmpty();
}
/*
@@ -79,11 +46,11 @@ bool ServerAcceptanceThread::hasPendingConnections() const
* connections. Pending connections are only terminated upon
* thread restart or destruction.
*/
-QAndroidJniObject ServerAcceptanceThread::nextPendingConnection()
+QJniObject ServerAcceptanceThread::nextPendingConnection()
{
QMutexLocker lock(&m_mutex);
if (pendingSockets.isEmpty())
- return QAndroidJniObject();
+ return QJniObject();
else
return pendingSockets.takeFirst();
}
@@ -108,21 +75,20 @@ void ServerAcceptanceThread::run()
shutdownPendingConnections();
}
- javaThread = QAndroidJniObject("org/qtproject/qt5/android/bluetooth/QtBluetoothSocketServer");
+ javaThread = QJniObject::construct<QtJniTypes::QtBtSocketServer>(
+ QNativeInterface::QAndroidApplication::context());
if (!javaThread.isValid())
return;
javaThread.setField<jlong>("qtObject", reinterpret_cast<long>(this));
javaThread.setField<jboolean>("logEnabled", QT_BT_ANDROID().isDebugEnabled());
- QString tempUuid = m_uuid.toString();
- tempUuid.chop(1); //remove trailing '}'
- tempUuid.remove(0,1); //remove first '{'
+ QString tempUuid = m_uuid.toString(QUuid::WithoutBraces);
- QAndroidJniObject uuidString = QAndroidJniObject::fromString(tempUuid);
- QAndroidJniObject serviceNameString = QAndroidJniObject::fromString(m_serviceName);
- bool isSecure = !(secFlags == QBluetooth::NoSecurity);
- javaThread.callMethod<void>("setServiceDetails", "(Ljava/lang/String;Ljava/lang/String;Z)V",
+ QJniObject uuidString = QJniObject::fromString(tempUuid);
+ QJniObject serviceNameString = QJniObject::fromString(m_serviceName);
+ bool isSecure = !(secFlags == QBluetooth::SecurityFlags(QBluetooth::Security::NoSecurity));
+ javaThread.callMethod<void>("setServiceDetails",
uuidString.object<jstring>(),
serviceNameString.object<jstring>(),
isSecure);
@@ -149,7 +115,7 @@ bool ServerAcceptanceThread::isRunning() const
void ServerAcceptanceThread::javaThreadErrorOccurred(int errorCode)
{
qCDebug(QT_BT_ANDROID) << "JavaThread error:" << errorCode;
- emit error(QBluetoothServer::InputOutputError);
+ emit errorOccurred(QBluetoothServer::InputOutputError);
}
//Runs inside the Java thread
@@ -157,23 +123,17 @@ void ServerAcceptanceThread::javaNewSocket(jobject s)
{
QMutexLocker lock(&m_mutex);
- QAndroidJniObject socket(s);
+ QJniObject socket(s);
if (!socket.isValid())
return;
- if (pendingSockets.count() < maxPendingConnections) {
+ if (pendingSockets.size() < maxPendingConnections) {
qCDebug(QT_BT_ANDROID) << "New incoming java socket detected";
pendingSockets.append(socket);
emit newConnection();
} else {
- QAndroidJniEnvironment env;
qCWarning(QT_BT_ANDROID) << "Refusing connection due to limited pending socket queue";
socket.callMethod<void>("close");
- if (env->ExceptionCheck()) {
- qCWarning(QT_BT_ANDROID) << "Error during refusal of new socket";
- env->ExceptionDescribe();
- env->ExceptionClear();
- }
}
}
@@ -185,7 +145,9 @@ bool ServerAcceptanceThread::validSetup() const
void ServerAcceptanceThread::shutdownPendingConnections()
{
while (!pendingSockets.isEmpty()) {
- QAndroidJniObject socket = pendingSockets.takeFirst();
+ QJniObject socket = pendingSockets.takeFirst();
socket.callMethod<void>("close");
}
}
+
+QT_END_NAMESPACE
diff --git a/src/bluetooth/android/serveracceptancethread_p.h b/src/bluetooth/android/serveracceptancethread_p.h
index c7c68314..bbdd7fc0 100644
--- a/src/bluetooth/android/serveracceptancethread_p.h
+++ b/src/bluetooth/android/serveracceptancethread_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef SERVERACCEPTANCETHREAD_H
#define SERVERACCEPTANCETHREAD_H
@@ -52,11 +16,13 @@
//
#include <QtCore/QMutex>
-#include <QtAndroidExtras/QAndroidJniObject>
+#include <QtCore/QJniObject>
#include <QtBluetooth/QBluetoothServer>
#include <QtBluetooth/QBluetoothUuid>
#include "qbluetooth.h"
+#include "private/qglobal_p.h"
+QT_BEGIN_NAMESPACE
class ServerAcceptanceThread : public QObject
{
@@ -69,7 +35,7 @@ public:
bool hasPendingConnections() const;
- QAndroidJniObject nextPendingConnection();
+ QJniObject nextPendingConnection();
void setMaxPendingConnections(int maximumCount);
void javaThreadErrorOccurred(int errorCode);
@@ -81,21 +47,23 @@ public:
signals:
void newConnection();
- void error(QBluetoothServer::Error);
+ void errorOccurred(QBluetoothServer::Error);
private:
bool validSetup() const;
void shutdownPendingConnections();
- QList<QAndroidJniObject> pendingSockets;
+ QList<QJniObject> pendingSockets;
mutable QMutex m_mutex;
QString m_serviceName;
QBluetoothUuid m_uuid;
int maxPendingConnections;
QBluetooth::SecurityFlags secFlags;
- QAndroidJniObject javaThread;
+ QJniObject javaThread;
};
+QT_END_NAMESPACE
+
#endif // SERVERACCEPTANCETHREAD_H
diff --git a/src/bluetooth/android/servicediscoverybroadcastreceiver.cpp b/src/bluetooth/android/servicediscoverybroadcastreceiver.cpp
index 283db623..a708035f 100644
--- a/src/bluetooth/android/servicediscoverybroadcastreceiver.cpp
+++ b/src/bluetooth/android/servicediscoverybroadcastreceiver.cpp
@@ -1,46 +1,10 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "android/servicediscoverybroadcastreceiver_p.h"
+#include <QCoreApplication>
#include <QtCore/QLoggingCategory>
-#include <QtCore/private/qjnihelpers_p.h>
-#include <QtAndroidExtras/QAndroidJniEnvironment>
+#include <QtCore/QJniEnvironment>
#include <QtBluetooth/QBluetoothAddress>
#include <QtBluetooth/QBluetoothDeviceInfo>
#include "android/jni_android_p.h"
@@ -51,8 +15,8 @@ Q_DECLARE_LOGGING_CATEGORY(QT_BT_ANDROID)
ServiceDiscoveryBroadcastReceiver::ServiceDiscoveryBroadcastReceiver(QObject* parent): AndroidBroadcastReceiver(parent)
{
- if (QtAndroidPrivate::androidSdkVersion() >= 15)
- addAction(valueForStaticField(JavaNames::BluetoothDevice, JavaNames::ActionUuid)); //API 15+
+ addAction(QJniObject::fromString(
+ valueForStaticField<QtJniTypes::BluetoothDevice, JavaNames::ActionUuid>()));
}
void ServiceDiscoveryBroadcastReceiver::onReceive(JNIEnv *env, jobject context, jobject intent)
@@ -60,19 +24,17 @@ void ServiceDiscoveryBroadcastReceiver::onReceive(JNIEnv *env, jobject context,
Q_UNUSED(context);
Q_UNUSED(env);
- QAndroidJniObject intentObject(intent);
- const QString action = intentObject.callObjectMethod("getAction", "()Ljava/lang/String;").toString();
+ QJniObject intentObject(intent);
+ const QString action = intentObject.callMethod<jstring>("getAction").toString();
qCDebug(QT_BT_ANDROID) << "ServiceDiscoveryBroadcastReceiver::onReceive() - event:" << action;
- if (action == valueForStaticField(JavaNames::BluetoothDevice,
- JavaNames::ActionUuid).toString()) {
+ if (action == valueForStaticField<QtJniTypes::BluetoothDevice, JavaNames::ActionUuid>()) {
- QAndroidJniObject keyExtra = valueForStaticField(JavaNames::BluetoothDevice,
- JavaNames::ExtraUuid);
- QAndroidJniObject parcelableUuids = intentObject.callObjectMethod(
+ QJniObject keyExtra = QJniObject::fromString(
+ valueForStaticField<QtJniTypes::BluetoothDevice, JavaNames::ExtraUuid>());
+ QJniObject parcelableUuids = intentObject.callMethod<QtJniTypes::ParcelableArray>(
"getParcelableArrayExtra",
- "(Ljava/lang/String;)[Landroid/os/Parcelable;",
keyExtra.object<jstring>());
if (!parcelableUuids.isValid()) {
emit uuidFetchFinished(QBluetoothAddress(), QList<QBluetoothUuid>());
@@ -80,14 +42,15 @@ void ServiceDiscoveryBroadcastReceiver::onReceive(JNIEnv *env, jobject context,
}
const QList<QBluetoothUuid> result = ServiceDiscoveryBroadcastReceiver::convertParcelableArray(parcelableUuids);
- keyExtra = valueForStaticField(JavaNames::BluetoothDevice, JavaNames::ExtraDevice);
- QAndroidJniObject bluetoothDevice =
- intentObject.callObjectMethod("getParcelableExtra",
- "(Ljava/lang/String;)Landroid/os/Parcelable;",
+ keyExtra = QJniObject::fromString(
+ valueForStaticField<QtJniTypes::BluetoothDevice, JavaNames::ExtraDevice>());
+ QJniObject bluetoothDevice =
+ intentObject.callMethod<QtJniTypes::Parcelable>("getParcelableExtra",
keyExtra.object<jstring>());
QBluetoothAddress address;
if (bluetoothDevice.isValid()) {
- address = QBluetoothAddress(bluetoothDevice.callObjectMethod<jstring>("getAddress").toString());
+ address =
+ QBluetoothAddress(bluetoothDevice.callMethod<jstring>("getAddress").toString());
emit uuidFetchFinished(address, result);
} else {
emit uuidFetchFinished(QBluetoothAddress(), QList<QBluetoothUuid>());
@@ -95,20 +58,20 @@ void ServiceDiscoveryBroadcastReceiver::onReceive(JNIEnv *env, jobject context,
}
}
-QList<QBluetoothUuid> ServiceDiscoveryBroadcastReceiver::convertParcelableArray(const QAndroidJniObject &parcelUuidArray)
+QList<QBluetoothUuid> ServiceDiscoveryBroadcastReceiver::convertParcelableArray(const QJniObject &parcelUuidArray)
{
QList<QBluetoothUuid> result;
- QAndroidJniEnvironment env;
+ QJniEnvironment env;
jobjectArray parcels = parcelUuidArray.object<jobjectArray>();
if (!parcels)
return result;
jint size = env->GetArrayLength(parcels);
- for (int i = 0; i < size; i++) {
- auto p = QAndroidJniObject::fromLocalRef(env->GetObjectArrayElement(parcels, i));
+ for (jint i = 0; i < size; ++i) {
+ auto p = QJniObject::fromLocalRef(env->GetObjectArrayElement(parcels, i));
- QBluetoothUuid uuid(p.callObjectMethod<jstring>("toString").toString());
+ QBluetoothUuid uuid(p.callMethod<jstring>("toString").toString());
//qCDebug(QT_BT_ANDROID) << uuid.toString();
result.append(uuid);
}
diff --git a/src/bluetooth/android/servicediscoverybroadcastreceiver_p.h b/src/bluetooth/android/servicediscoverybroadcastreceiver_p.h
index 4984e358..05149826 100644
--- a/src/bluetooth/android/servicediscoverybroadcastreceiver_p.h
+++ b/src/bluetooth/android/servicediscoverybroadcastreceiver_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef SERVICEDISCOVERYBROADCASTRECEIVER_H
#define SERVICEDISCOVERYBROADCASTRECEIVER_H
@@ -68,7 +32,7 @@ public:
virtual void onReceive(JNIEnv *env, jobject context, jobject intent);
virtual void onReceiveLeScan(JNIEnv *, jobject, jint, jbyteArray) {}
- static QList<QBluetoothUuid> convertParcelableArray(const QAndroidJniObject &obj);
+ static QList<QBluetoothUuid> convertParcelableArray(const QJniObject &obj);
signals:
void uuidFetchFinished(const QBluetoothAddress &addr, const QList<QBluetoothUuid> &serviceUuid);
diff --git a/src/bluetooth/bluetooth.pro b/src/bluetooth/bluetooth.pro
deleted file mode 100644
index b2ed5edf..00000000
--- a/src/bluetooth/bluetooth.pro
+++ /dev/null
@@ -1,269 +0,0 @@
-TARGET = QtBluetooth
-QT = core core-private
-DEFINES += QT_NO_FOREACH
-
-QMAKE_DOCS = $$PWD/doc/qtbluetooth.qdocconf
-OTHER_FILES += doc/src/*.qdoc # show .qdoc files in Qt Creator
-
-HEADERS += \
- qtbluetoothglobal.h \
- qbluetoothaddress.h\
- qbluetoothhostinfo.h \
- qbluetoothuuid.h\
- qbluetoothdeviceinfo.h\
- qbluetoothserviceinfo.h\
- qbluetoothdevicediscoveryagent.h\
- qbluetoothservicediscoveryagent.h\
- qbluetoothsocket.h\
- qbluetoothserver.h \
- qbluetooth.h \
- qbluetoothlocaldevice.h \
- qbluetoothtransfermanager.h \
- qbluetoothtransferrequest.h \
- qlowenergyservice.h \
- qlowenergyservicedata.h \
- qlowenergycharacteristic.h \
- qlowenergycharacteristicdata.h \
- qlowenergydescriptor.h \
- qlowenergydescriptordata.h \
- qbluetoothtransferreply.h \
- qlowenergyadvertisingdata.h \
- qlowenergyadvertisingparameters.h \
- qlowenergyconnectionparameters.h \
- qlowenergycontroller.h \
- qtbluetoothglobal_p.h \
- qbluetoothaddress_p.h\
- qbluetoothhostinfo_p.h \
- qbluetoothdeviceinfo_p.h\
- qbluetoothserviceinfo_p.h\
- qbluetoothdevicediscoveryagent_p.h\
- qbluetoothservicediscoveryagent_p.h\
- qbluetoothsocketbase_p.h \
- qbluetoothserver_p.h\
- qbluetoothtransferreply_p.h \
- qbluetoothtransferrequest_p.h \
- qprivatelinearbuffer_p.h \
- qbluetoothlocaldevice_p.h \
- qlowenergycontrollerbase_p.h \
- qlowenergyserviceprivate_p.h \
- qleadvertiser_p.h \
- lecmaccalculator_p.h
-
-SOURCES += \
- qbluetoothaddress.cpp\
- qbluetoothhostinfo.cpp \
- qbluetoothuuid.cpp\
- qbluetoothdeviceinfo.cpp\
- qbluetoothserviceinfo.cpp\
- qbluetoothdevicediscoveryagent.cpp\
- qbluetoothservicediscoveryagent.cpp\
- qbluetoothsocket.cpp\
- qbluetoothsocketbase.cpp \
- qbluetoothserver.cpp \
- qbluetoothlocaldevice.cpp \
- qbluetooth.cpp \
- qbluetoothtransfermanager.cpp \
- qbluetoothtransferrequest.cpp \
- qbluetoothtransferreply.cpp \
- qlowenergyadvertisingdata.cpp \
- qlowenergyadvertisingparameters.cpp \
- qlowenergyconnectionparameters.cpp \
- qlowenergyservice.cpp \
- qlowenergyservicedata.cpp \
- qlowenergycharacteristic.cpp \
- qlowenergycharacteristicdata.cpp \
- qlowenergydescriptor.cpp \
- qlowenergydescriptordata.cpp \
- qlowenergycontroller.cpp \
- qlowenergycontrollerbase.cpp \
- qlowenergyserviceprivate.cpp
-
-win32 {
- WINDOWS_SDK_VERSION_STRING = $$(WindowsSDKVersion)
- WINDOWS_SDK_VERSION = $$member($$list($$split(WINDOWS_SDK_VERSION_STRING, .)), 2)
-}
-
-qtConfig(bluez) {
- QT_PRIVATE = concurrent
- QT_FOR_PRIVATE += dbus network
-
- # do not link against QtNetwork but use inline qt_safe_* functions
- INCLUDEPATH += $$QT.network_private.includes
-
- include(bluez/bluez.pri)
-
- HEADERS += \
- qbluetoothtransferreply_bluez_p.h \
- qbluetoothsocket_bluez_p.h \
- qbluetoothsocket_bluezdbus_p.h
-
- SOURCES += \
- qbluetoothserviceinfo_bluez.cpp \
- qbluetoothdevicediscoveryagent_bluez.cpp\
- qbluetoothservicediscoveryagent_bluez.cpp \
- qbluetoothsocket_bluez.cpp \
- qbluetoothsocket_bluezdbus.cpp \
- qbluetoothserver_bluez.cpp \
- qbluetoothlocaldevice_bluez.cpp \
- qbluetoothtransferreply_bluez.cpp
-
-
- # old versions of Bluez do not have the required BTLE symbols
- qtConfig(bluez_le) {
- SOURCES += \
- qleadvertiser_bluez.cpp \
- qlowenergycontroller_bluez.cpp \
- lecmaccalculator.cpp \
- qlowenergycontroller_bluezdbus.cpp
-
- HEADERS += qlowenergycontroller_bluezdbus_p.h \
- qlowenergycontroller_bluez_p.h
-
- qtConfig(linux_crypto_api): DEFINES += CONFIG_LINUX_CRYPTO_API
- } else {
- DEFINES += QT_BLUEZ_NO_BTLE
- include(dummy/dummy.pri)
- SOURCES += \
- qlowenergycontroller_dummy.cpp
-
- HEADERS += qlowenergycontroller_dummy_p.h
- }
-
-} else:android:!android-embedded {
- include(android/android.pri)
- DEFINES += QT_ANDROID_BLUETOOTH
- QT_FOR_PRIVATE += core-private androidextras
-
- ANDROID_PERMISSIONS = \
- android.permission.BLUETOOTH \
- android.permission.BLUETOOTH_ADMIN \
- android.permission.ACCESS_COARSE_LOCATION # since Android 6.0 (API lvl 23)
- ANDROID_BUNDLED_JAR_DEPENDENCIES = \
- jar/QtAndroidBluetooth.jar:org.qtproject.qt5.android.bluetooth.QtBluetoothBroadcastReceiver
-
- SOURCES += \
- qbluetoothdevicediscoveryagent_android.cpp \
- qbluetoothlocaldevice_android.cpp \
- qbluetoothserviceinfo_android.cpp \
- qbluetoothservicediscoveryagent_android.cpp \
- qbluetoothsocket_android.cpp \
- qbluetoothserver_android.cpp \
- qlowenergycontroller_android.cpp
-
- HEADERS += qlowenergycontroller_android_p.h \
- qbluetoothsocket_android_p.h
-} else:osx {
- QT_PRIVATE = concurrent
- DEFINES += QT_OSX_BLUETOOTH
- LIBS_PRIVATE += -framework Foundation -framework IOBluetooth
-
- include(darwin/darwinbt.pri)
- OBJECTIVE_SOURCES += \
- qbluetoothlocaldevice_macos.mm \
- qbluetoothdevicediscoveryagent_darwin.mm \
- qbluetoothserviceinfo_macos.mm \
- qbluetoothservicediscoveryagent_macos.mm \
- qbluetoothsocket_macos.mm \
- qbluetoothserver_macos.mm \
- qbluetoothtransferreply_macos.mm \
- qlowenergycontroller_darwin.mm
-
- HEADERS += qbluetoothsocket_macos_p.h \
- qbluetoothtransferreply_macos_p.h \
- qlowenergycontroller_darwin_p.h
-} else:ios|tvos {
- DEFINES += QT_IOS_BLUETOOTH
- LIBS_PRIVATE += -framework Foundation -framework CoreBluetooth
-
- OBJECTIVE_SOURCES += \
- qbluetoothdevicediscoveryagent_darwin.mm \
- qlowenergycontroller_darwin.mm
-
- HEADERS += \
- qlowenergycontroller_darwin_p.h \
- qbluetoothsocket_dummy_p.h
-
- include(darwin/darwinbt.pri)
- SOURCES += \
- qbluetoothlocaldevice_p.cpp \
- qbluetoothserviceinfo_p.cpp \
- qbluetoothservicediscoveryagent_p.cpp \
- qbluetoothsocket_dummy.cpp \
- qbluetoothserver_p.cpp
-} else: qtConfig(winrt_bt) {
- DEFINES += QT_WINRT_BLUETOOTH
- !winrt {
- SOURCES += qbluetoothutils_win.cpp
- DEFINES += CLASSIC_APP_BUILD
- LIBS += runtimeobject.lib user32.lib
- }
-
- QT += core-private
-
- SOURCES += \
- qbluetoothdevicediscoveryagent_winrt.cpp \
- qbluetoothlocaldevice_winrt.cpp \
- qbluetoothserver_winrt.cpp \
- qbluetoothservicediscoveryagent_winrt.cpp \
- qbluetoothserviceinfo_winrt.cpp \
- qbluetoothsocket_winrt.cpp \
- qbluetoothutils_winrt.cpp \
- qlowenergycontroller_winrt.cpp
-
- HEADERS += qlowenergycontroller_winrt_p.h \
- qbluetoothsocket_winrt_p.h \
- qbluetoothutils_winrt_p.h
-
- qtConfig(winrt_btle_no_pairing) {
- SOURCES += qlowenergycontroller_winrt_new.cpp
- HEADERS += qlowenergycontroller_winrt_new_p.h
- }
-
- lessThan(WINDOWS_SDK_VERSION, 14393) {
- DEFINES += QT_WINRT_LIMITED_SERVICEDISCOVERY
- DEFINES += QT_UCRTVERSION=$$WINDOWS_SDK_VERSION
- }
-} else:win32 {
- QT_PRIVATE = concurrent
- DEFINES += QT_WIN_BLUETOOTH
- LIBS += -lbthprops -lws2_32 -lsetupapi
-
- include(windows/windows.pri)
-
- SOURCES += \
- qbluetoothdevicediscoveryagent_win.cpp \
- qbluetoothlocaldevice_win.cpp \
- qbluetoothserviceinfo_win.cpp \
- qbluetoothservicediscoveryagent_win.cpp \
- qbluetoothsocket_win.cpp \
- qbluetoothserver_win.cpp \
- qlowenergycontroller_win.cpp
-
- HEADERS += qlowenergycontroller_win_p.h \
- qbluetoothsocket_win_p.h
-} else {
- message("Unsupported Bluetooth platform, will not build a working QtBluetooth library.")
- message("Either no Qt D-Bus found or no BlueZ headers available.")
- include(dummy/dummy.pri)
- SOURCES += \
- qbluetoothdevicediscoveryagent_p.cpp \
- qbluetoothlocaldevice_p.cpp \
- qbluetoothserviceinfo_p.cpp \
- qbluetoothservicediscoveryagent_p.cpp \
- qbluetoothsocket_dummy.cpp \
- qbluetoothserver_p.cpp \
- qlowenergycontroller_dummy.cpp
-
- HEADERS += qlowenergycontroller_dummy_p.h \
- qbluetoothsocket_dummy_p.h
-}
-
-winrt {
- MODULE_WINRT_CAPABILITIES_DEVICE += \
- bluetooth.genericAttributeProfile \
- bluetooth.rfcomm
-}
-
-OTHER_FILES +=
-
-load(qt_module)
diff --git a/src/bluetooth/bluez/adapter.cpp b/src/bluetooth/bluez/adapter.cpp
deleted file mode 100644
index eaea76f8..00000000
--- a/src/bluetooth/bluez/adapter.cpp
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * This file was generated by qdbusxml2cpp version 0.8
- * Command line was: qdbusxml2cpp -p adapter_p.h:adapter.cpp org.bluez.all.xml org.bluez.Adapter
- *
- * qdbusxml2cpp is Copyright (C) 2017 The Qt Company Ltd.
- *
- * This is an auto-generated file.
- * This file may have been hand-edited. Look for HAND-EDIT comments
- * before re-generating it.
- */
-
-#include "adapter_p.h"
-
-/*
- * Implementation of interface class OrgBluezAdapterInterface
- */
-
-OrgBluezAdapterInterface::OrgBluezAdapterInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent)
- : QDBusAbstractInterface(service, path, staticInterfaceName(), connection, parent)
-{
-}
-
-OrgBluezAdapterInterface::~OrgBluezAdapterInterface()
-{
-}
-
diff --git a/src/bluetooth/bluez/adapter1_bluez5.cpp b/src/bluetooth/bluez/adapter1_bluez5.cpp
index b1aefc8d..285c79b1 100644
--- a/src/bluetooth/bluez/adapter1_bluez5.cpp
+++ b/src/bluetooth/bluez/adapter1_bluez5.cpp
@@ -1,8 +1,8 @@
/*
* This file was generated by qdbusxml2cpp version 0.8
- * Command line was: qdbusxml2cpp -p adapter1_bluez5_p.h:adapter1_bluez5.cpp org.bluez.Adapter1.xml
+ * Command line was: qdbusxml2cpp -I QtCore/private/qglobal_p.h -p adapter1_bluez5_p.h:adapter1_bluez5.cpp org.bluez.Adapter1.xml
*
- * qdbusxml2cpp is Copyright (C) 2017 The Qt Company Ltd.
+ * qdbusxml2cpp is Copyright (C) 2022 The Qt Company Ltd.
*
* This is an auto-generated file.
* This file may have been hand-edited. Look for HAND-EDIT comments
@@ -24,3 +24,5 @@ OrgBluezAdapter1Interface::~OrgBluezAdapter1Interface()
{
}
+
+#include "moc_adapter1_bluez5_p.cpp"
diff --git a/src/bluetooth/bluez/adapter1_bluez5_p.h b/src/bluetooth/bluez/adapter1_bluez5_p.h
index ce108ad0..fc641b37 100644
--- a/src/bluetooth/bluez/adapter1_bluez5_p.h
+++ b/src/bluetooth/bluez/adapter1_bluez5_p.h
@@ -1,8 +1,8 @@
/*
* This file was generated by qdbusxml2cpp version 0.8
- * Command line was: qdbusxml2cpp -p adapter1_bluez5_p.h:adapter1_bluez5.cpp org.bluez.Adapter1.xml
+ * Command line was: qdbusxml2cpp -I QtCore/private/qglobal_p.h -p adapter1_bluez5_p.h:adapter1_bluez5.cpp org.bluez.Adapter1.xml
*
- * qdbusxml2cpp is Copyright (C) 2017 The Qt Company Ltd.
+ * qdbusxml2cpp is Copyright (C) 2022 The Qt Company Ltd.
*
* This is an auto-generated file.
* Do not edit! All changes made to it will be lost.
@@ -11,6 +11,17 @@
#ifndef ADAPTER1_BLUEZ5_P_H
#define ADAPTER1_BLUEZ5_P_H
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
#include <QtCore/QObject>
#include <QtCore/QByteArray>
#include <QtCore/QList>
@@ -19,6 +30,7 @@
#include <QtCore/QStringList>
#include <QtCore/QVariant>
#include <QtDBus/QtDBus>
+#include <QtCore/private/qglobal_p.h>
/*
* Proxy class for interface org.bluez.Adapter1
@@ -127,7 +139,7 @@ Q_SIGNALS: // SIGNALS
namespace org {
namespace bluez {
- typedef ::OrgBluezAdapter1Interface Adapter1;
+ using Adapter1 = ::OrgBluezAdapter1Interface;
}
}
#endif
diff --git a/src/bluetooth/bluez/adapter_p.h b/src/bluetooth/bluez/adapter_p.h
deleted file mode 100644
index 236fe7e4..00000000
--- a/src/bluetooth/bluez/adapter_p.h
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * This file was generated by qdbusxml2cpp version 0.8
- * Command line was: qdbusxml2cpp -p adapter_p.h:adapter.cpp org.bluez.all.xml org.bluez.Adapter
- *
- * qdbusxml2cpp is Copyright (C) 2017 The Qt Company Ltd.
- *
- * This is an auto-generated file.
- * Do not edit! All changes made to it will be lost.
- */
-
-#ifndef ADAPTER_P_H
-#define ADAPTER_P_H
-
-#include <QtCore/QObject>
-#include <QtCore/QByteArray>
-#include <QtCore/QList>
-#include <QtCore/QMap>
-#include <QtCore/QString>
-#include <QtCore/QStringList>
-#include <QtCore/QVariant>
-#include <QtDBus/QtDBus>
-
-/*
- * Proxy class for interface org.bluez.Adapter
- */
-class OrgBluezAdapterInterface: public QDBusAbstractInterface
-{
- Q_OBJECT
-public:
- static inline const char *staticInterfaceName()
- { return "org.bluez.Adapter"; }
-
-public:
- OrgBluezAdapterInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = nullptr);
-
- ~OrgBluezAdapterInterface();
-
-public Q_SLOTS: // METHODS
- inline QDBusPendingReply<> CancelDeviceCreation(const QString &in0)
- {
- QList<QVariant> argumentList;
- argumentList << QVariant::fromValue(in0);
- return asyncCallWithArgumentList(QStringLiteral("CancelDeviceCreation"), argumentList);
- }
-
- inline QDBusPendingReply<QDBusObjectPath> CreateDevice(const QString &in0)
- {
- QList<QVariant> argumentList;
- argumentList << QVariant::fromValue(in0);
- return asyncCallWithArgumentList(QStringLiteral("CreateDevice"), argumentList);
- }
-
- inline QDBusPendingReply<QDBusObjectPath> CreatePairedDevice(const QString &in0, const QDBusObjectPath &in1, const QString &in2)
- {
- QList<QVariant> argumentList;
- argumentList << QVariant::fromValue(in0) << QVariant::fromValue(in1) << QVariant::fromValue(in2);
- return asyncCallWithArgumentList(QStringLiteral("CreatePairedDevice"), argumentList);
- }
-
- inline QDBusPendingReply<QDBusObjectPath> FindDevice(const QString &in0)
- {
- QList<QVariant> argumentList;
- argumentList << QVariant::fromValue(in0);
- return asyncCallWithArgumentList(QStringLiteral("FindDevice"), argumentList);
- }
-
- inline QDBusPendingReply<QVariantMap> GetProperties()
- {
- QList<QVariant> argumentList;
- return asyncCallWithArgumentList(QStringLiteral("GetProperties"), argumentList);
- }
-
- inline QDBusPendingReply<QList<QDBusObjectPath> > ListDevices()
- {
- QList<QVariant> argumentList;
- return asyncCallWithArgumentList(QStringLiteral("ListDevices"), argumentList);
- }
-
- inline QDBusPendingReply<> RegisterAgent(const QDBusObjectPath &in0, const QString &in1)
- {
- QList<QVariant> argumentList;
- argumentList << QVariant::fromValue(in0) << QVariant::fromValue(in1);
- return asyncCallWithArgumentList(QStringLiteral("RegisterAgent"), argumentList);
- }
-
- inline QDBusPendingReply<> ReleaseMode()
- {
- QList<QVariant> argumentList;
- return asyncCallWithArgumentList(QStringLiteral("ReleaseMode"), argumentList);
- }
-
- inline QDBusPendingReply<> ReleaseSession()
- {
- QList<QVariant> argumentList;
- return asyncCallWithArgumentList(QStringLiteral("ReleaseSession"), argumentList);
- }
-
- inline QDBusPendingReply<> RemoveDevice(const QDBusObjectPath &in0)
- {
- QList<QVariant> argumentList;
- argumentList << QVariant::fromValue(in0);
- return asyncCallWithArgumentList(QStringLiteral("RemoveDevice"), argumentList);
- }
-
- inline QDBusPendingReply<> RequestMode(const QString &in0)
- {
- QList<QVariant> argumentList;
- argumentList << QVariant::fromValue(in0);
- return asyncCallWithArgumentList(QStringLiteral("RequestMode"), argumentList);
- }
-
- inline QDBusPendingReply<> RequestSession()
- {
- QList<QVariant> argumentList;
- return asyncCallWithArgumentList(QStringLiteral("RequestSession"), argumentList);
- }
-
- inline QDBusPendingReply<> SetProperty(const QString &in0, const QDBusVariant &in1)
- {
- QList<QVariant> argumentList;
- argumentList << QVariant::fromValue(in0) << QVariant::fromValue(in1);
- return asyncCallWithArgumentList(QStringLiteral("SetProperty"), argumentList);
- }
-
- inline QDBusPendingReply<> StartDiscovery()
- {
- QList<QVariant> argumentList;
- return asyncCallWithArgumentList(QStringLiteral("StartDiscovery"), argumentList);
- }
-
- inline QDBusPendingReply<> StopDiscovery()
- {
- QList<QVariant> argumentList;
- return asyncCallWithArgumentList(QStringLiteral("StopDiscovery"), argumentList);
- }
-
- inline QDBusPendingReply<> UnregisterAgent(const QDBusObjectPath &in0)
- {
- QList<QVariant> argumentList;
- argumentList << QVariant::fromValue(in0);
- return asyncCallWithArgumentList(QStringLiteral("UnregisterAgent"), argumentList);
- }
-
-Q_SIGNALS: // SIGNALS
- void DeviceCreated(const QDBusObjectPath &in0);
- void DeviceDisappeared(const QString &in0);
- void DeviceFound(const QString &in0, const QVariantMap &in1);
- void DeviceRemoved(const QDBusObjectPath &in0);
- void PropertyChanged(const QString &in0, const QDBusVariant &in1);
-};
-
-namespace org {
- namespace bluez {
- typedef ::OrgBluezAdapterInterface Adapter;
- }
-}
-#endif
diff --git a/src/bluetooth/bluez/agent.cpp b/src/bluetooth/bluez/agent.cpp
deleted file mode 100644
index 6fa80176..00000000
--- a/src/bluetooth/bluez/agent.cpp
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * This file was generated by qdbusxml2cpp version 0.8
- * Command line was: qdbusxml2cpp -c OrgBluezAgentAdaptor -a agent_p.h:agent.cpp org.bluez.Agent.xml org.bluez.Agent
- *
- * qdbusxml2cpp is Copyright (C) 2017 The Qt Company Ltd.
- *
- * This is an auto-generated file.
- * Do not edit! All changes made to it will be lost.
- */
-
-#include "agent_p.h"
-#include <QtCore/QMetaObject>
-#include <QtCore/QByteArray>
-#include <QtCore/QList>
-#include <QtCore/QMap>
-#include <QtCore/QString>
-#include <QtCore/QStringList>
-#include <QtCore/QVariant>
-
-/*
- * Implementation of adaptor class OrgBluezAgentAdaptor
- */
-
-OrgBluezAgentAdaptor::OrgBluezAgentAdaptor(QObject *parent)
- : QDBusAbstractAdaptor(parent)
-{
- // constructor
- setAutoRelaySignals(true);
-}
-
-OrgBluezAgentAdaptor::~OrgBluezAgentAdaptor()
-{
- // destructor
-}
-
-void OrgBluezAgentAdaptor::Authorize(const QDBusObjectPath &in0, const QString &in1)
-{
- // handle method call org.bluez.Agent.Authorize
- QMetaObject::invokeMethod(parent(), "Authorize", Q_ARG(QDBusObjectPath, in0), Q_ARG(QString, in1));
-}
-
-void OrgBluezAgentAdaptor::Cancel()
-{
- // handle method call org.bluez.Agent.Cancel
- QMetaObject::invokeMethod(parent(), "Cancel");
-}
-
-void OrgBluezAgentAdaptor::ConfirmModeChange(const QString &in0)
-{
- // handle method call org.bluez.Agent.ConfirmModeChange
- QMetaObject::invokeMethod(parent(), "ConfirmModeChange", Q_ARG(QString, in0));
-}
-
-void OrgBluezAgentAdaptor::DisplayPasskey(const QDBusObjectPath &in0, uint in1, uchar in2)
-{
- // handle method call org.bluez.Agent.DisplayPasskey
- QMetaObject::invokeMethod(parent(), "DisplayPasskey", Q_ARG(QDBusObjectPath, in0), Q_ARG(uint, in1), Q_ARG(uchar, in2));
-}
-
-void OrgBluezAgentAdaptor::Release()
-{
- // handle method call org.bluez.Agent.Release
- QMetaObject::invokeMethod(parent(), "Release");
-}
-
-void OrgBluezAgentAdaptor::RequestConfirmation(const QDBusObjectPath &in0, uint in1)
-{
- // handle method call org.bluez.Agent.RequestConfirmation
- QMetaObject::invokeMethod(parent(), "RequestConfirmation", Q_ARG(QDBusObjectPath, in0), Q_ARG(uint, in1));
-}
-
-uint OrgBluezAgentAdaptor::RequestPasskey(const QDBusObjectPath &in0)
-{
- // handle method call org.bluez.Agent.RequestPasskey
- uint out0;
- QMetaObject::invokeMethod(parent(), "RequestPasskey", Q_RETURN_ARG(uint, out0), Q_ARG(QDBusObjectPath, in0));
- return out0;
-}
-
-QString OrgBluezAgentAdaptor::RequestPinCode(const QDBusObjectPath &in0)
-{
- // handle method call org.bluez.Agent.RequestPinCode
- QString out0;
- QMetaObject::invokeMethod(parent(), "RequestPinCode", Q_RETURN_ARG(QString, out0), Q_ARG(QDBusObjectPath, in0));
- return out0;
-}
-
diff --git a/src/bluetooth/bluez/agent_p.h b/src/bluetooth/bluez/agent_p.h
deleted file mode 100644
index 7ca177fd..00000000
--- a/src/bluetooth/bluez/agent_p.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * This file was generated by qdbusxml2cpp version 0.8
- * Command line was: qdbusxml2cpp -c OrgBluezAgentAdaptor -a agent_p.h:agent.cpp org.bluez.Agent.xml org.bluez.Agent
- *
- * qdbusxml2cpp is Copyright (C) 2017 The Qt Company Ltd.
- *
- * This is an auto-generated file.
- * This file may have been hand-edited. Look for HAND-EDIT comments
- * before re-generating it.
- */
-
-#ifndef AGENT_P_H
-#define AGENT_P_H
-
-#include <QtCore/QObject>
-#include <QtCore/qcontainerfwd.h>
-#include <QtDBus/QtDBus>
-QT_BEGIN_NAMESPACE
-class QByteArray;
-class QString;
-class QStringList;
-class QVariant;
-QT_END_NAMESPACE
-
-/*
- * Adaptor class for interface org.bluez.Agent
- */
-class OrgBluezAgentAdaptor: public QDBusAbstractAdaptor
-{
- Q_OBJECT
- Q_CLASSINFO("D-Bus Interface", "org.bluez.Agent")
- Q_CLASSINFO("D-Bus Introspection", ""
-" <interface name=\"org.bluez.Agent\">\n"
-" <method name=\"Release\"/>\n"
-" <method name=\"RequestPinCode\">\n"
-" <arg direction=\"in\" type=\"o\"/>\n"
-" <arg direction=\"out\" type=\"s\"/>\n"
-" </method>\n"
-" <method name=\"RequestPasskey\">\n"
-" <arg direction=\"in\" type=\"o\"/>\n"
-" <arg direction=\"out\" type=\"u\"/>\n"
-" </method>\n"
-" <method name=\"DisplayPasskey\">\n"
-" <arg direction=\"in\" type=\"o\"/>\n"
-" <arg direction=\"in\" type=\"u\"/>\n"
-" <arg direction=\"in\" type=\"y\"/>\n"
-" </method>\n"
-" <method name=\"RequestConfirmation\">\n"
-" <arg direction=\"in\" type=\"o\"/>\n"
-" <arg direction=\"in\" type=\"u\"/>\n"
-" </method>\n"
-" <method name=\"Authorize\">\n"
-" <arg direction=\"in\" type=\"o\"/>\n"
-" <arg direction=\"in\" type=\"s\"/>\n"
-" </method>\n"
-" <method name=\"ConfirmModeChange\">\n"
-" <arg direction=\"in\" type=\"s\"/>\n"
-" </method>\n"
-" <method name=\"Cancel\"/>\n"
-" </interface>\n"
- "")
-public:
- OrgBluezAgentAdaptor(QObject *parent);
- virtual ~OrgBluezAgentAdaptor();
-
-public: // PROPERTIES
-public Q_SLOTS: // METHODS
- void Authorize(const QDBusObjectPath &in0, const QString &in1);
- void Cancel();
- void ConfirmModeChange(const QString &in0);
- void DisplayPasskey(const QDBusObjectPath &in0, uint in1, uchar in2);
- void Release();
- void RequestConfirmation(const QDBusObjectPath &in0, uint in1);
- uint RequestPasskey(const QDBusObjectPath &in0);
- QString RequestPinCode(const QDBusObjectPath &in0);
-Q_SIGNALS: // SIGNALS
-};
-
-#endif
diff --git a/src/bluetooth/bluez/battery1.cpp b/src/bluetooth/bluez/battery1.cpp
index f23cc205..abbad849 100644
--- a/src/bluetooth/bluez/battery1.cpp
+++ b/src/bluetooth/bluez/battery1.cpp
@@ -1,8 +1,8 @@
/*
* This file was generated by qdbusxml2cpp version 0.8
- * Command line was: qdbusxml2cpp -p battery1_p.h:battery1.cpp org.bluez.Battery1.xml
+ * Command line was: qdbusxml2cpp -I QtCore/private/qglobal_p.h -p battery1_p.h:battery1.cpp org.bluez.Battery1.xml
*
- * qdbusxml2cpp is Copyright (C) 2018 The Qt Company Ltd.
+ * qdbusxml2cpp is Copyright (C) 2022 The Qt Company Ltd.
*
* This is an auto-generated file.
* This file may have been hand-edited. Look for HAND-EDIT comments
@@ -24,3 +24,5 @@ OrgBluezBattery1Interface::~OrgBluezBattery1Interface()
{
}
+
+#include "moc_battery1_p.cpp"
diff --git a/src/bluetooth/bluez/battery1_p.h b/src/bluetooth/bluez/battery1_p.h
index 035382df..8211209d 100644
--- a/src/bluetooth/bluez/battery1_p.h
+++ b/src/bluetooth/bluez/battery1_p.h
@@ -1,8 +1,8 @@
/*
* This file was generated by qdbusxml2cpp version 0.8
- * Command line was: qdbusxml2cpp -p battery1_p.h:battery1.cpp org.bluez.Battery1.xml
+ * Command line was: qdbusxml2cpp -I QtCore/private/qglobal_p.h -p battery1_p.h:battery1.cpp org.bluez.Battery1.xml
*
- * qdbusxml2cpp is Copyright (C) 2018 The Qt Company Ltd.
+ * qdbusxml2cpp is Copyright (C) 2022 The Qt Company Ltd.
*
* This is an auto-generated file.
* Do not edit! All changes made to it will be lost.
@@ -11,6 +11,17 @@
#ifndef BATTERY1_P_H
#define BATTERY1_P_H
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
#include <QtCore/QObject>
#include <QtCore/QByteArray>
#include <QtCore/QList>
@@ -19,6 +30,7 @@
#include <QtCore/QStringList>
#include <QtCore/QVariant>
#include <QtDBus/QtDBus>
+#include <QtCore/private/qglobal_p.h>
/*
* Proxy class for interface org.bluez.Battery1
@@ -45,7 +57,7 @@ Q_SIGNALS: // SIGNALS
namespace org {
namespace bluez {
- typedef ::OrgBluezBattery1Interface Battery1;
+ using Battery1 = ::OrgBluezBattery1Interface;
}
}
#endif
diff --git a/src/bluetooth/bluez/bluetoothmanagement.cpp b/src/bluetooth/bluez/bluetoothmanagement.cpp
index 6a1e8864..15ca8e56 100644
--- a/src/bluetooth/bluez/bluetoothmanagement.cpp
+++ b/src/bluetooth/bluez/bluetoothmanagement.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtCore/qloggingcategory.h>
#include <QtCore/qsocketnotifier.h>
@@ -51,15 +15,12 @@
#include <sys/types.h>
#include <linux/capability.h>
+#include <cerrno>
QT_BEGIN_NAMESPACE
// Packet data structures for Mgmt API bluez.git/doc/mgmt-api.txt
-enum class EventCode {
- DeviceFound = 0x0012,
-};
-
struct MgmtHdr {
quint16 cmdCode;
quint16 controllerIndex;
@@ -125,11 +86,6 @@ struct capData {
const int msecInADay = 1000*60*60*24;
-inline uint qHash(const QBluetoothAddress& address)
-{
- return qHash(address.toUInt64());
-}
-
static int sysCallCapGet(capHdr *header, capData *data)
{
return syscall(__NR_capget, header, data);
@@ -209,7 +165,7 @@ BluetoothManagement *BluetoothManagement::instance()
void BluetoothManagement::_q_readNotifier()
{
char *dst = buffer.reserve(QPRIVATELINEARBUFFER_BUFFERSIZE);
- int readCount = ::read(fd, dst, QPRIVATELINEARBUFFER_BUFFERSIZE);
+ const auto readCount = ::read(fd, dst, QPRIVATELINEARBUFFER_BUFFERSIZE);
buffer.chop(QPRIVATELINEARBUFFER_BUFFERSIZE - (readCount < 0 ? 0 : readCount));
if (readCount < 0) {
qCWarning(QT_BT_BLUEZ, "Management Control read error %s", qPrintable(qt_error_string(errno)));
@@ -217,24 +173,24 @@ void BluetoothManagement::_q_readNotifier()
}
// do we have at least one complete mgmt header?
- if ((uint)buffer.size() < sizeof(MgmtHdr))
+ if (size_t(buffer.size()) < sizeof(MgmtHdr))
return;
QByteArray data = buffer.readAll();
while (true) {
- if ((uint)data.size() < sizeof(MgmtHdr))
+ if (size_t(data.size()) < sizeof(MgmtHdr))
break;
const MgmtHdr *hdr = reinterpret_cast<const MgmtHdr*>(data.constData());
- const int nextPackageSize = qFromLittleEndian(hdr->length) + sizeof(MgmtHdr);
- const int remainingPackageSize = data.length() - nextPackageSize;
+ const auto nextPackageSize = qsizetype(qFromLittleEndian(hdr->length) + sizeof(MgmtHdr));
+ const qsizetype remainingPackageSize = data.size() - nextPackageSize;
- if (data.length() < nextPackageSize)
+ if (data.size() < nextPackageSize)
break; // not a complete event header -> wait for next notifier
switch (static_cast<EventCode>(qFromLittleEndian(hdr->cmdCode))) {
- case EventCode::DeviceFound:
+ case EventCode::DeviceFoundEvent:
{
const MgmtEventDeviceFound *event = reinterpret_cast<const MgmtEventDeviceFound*>
(data.constData() + sizeof(MgmtHdr));
@@ -254,11 +210,11 @@ void BluetoothManagement::_q_readNotifier()
}
default:
qCDebug(QT_BT_BLUEZ) << "BluetoothManagement: Ignored event:"
- << Qt::hex << qFromLittleEndian(hdr->cmdCode);
+ << Qt::hex << (EventCode)qFromLittleEndian(hdr->cmdCode);
break;
}
- if (data.length() > nextPackageSize)
+ if (data.size() > nextPackageSize)
data = data.right(remainingPackageSize);
else
data.clear();
@@ -312,3 +268,5 @@ bool BluetoothManagement::isMonitoringEnabled() const
QT_END_NAMESPACE
+
+#include "moc_bluetoothmanagement_p.cpp"
diff --git a/src/bluetooth/bluez/bluetoothmanagement_p.h b/src/bluetooth/bluez/bluetoothmanagement_p.h
index 954f6e03..c45d31f7 100644
--- a/src/bluetooth/bluez/bluetoothmanagement_p.h
+++ b/src/bluetooth/bluez/bluetoothmanagement_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef BLUETOOTHMANAGEMENT_P_H
#define BLUETOOTHMANAGEMENT_P_H
@@ -58,7 +22,7 @@
#include <QtBluetooth/qbluetoothaddress.h>
#ifndef QPRIVATELINEARBUFFER_BUFFERSIZE
-#define QPRIVATELINEARBUFFER_BUFFERSIZE Q_INT64_C(16384)
+#define QPRIVATELINEARBUFFER_BUFFERSIZE qsizetype(16384)
#endif
#include "../qprivatelinearbuffer_p.h"
@@ -71,6 +35,57 @@ class BluetoothManagement : public QObject
Q_OBJECT
public:
+
+ enum class EventCode {
+ CommandCompleteEvent = 0x0001,
+ CommandStatusEvent = 0x0002,
+ ControllerErrorEvent = 0x0003,
+ IndexAddedEvent = 0x0004,
+ IndexRemovedEvent = 0x0005,
+ NewSettingsEvent = 0x0006,
+ ClassOfDeviceChangedEvent = 0x0007,
+ LocalNameChangedEvent = 0x0008,
+ NewLinkKeyEvent = 0x0009,
+ NewLongTermKeyEvent = 0x000A,
+ DeviceConnectedEvent = 0x000B,
+ DeviceDisconnectedEvent = 0x000C,
+ ConnectFailedEvent = 0x000D,
+ PINCodeRequestEvent = 0x000E,
+ UserConfirmationRequestEvent = 0x000F,
+ UserPasskeyRequestEvent = 0x0010,
+ AuthenticationFailedEvent = 0x0011,
+ DeviceFoundEvent = 0x0012,
+ DiscoveringEvent = 0x0013,
+ DeviceBlockedEvent = 0x0014,
+ DeviceUnblockedEvent = 0x00150,
+ DeviceUnpairedEvent = 0x0016,
+ PasskeyNotifyEvent = 0x0017,
+ NewIdentityResolvingKeyEvent = 0x0018,
+ NewSignatureResolvingKeyEvent = 0x0019,
+ DeviceAddedEvent = 0x001a,
+ DeviceRemovedEvent = 0x001b,
+ NewConnectionParameterEvent = 0x001c,
+ UnconfiguredIndexAddedEvent = 0x001d,
+ UnconfiguredIndexRemovedEvent = 0x001e,
+ NewConfigurationOptionsEvent = 0x001f,
+ ExtendedIndexAddedEvent = 0x0020,
+ ExtendedIndexRemovedEvent = 0x0021,
+ LocalOutOfBandExtendedDataUpdatedEvent = 0x0022,
+ AdvertisingAddedEvent = 0x0023,
+ AdvertisingRemovedEvent = 0x0024,
+ ExtendedControllerInformationChangedEvent = 0x0025,
+ PHYConfigurationChangedEvent = 0x0026,
+ ExperimentalFeatureChangedEvent = 0x0027,
+ DefaultSystemConfigurationChangedEvent = 0x0028,
+ DefaultRuntimeConfigurationChangedEvent = 0x0029,
+ DeviceFlagsChangedEvent = 0x002a,
+ AdvertisementMonitorAddedEvent = 0x002b,
+ AdvertisementMonitorRemovedEvent = 0x002c,
+ ControllerSuspendEvent = 0x002d,
+ ControllerResumeEvent = 0x002e
+ };
+ Q_ENUM(EventCode)
+
explicit BluetoothManagement(QObject *parent = nullptr);
static BluetoothManagement *instance();
diff --git a/src/bluetooth/bluez/bluez.pri b/src/bluetooth/bluez/bluez.pri
deleted file mode 100644
index af7f0e0c..00000000
--- a/src/bluetooth/bluez/bluez.pri
+++ /dev/null
@@ -1,58 +0,0 @@
-HEADERS += bluez/manager_p.h \
- bluez/adapter_p.h \
- bluez/device_p.h \
- bluez/service_p.h \
- bluez/agent_p.h \
- bluez/servicemap_p.h \
- bluez/obex_client_p.h \
- bluez/obex_agent_p.h \
- bluez/obex_transfer_p.h \
- bluez/obex_manager_p.h \
- bluez/bluez5_helper_p.h \
- bluez/objectmanager_p.h \
- bluez/properties_p.h \
- bluez/adapter1_bluez5_p.h \
- bluez/device1_bluez5_p.h \
- bluez/profilemanager1_p.h \
- bluez/profile1_p.h \
- bluez/profile1context_p.h \
- bluez/obex_client1_bluez5_p.h \
- bluez/obex_objectpush1_bluez5_p.h \
- bluez/obex_transfer1_bluez5_p.h \
- bluez/gattchar1_p.h \
- bluez/gattdesc1_p.h \
- bluez/gattservice1_p.h \
- bluez/battery1_p.h \
- bluez/bluez_data_p.h \
- bluez/hcimanager_p.h \
- bluez/remotedevicemanager_p.h \
- bluez/bluetoothmanagement_p.h
-
-SOURCES += bluez/manager.cpp \
- bluez/adapter.cpp \
- bluez/agent.cpp \
- bluez/device.cpp \
- bluez/service.cpp \
- bluez/servicemap.cpp \
- bluez/obex_client.cpp \
- bluez/obex_agent.cpp \
- bluez/obex_transfer.cpp \
- bluez/obex_manager.cpp \
- bluez/objectmanager.cpp \
- bluez/properties.cpp \
- bluez/adapter1_bluez5.cpp \
- bluez/device1_bluez5.cpp \
- bluez/bluez5_helper.cpp \
- bluez/profilemanager1.cpp \
- bluez/profile1.cpp \
- bluez/profile1context.cpp \
- bluez/obex_client1_bluez5.cpp \
- bluez/obex_objectpush1_bluez5.cpp \
- bluez/obex_transfer1_bluez5.cpp \
- bluez/gattchar1.cpp \
- bluez/gattdesc1.cpp \
- bluez/gattservice1.cpp \
- bluez/battery1.cpp \
- bluez/hcimanager.cpp \
- bluez/remotedevicemanager.cpp \
- bluez/bluetoothmanagement.cpp
diff --git a/src/bluetooth/bluez/bluez5_helper.cpp b/src/bluetooth/bluez/bluez5_helper.cpp
index 7ce67690..3b74ee64 100644
--- a/src/bluetooth/bluez/bluez5_helper.cpp
+++ b/src/bluetooth/bluez/bluez5_helper.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtCore/QGlobalStatic>
#include <QtCore/QLoggingCategory>
@@ -47,58 +11,54 @@
#include "objectmanager_p.h"
#include "properties_p.h"
#include "adapter1_bluez5_p.h"
-#include "manager_p.h"
QT_BEGIN_NAMESPACE
+QT_IMPL_METATYPE_EXTERN(InterfaceList)
+QT_IMPL_METATYPE_EXTERN(ManufacturerDataList)
+QT_IMPL_METATYPE_EXTERN(ServiceDataList)
+QT_IMPL_METATYPE_EXTERN(ManagedObjectList)
+
+
Q_DECLARE_LOGGING_CATEGORY(QT_BT_BLUEZ)
typedef enum Bluez5TestResultType
{
BluezVersionUnknown,
- BluezVersion4,
BluezVersion5,
BluezNotAvailable
} Bluez5TestResult;
-Q_GLOBAL_STATIC_WITH_ARGS(Bluez5TestResult, bluezVersion, (BluezVersionUnknown));
-Q_GLOBAL_STATIC_WITH_ARGS(QVersionNumber, bluezDaemonVersion, (QVersionNumber()));
+Q_GLOBAL_STATIC_WITH_ARGS(Bluez5TestResult, bluezVersion, (BluezVersionUnknown))
+Q_GLOBAL_STATIC_WITH_ARGS(QVersionNumber, bluezDaemonVersion, (QVersionNumber()))
+
+/*
+ Ensures that the DBus types are registered
+ */
-bool isBluez5()
+void initializeBluez5()
{
if (*bluezVersion() == BluezVersionUnknown) {
OrgFreedesktopDBusObjectManagerInterface manager(QStringLiteral("org.bluez"),
QStringLiteral("/"),
QDBusConnection::systemBus());
-
qDBusRegisterMetaType<InterfaceList>();
qDBusRegisterMetaType<ManagedObjectList>();
qDBusRegisterMetaType<ManufacturerDataList>();
+ qDBusRegisterMetaType<ServiceDataList>();
QDBusPendingReply<ManagedObjectList> reply = manager.GetManagedObjects();
reply.waitForFinished();
if (reply.isError()) {
- // not Bluez 5.x
- OrgBluezManagerInterface manager_bluez4(QStringLiteral("org.bluez"),
- QStringLiteral("/"),
- QDBusConnection::systemBus());
- QDBusPendingReply<QList<QDBusObjectPath> > reply
- = manager_bluez4.ListAdapters();
- reply.waitForFinished();
- if (reply.isError()) {
- *bluezVersion() = BluezNotAvailable;
- qWarning() << "Cannot find a running Bluez. Please check the Bluez installation.";
- } else {
- *bluezVersion() = BluezVersion4;
- qCDebug(QT_BT_BLUEZ) << "Bluez 4 detected.";
- }
+ *bluezVersion() = BluezNotAvailable;
+ qWarning() << "Cannot find a compatible running Bluez. "
+ "Please check the Bluez installation. "
+ "QtBluetooth requires at least BlueZ version 5.";
} else {
*bluezVersion() = BluezVersion5;
qCDebug(QT_BT_BLUEZ) << "Bluez 5 detected.";
}
}
-
- return (*bluezVersion() == BluezVersion5);
}
/*
@@ -177,7 +137,7 @@ bool mandatoryHciIoctlsAvailable()
return true;
}
-/*!
+/*
* This function returns the version of bluetoothd in use on the system.
* This is required to determine which QLEControllerPrivate implementation
* is required. The following version tags are of significance:
@@ -201,6 +161,7 @@ QVersionNumber bluetoothdVersion()
qDBusRegisterMetaType<InterfaceList>();
qDBusRegisterMetaType<ManagedObjectList>();
qDBusRegisterMetaType<ManufacturerDataList>();
+ qDBusRegisterMetaType<ServiceDataList>();
qCDebug(QT_BT_BLUEZ) << "Detecting bluetoothd version";
//Order of matching
@@ -358,11 +319,7 @@ QtBluezDiscoveryManager::~QtBluezDiscoveryManager()
QtBluezDiscoveryManager *QtBluezDiscoveryManager::instance()
{
- if (isBluez5())
- return discoveryManager();
-
- Q_ASSERT(false);
- return nullptr;
+ return discoveryManager();
}
bool QtBluezDiscoveryManager::registerDiscoveryInterest(const QString &adapterPath)
@@ -380,8 +337,8 @@ bool QtBluezDiscoveryManager::registerDiscoveryInterest(const QString &adapterPa
OrgFreedesktopDBusPropertiesInterface *propIface = new OrgFreedesktopDBusPropertiesInterface(
QStringLiteral("org.bluez"), adapterPath, QDBusConnection::systemBus());
- connect(propIface, SIGNAL(PropertiesChanged(QString,QVariantMap,QStringList)),
- SLOT(PropertiesChanged(QString,QVariantMap,QStringList)));
+ connect(propIface, &OrgFreedesktopDBusPropertiesInterface::PropertiesChanged,
+ this, &QtBluezDiscoveryManager::PropertiesChanged);
data->propteryListener = propIface;
OrgBluezAdapter1Interface iface(QStringLiteral("org.bluez"), adapterPath,
@@ -444,7 +401,8 @@ void QtBluezDiscoveryManager::InterfacesRemoved(const QDBusObjectPath &object_pa
void QtBluezDiscoveryManager::PropertiesChanged(const QString &interface,
const QVariantMap &changed_properties,
- const QStringList &invalidated_properties)
+ const QStringList &invalidated_properties,
+ const QDBusMessage &)
{
Q_UNUSED(invalidated_properties);
@@ -489,7 +447,7 @@ void QtBluezDiscoveryManager::removeAdapterFromMonitoring(const QString &dbusPat
emit discoveryInterrupted(dbusPath);
}
-/*!
+/*
Finds the path for the local adapter with \a wantedAddress or an empty string
if no local adapter with the given address can be found.
If \a wantedAddress is \c null it returns the first/default adapter or an empty
@@ -545,7 +503,7 @@ QString findAdapterForAddress(const QBluetoothAddress &wantedAddress, bool *ok =
if (wantedAddress.isNull())
return localAdapters.front().first; // -> return first found adapter
- for (const AddressForPathType &pair : qAsConst(localAdapters)) {
+ for (const AddressForPathType &pair : std::as_const(localAdapters)) {
if (pair.second == wantedAddress)
return pair.first; // -> found local adapter with wanted address
}
@@ -554,6 +512,43 @@ QString findAdapterForAddress(const QBluetoothAddress &wantedAddress, bool *ok =
}
/*
+
+ Checks the presence of peripheral interface and returns path to the adapter
+
+*/
+
+QString adapterWithDBusPeripheralInterface(const QBluetoothAddress &localAddress)
+{
+ initializeBluez5();
+
+ // First find the object path to the desired adapter
+ bool ok = false;
+ const QString hostAdapterPath = findAdapterForAddress(localAddress, &ok);
+ if (!ok || hostAdapterPath.isEmpty())
+ return {};
+
+ // Then check if that adapter provides peripheral dbus interface
+ OrgFreedesktopDBusObjectManagerInterface manager(QStringLiteral("org.bluez"),
+ QStringLiteral("/"),
+ QDBusConnection::systemBus());
+ QDBusPendingReply<ManagedObjectList> reply = manager.GetManagedObjects();
+ reply.waitForFinished();
+ if (reply.isError())
+ return {};
+
+ using namespace Qt::StringLiterals;
+ // For example /org/bluez/hci0 contains org.bluezLEAdvertisingManager1
+ const bool peripheralSupported = reply.value()
+ .value(QDBusObjectPath(hostAdapterPath))
+ .contains("org.bluez.LEAdvertisingManager1"_L1);
+
+ qCDebug(QT_BT_BLUEZ) << "Peripheral role"
+ << (peripheralSupported ? "" : "not")
+ << "supported on" << hostAdapterPath;
+ return peripheralSupported ? hostAdapterPath : QString{};
+}
+
+/*
Removes every character that cannot be used in QDbusObjectPath
See QDbusUtil::isValidObjectPath(QString) for more details.
@@ -561,7 +556,7 @@ QString findAdapterForAddress(const QBluetoothAddress &wantedAddress, bool *ok =
QString sanitizeNameForDBus(const QString &text)
{
QString appName = text;
- for (int i = 0; i < appName.length(); i++) {
+ for (qsizetype i = 0; i < appName.size(); ++i) {
ushort us = appName[i].unicode();
bool valid = (us >= 'a' && us <= 'z')
|| (us >= 'A' && us <= 'Z')
@@ -576,3 +571,5 @@ QString sanitizeNameForDBus(const QString &text)
}
QT_END_NAMESPACE
+
+#include "moc_bluez5_helper_p.cpp"
diff --git a/src/bluetooth/bluez/bluez5_helper_p.h b/src/bluetooth/bluez/bluez5_helper_p.h
index 0db6f29f..f16566d4 100644
--- a/src/bluetooth/bluez/bluez5_helper_p.h
+++ b/src/bluetooth/bluez/bluez5_helper_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef BLUEZ5_HELPER_H
#define BLUEZ5_HELPER_H
@@ -53,28 +17,34 @@
#include <QtCore/QObject>
#include <QtDBus/QtDBus>
+#include <QtBluetooth/QBluetoothUuid>
#include <QtBluetooth/QBluetoothAddress>
#include <QtBluetooth/private/qtbluetoothglobal_p.h>
typedef QMap<QString, QVariantMap> InterfaceList;
typedef QMap<QDBusObjectPath, InterfaceList> ManagedObjectList;
typedef QMap<quint16, QDBusVariant> ManufacturerDataList;
+typedef QMap<QString, QDBusVariant> ServiceDataList;
-Q_DECLARE_METATYPE(InterfaceList)
-Q_DECLARE_METATYPE(ManufacturerDataList)
-Q_DECLARE_METATYPE(ManagedObjectList)
+QT_DECL_METATYPE_EXTERN(InterfaceList, /* not exported */)
+QT_DECL_METATYPE_EXTERN(ManufacturerDataList, /* not exported */)
+QT_DECL_METATYPE_EXTERN(ServiceDataList, /* not exported */)
+QT_DECL_METATYPE_EXTERN(ManagedObjectList, /* not exported */)
QT_BEGIN_NAMESPACE
+void initializeBluez5();
bool isBluez5();
// exported for unit test purposes
-Q_BLUETOOTH_PRIVATE_EXPORT QVersionNumber bluetoothdVersion();
+Q_BLUETOOTH_EXPORT QVersionNumber bluetoothdVersion();
QString sanitizeNameForDBus(const QString& text);
QString findAdapterForAddress(const QBluetoothAddress &wantedAddress, bool *ok);
+QString adapterWithDBusPeripheralInterface(const QBluetoothAddress &localAddress);
+
class QtBluezDiscoveryManagerPrivate;
class QtBluezDiscoveryManager : public QObject
{
@@ -97,7 +67,8 @@ private slots:
const QStringList &interfaces);
void PropertiesChanged(const QString &interface,
const QVariantMap &changed_properties,
- const QStringList &invalidated_properties);
+ const QStringList &invalidated_properties,
+ const QDBusMessage &msg);
private:
void removeAdapterFromMonitoring(const QString &dbusPath);
diff --git a/src/bluetooth/bluez/bluez_data.cpp b/src/bluetooth/bluez/bluez_data.cpp
new file mode 100644
index 00000000..8ffd23be
--- /dev/null
+++ b/src/bluetooth/bluez/bluez_data.cpp
@@ -0,0 +1,10 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "bluez_data_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QT_END_NAMESPACE
+
+#include "moc_bluez_data_p.cpp"
diff --git a/src/bluetooth/bluez/bluez_data_p.h b/src/bluetooth/bluez/bluez_data_p.h
index 2a2e597c..65ddeb97 100644
--- a/src/bluetooth/bluez/bluez_data_p.h
+++ b/src/bluetooth/bluez/bluez_data_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef BLUEZ_DATA_P_H
#define BLUEZ_DATA_P_H
@@ -51,10 +15,11 @@
// We mean it.
//
-#include <QtCore/qglobal.h>
+#include <QtCore/private/qglobal_p.h>
#include <QtCore/qendian.h>
#include <sys/socket.h>
#include <QtBluetooth/QBluetoothUuid>
+#include <QtCore/qtmetamacros.h>
QT_BEGIN_NAMESPACE
@@ -127,6 +92,9 @@ struct bt_security {
#define HCIGETDEVINFO _IOR('H', 211, int)
#define HCIGETDEVLIST _IOR('H', 210, int)
+// Generic 128 bits of data
+typedef QUuid::Id128Bytes BluezUint128;
+
// Bluetooth address
typedef struct {
quint8 b[6];
@@ -152,39 +120,6 @@ struct sockaddr_rc {
// Bt Low Energy related
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-
-static inline void btoh128(const quint128 *src, quint128 *dst)
-{
- memcpy(dst, src, sizeof(quint128));
-}
-
-static inline void ntoh128(const quint128 *src, quint128 *dst)
-{
- int i;
-
- for (i = 0; i < 16; i++)
- dst->data[15 - i] = src->data[i];
-}
-
-#elif __BYTE_ORDER == __BIG_ENDIAN
-
-static inline void btoh128(const quint128 *src, quint128 *dst)
-{
- int i;
-
- for (i = 0; i < 16; i++)
- dst->data[15 - i] = src->data[i];
-}
-
-static inline void ntoh128(const quint128 *src, quint128 *dst)
-{
- memcpy(dst, src, sizeof(quint128));
-}
-#else
-#error "Unknown byte order"
-#endif
-
template<typename T> inline T getBtData(const void *ptr)
{
return qFromLittleEndian<T>(reinterpret_cast<const uchar *>(ptr));
@@ -199,12 +134,6 @@ template<typename T> inline void putBtData(T src, void *dst)
{
qToLittleEndian(src, reinterpret_cast<uchar *>(dst));
}
-template<> inline void putBtData(quint128 src, void *dst)
-{
- btoh128(&src, reinterpret_cast<quint128 *>(dst));
-}
-
-#define hton128(x, y) ntoh128(x, y)
// HCI related
@@ -344,7 +273,6 @@ typedef struct {
} __attribute__ ((packed)) hci_event_hdr;
#define HCI_EVENT_HDR_SIZE 2
-#define EVT_ENCRYPT_CHANGE 0x08
typedef struct {
quint8 status;
quint16 handle;
@@ -352,7 +280,6 @@ typedef struct {
} __attribute__ ((packed)) evt_encrypt_change;
#define EVT_ENCRYPT_CHANGE_SIZE 4
-#define EVT_CMD_COMPLETE 0x0E
struct evt_cmd_complete {
quint8 ncmd;
quint16 opcode;
@@ -375,21 +302,88 @@ struct hci_command_hdr {
quint8 plen;
} __attribute__ ((packed));
-enum OpCodeGroupField {
- OgfLinkControl = 0x8,
-};
-
-enum OpCodeCommandField {
- OcfLeSetAdvParams = 0x6,
- OcfLeReadTxPowerLevel = 0x7,
- OcfLeSetAdvData = 0x8,
- OcfLeSetScanResponseData = 0x9,
- OcfLeSetAdvEnable = 0xa,
- OcfLeClearWhiteList = 0x10,
- OcfLeAddToWhiteList = 0x11,
- OcfLeConnectionUpdate = 0x13,
-};
-
+namespace QBluezConst {
+ Q_NAMESPACE
+ enum OpCodeGroupField {
+ OgfLinkControl = 0x8,
+ };
+ Q_ENUM_NS(OpCodeGroupField)
+
+ enum OpCodeCommandField {
+ OcfLeSetAdvParams = 0x6,
+ OcfLeReadTxPowerLevel = 0x7,
+ OcfLeSetAdvData = 0x8,
+ OcfLeSetScanResponseData = 0x9,
+ OcfLeSetAdvEnable = 0xa,
+ OcfLeClearWhiteList = 0x10,
+ OcfLeAddToWhiteList = 0x11,
+ OcfLeConnectionUpdate = 0x13,
+ };
+ Q_ENUM_NS(OpCodeCommandField)
+
+ enum class AttCommand : quint8 {
+ ATT_OP_ERROR_RESPONSE = 0x01,
+ ATT_OP_EXCHANGE_MTU_REQUEST = 0x02, //send own mtu
+ ATT_OP_EXCHANGE_MTU_RESPONSE = 0x03, //receive server MTU
+ ATT_OP_FIND_INFORMATION_REQUEST = 0x04, //discover individual attribute info
+ ATT_OP_FIND_INFORMATION_RESPONSE = 0x05,
+ ATT_OP_FIND_BY_TYPE_VALUE_REQUEST = 0x06,
+ ATT_OP_FIND_BY_TYPE_VALUE_RESPONSE = 0x07,
+ ATT_OP_READ_BY_TYPE_REQUEST = 0x08, //discover characteristics
+ ATT_OP_READ_BY_TYPE_RESPONSE = 0x09,
+ ATT_OP_READ_REQUEST = 0x0A, //read characteristic & descriptor values
+ ATT_OP_READ_RESPONSE = 0x0B,
+ ATT_OP_READ_BLOB_REQUEST = 0x0C, //read values longer than MTU-1
+ ATT_OP_READ_BLOB_RESPONSE = 0x0D,
+ ATT_OP_READ_MULTIPLE_REQUEST = 0x0E,
+ ATT_OP_READ_MULTIPLE_RESPONSE = 0x0F,
+ ATT_OP_READ_BY_GROUP_REQUEST = 0x10, //discover services
+ ATT_OP_READ_BY_GROUP_RESPONSE = 0x11,
+ ATT_OP_WRITE_REQUEST = 0x12, //write characteristic with response
+ ATT_OP_WRITE_RESPONSE = 0x13,
+ ATT_OP_PREPARE_WRITE_REQUEST = 0x16, //write values longer than MTU-3 -> queueing
+ ATT_OP_PREPARE_WRITE_RESPONSE = 0x17,
+ ATT_OP_EXECUTE_WRITE_REQUEST = 0x18, //write values longer than MTU-3 -> execute queue
+ ATT_OP_EXECUTE_WRITE_RESPONSE = 0x19,
+ ATT_OP_HANDLE_VAL_NOTIFICATION = 0x1b, //informs about value change
+ ATT_OP_HANDLE_VAL_INDICATION = 0x1d, //informs about value change -> requires reply
+ ATT_OP_HANDLE_VAL_CONFIRMATION = 0x1e, //answer for ATT_OP_HANDLE_VAL_INDICATION
+ ATT_OP_WRITE_COMMAND = 0x52, //write characteristic without response
+ ATT_OP_SIGNED_WRITE_COMMAND = 0xD2
+ };
+ Q_ENUM_NS(AttCommand)
+
+ enum class AttError : quint8 {
+ ATT_ERROR_NO_ERROR = 0x00,
+ ATT_ERROR_INVALID_HANDLE = 0x01,
+ ATT_ERROR_READ_NOT_PERM = 0x02,
+ ATT_ERROR_WRITE_NOT_PERM = 0x03,
+ ATT_ERROR_INVALID_PDU = 0x04,
+ ATT_ERROR_INSUF_AUTHENTICATION = 0x05,
+ ATT_ERROR_REQUEST_NOT_SUPPORTED = 0x06,
+ ATT_ERROR_INVALID_OFFSET = 0x07,
+ ATT_ERROR_INSUF_AUTHORIZATION = 0x08,
+ ATT_ERROR_PREPARE_QUEUE_FULL = 0x09,
+ ATT_ERROR_ATTRIBUTE_NOT_FOUND = 0x0A,
+ ATT_ERROR_ATTRIBUTE_NOT_LONG = 0x0B,
+ ATT_ERROR_INSUF_ENCR_KEY_SIZE = 0x0C,
+ ATT_ERROR_INVAL_ATTR_VALUE_LEN = 0x0D,
+ ATT_ERROR_UNLIKELY = 0x0E,
+ ATT_ERROR_INSUF_ENCRYPTION = 0x0F,
+ ATT_ERROR_UNSUPPRTED_GROUP_TYPE = 0x10,
+ ATT_ERROR_INSUF_RESOURCES = 0x11,
+ ATT_ERROR_APPLICATION_START = 0x80,
+ //------------------------------------------
+ // The error codes in this block are
+ // implementation specific errors
+
+ ATT_ERROR_REQUEST_STALLED = 0x81,
+
+ //------------------------------------------
+ ATT_ERROR_APPLICATION_END = 0x9f
+ };
+ Q_ENUM_NS(AttError)
+}
/* Command opcode pack/unpack */
#define opCodePack(ogf, ocf) (quint16(((ocf) & 0x03ff)|((ogf) << 10)))
#define ogfFromOpCode(op) ((op) >> 10)
diff --git a/src/bluetooth/bluez/bluezperipheralapplication.cpp b/src/bluetooth/bluez/bluezperipheralapplication.cpp
new file mode 100644
index 00000000..5a8e4899
--- /dev/null
+++ b/src/bluetooth/bluez/bluezperipheralapplication.cpp
@@ -0,0 +1,280 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "bluezperipheralapplication_p.h"
+#include "bluezperipheralobjects_p.h"
+#include "objectmanageradaptor_p.h"
+#include "gattmanager1_p.h"
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_LOGGING_CATEGORY(QT_BT_BLUEZ)
+
+using namespace Qt::StringLiterals;
+
+static constexpr QLatin1String appObjectPathTemplate{"/qt/btle/application/%1%2/%3"};
+
+QtBluezPeripheralApplication::QtBluezPeripheralApplication(const QString& hostAdapterPath,
+ QObject* parent)
+ : QObject(parent),
+ m_objectPath(QString(appObjectPathTemplate).
+ arg(sanitizeNameForDBus(QCoreApplication::applicationName())).
+ arg(QCoreApplication::applicationPid()).
+ arg(QRandomGenerator::global()->generate()))
+{
+ m_objectManager = new OrgFreedesktopDBusObjectManagerAdaptor(this);
+ m_gattManager = new OrgBluezGattManager1Interface("org.bluez"_L1, hostAdapterPath,
+ QDBusConnection::systemBus(), this);
+}
+
+QtBluezPeripheralApplication::~QtBluezPeripheralApplication()
+{
+ unregisterApplication();
+}
+
+void QtBluezPeripheralApplication::registerApplication()
+{
+ if (m_applicationRegistered) {
+ // Can happen eg. if advertisement is start-stop-started
+ qCDebug(QT_BT_BLUEZ) << "Bluez peripheral application already registered";
+ return;
+ }
+
+ if (m_services.isEmpty()) {
+ // Registering the application to bluez without services would fail
+ qCDebug(QT_BT_BLUEZ) << "No services, omiting Bluez peripheral application registration";
+ return;
+ }
+
+ qCDebug(QT_BT_BLUEZ) << "Registering bluez peripheral application:" << m_objectPath;
+
+ // Register this application object on DBus
+ if (!QDBusConnection::systemBus().registerObject(m_objectPath, m_objectManager,
+ QDBusConnection::ExportAllContents)) {
+ qCWarning(QT_BT_BLUEZ) << "Peripheral application object registration failed";
+ emit errorOccurred();
+ return;
+ }
+
+ // Register the service objects on DBus
+ registerServices();
+
+ // Register the gatt application to Bluez. After successful registration Bluez
+ // is aware of this peripheral application and will inquiry which services this application
+ // provides, see GetManagedObjects()
+ auto reply = m_gattManager->RegisterApplication(QDBusObjectPath(m_objectPath), {});
+ QDBusPendingCallWatcher* watcher = new QDBusPendingCallWatcher(reply, this);
+ QObject::connect(watcher, &QDBusPendingCallWatcher::finished, this,
+ [this](QDBusPendingCallWatcher* watcher) {
+ QDBusPendingReply<> reply = *watcher;
+ if (reply.isError()) {
+ qCWarning(QT_BT_BLUEZ) << "Application registration failed" << reply.error();
+ QDBusConnection::systemBus().unregisterObject(m_objectPath);
+ emit errorOccurred();
+ } else {
+ qCDebug(QT_BT_BLUEZ) << "Peripheral application registered as" << m_objectPath;
+ m_applicationRegistered = true;
+ emit registered();
+ }
+ watcher->deleteLater();
+ });
+}
+
+void QtBluezPeripheralApplication::unregisterApplication()
+{
+ if (!m_applicationRegistered)
+ return;
+ m_applicationRegistered = false;
+ auto reply = m_gattManager->UnregisterApplication(QDBusObjectPath(m_objectPath));
+ reply.waitForFinished();
+ if (reply.isError())
+ qCWarning(QT_BT_BLUEZ) << "Error in unregistering peripheral application";
+ else
+ qCDebug(QT_BT_BLUEZ) << "Peripheral application unregistered successfully";
+ QDBusConnection::systemBus().unregisterObject(m_objectPath);
+ unregisterServices();
+
+ qCDebug(QT_BT_BLUEZ) << "Unregistered Bluez peripheral application on DBus:" << m_objectPath;
+}
+
+void QtBluezPeripheralApplication::registerServices()
+{
+ // Register the service objects on DBus
+ for (const auto service: std::as_const(m_services))
+ service->registerObject();
+ for (const auto& characteristic : std::as_const(m_characteristics))
+ characteristic->registerObject();
+ for (const auto& descriptor : std::as_const(m_descriptors))
+ descriptor->registerObject();
+}
+
+void QtBluezPeripheralApplication::unregisterServices()
+{
+ // Unregister the service objects from DBus
+ for (const auto service: std::as_const(m_services))
+ service->unregisterObject();
+ for (const auto& characteristic : std::as_const(m_characteristics))
+ characteristic->unregisterObject();
+ for (const auto& descriptor : std::as_const(m_descriptors))
+ descriptor->unregisterObject();
+}
+
+void QtBluezPeripheralApplication::reset()
+{
+ unregisterApplication();
+
+ qDeleteAll(m_services);
+ m_services.clear();
+ qDeleteAll(m_descriptors);
+ m_descriptors.clear();
+ qDeleteAll(m_characteristics);
+ m_characteristics.clear();
+}
+
+void QtBluezPeripheralApplication::addService(const QLowEnergyServiceData &serviceData,
+ QSharedPointer<QLowEnergyServicePrivate> servicePrivate,
+ QLowEnergyHandle serviceHandle)
+{
+ if (m_applicationRegistered) {
+ qCWarning(QT_BT_BLUEZ) << "Adding services to a registered application is not supported "
+ "on Bluez DBus. Add services only before first advertisement or "
+ "after disconnection";
+ return;
+ }
+
+ // The ordinal numbers in the below object creation are used to create paths such as:
+ // ../service0/char0/desc0
+ // ../service0/char1/desc0
+ // ../service1/char0/desc0
+ // ../service1/char0/desc1
+ // For the Service object itself the ordinal number is the size of the service container
+ QtBluezPeripheralService* service = new QtBluezPeripheralService(
+ serviceData, m_objectPath, m_services.size(), serviceHandle, this);
+ m_services.insert(serviceHandle, service);
+
+ // Add included services
+ for (const auto includedService : serviceData.includedServices()) {
+ // As per Qt documentation the included service must have been added earlier
+ for (const auto s : std::as_const(m_services)) {
+ if (QBluetoothUuid(s->uuid) == includedService->serviceUuid()) {
+ service->addIncludedService(s->objectPath);
+ }
+ }
+ }
+
+ // Set characteristics and their descriptors
+ quint16 characteristicOrdinal{0};
+ for (const auto& characteristicData : serviceData.characteristics()) {
+ auto characteristicHandle = handleForCharacteristic(
+ characteristicData.uuid(), servicePrivate);
+ QtBluezPeripheralCharacteristic* characteristic =
+ new QtBluezPeripheralCharacteristic(characteristicData,
+ service->objectPath, characteristicOrdinal++,
+ characteristicHandle, this);
+ m_characteristics.insert(characteristicHandle, characteristic);
+ QObject::connect(characteristic, &QtBluezPeripheralCharacteristic::valueUpdatedByRemote,
+ this, &QtBluezPeripheralApplication::characteristicValueUpdatedByRemote);
+ QObject::connect(characteristic, &QtBluezPeripheralCharacteristic::remoteDeviceAccessEvent,
+ this, &QtBluezPeripheralApplication::remoteDeviceAccessEvent);
+
+ quint16 descriptorOrdinal{0};
+ for (const auto& descriptorData : characteristicData.descriptors()) {
+ // With bluez we don't use the CCCD user has provided, because Bluez
+ // generates it if 'notify/indicate' flag is set. Similarly the extended properties
+ // descriptor is generated by Bluez if the related flags are set. Using the application
+ // provided descriptors would result in duplicate descriptors.
+ if (descriptorData.uuid()
+ == QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration
+ || descriptorData.uuid()
+ == QBluetoothUuid::DescriptorType::CharacteristicExtendedProperties) {
+ continue;
+ }
+ auto descriptorHandle = handleForDescriptor(descriptorData.uuid(),
+ servicePrivate,
+ characteristicHandle);
+ QtBluezPeripheralDescriptor* descriptor =
+ new QtBluezPeripheralDescriptor(descriptorData,
+ characteristic->objectPath, descriptorOrdinal++,
+ descriptorHandle, characteristicHandle, this);
+ QObject::connect(descriptor, &QtBluezPeripheralDescriptor::valueUpdatedByRemote,
+ this, &QtBluezPeripheralApplication::descriptorValueUpdatedByRemote);
+ QObject::connect(descriptor, &QtBluezPeripheralCharacteristic::remoteDeviceAccessEvent,
+ this, &QtBluezPeripheralApplication::remoteDeviceAccessEvent);
+ m_descriptors.insert(descriptorHandle, descriptor);
+ }
+ }
+}
+
+// This function is called when characteristic is written to from Qt API
+bool QtBluezPeripheralApplication::localCharacteristicWrite(QLowEnergyHandle handle,
+ const QByteArray& value)
+{
+ auto characteristic = m_characteristics.value(handle);
+ if (!characteristic) {
+ qCWarning(QT_BT_BLUEZ) << "DBus characteristic not found for write";
+ return false;
+ }
+ return characteristic->localValueUpdate(value);
+}
+
+// This function is called when characteristic is written to from Qt API
+bool QtBluezPeripheralApplication::localDescriptorWrite(QLowEnergyHandle handle,
+ const QByteArray& value)
+{
+ auto descriptor = m_descriptors.value(handle);
+ if (!descriptor) {
+ qCWarning(QT_BT_BLUEZ) << "DBus descriptor not found for write";
+ return false;
+ }
+ return descriptor->localValueUpdate(value);
+}
+
+bool QtBluezPeripheralApplication::registrationNeeded()
+{
+ return !m_applicationRegistered && !m_services.isEmpty();
+}
+
+// org.freedesktop.DBus.ObjectManager
+// This is called by Bluez when we register the application
+ManagedObjectList QtBluezPeripheralApplication::GetManagedObjects()
+{
+ ManagedObjectList managedObjects;
+ for (const auto service: std::as_const(m_services))
+ managedObjects.insert(QDBusObjectPath(service->objectPath), service->properties());
+ for (const auto& charac : std::as_const(m_characteristics))
+ managedObjects.insert(QDBusObjectPath(charac->objectPath), charac->properties());
+ for (const auto& descriptor : std::as_const(m_descriptors))
+ managedObjects.insert(QDBusObjectPath(descriptor->objectPath), descriptor->properties());
+
+ return managedObjects;
+}
+
+// Returns the Qt-internal handle for the characteristic
+QLowEnergyHandle QtBluezPeripheralApplication::handleForCharacteristic(QBluetoothUuid uuid,
+ QSharedPointer<QLowEnergyServicePrivate> service)
+{
+ const auto handles = service->characteristicList.keys();
+ for (const auto handle : handles) {
+ if (uuid == service->characteristicList[handle].uuid)
+ return handle;
+ }
+ return 0;
+}
+
+// Returns the Qt-internal handle for the descriptor
+QLowEnergyHandle QtBluezPeripheralApplication::handleForDescriptor(QBluetoothUuid uuid,
+ QSharedPointer<QLowEnergyServicePrivate> service,
+ QLowEnergyHandle characteristicHandle)
+{
+ const auto characteristicData = service->characteristicList[characteristicHandle];
+ const auto handles = characteristicData.descriptorList.keys();
+ for (const auto handle : handles) {
+ if (uuid == characteristicData.descriptorList[handle].uuid)
+ return handle;
+ }
+ return 0;
+}
+
+QT_END_NAMESPACE
+
+#include "moc_bluezperipheralapplication_p.cpp"
diff --git a/src/bluetooth/bluez/bluezperipheralapplication_p.h b/src/bluetooth/bluez/bluezperipheralapplication_p.h
new file mode 100644
index 00000000..1b8287b9
--- /dev/null
+++ b/src/bluetooth/bluez/bluezperipheralapplication_p.h
@@ -0,0 +1,100 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef BLUEZ_PERIPHERAL_APPLICATION_P_H
+#define BLUEZ_PERIPHERAL_APPLICATION_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtBluetooth/private/qlowenergycontroller_bluezdbus_p.h>
+#include "bluez5_helper_p.h"
+
+#include <QtBluetooth/QBluetoothAddress>
+#include <QtCore/QCoreApplication>
+
+class OrgFreedesktopDBusObjectManagerAdaptor;
+class OrgBluezGattManager1Interface;
+
+QT_BEGIN_NAMESPACE
+
+class QLowEnergyControllerPrivateBluezDBus;
+class QtBluezPeripheralService;
+class QtBluezPeripheralCharacteristic;
+class QtBluezPeripheralDescriptor;
+class QtBluezPeripheralConnectionManager;
+
+class QtBluezPeripheralApplication : public QObject
+{
+ Q_OBJECT
+
+public:
+ QtBluezPeripheralApplication(const QString& localAdapterPath, QObject* parent = nullptr);
+ ~QtBluezPeripheralApplication();
+
+ // Register the application and its services to DBus & Bluez
+ void registerApplication();
+ // Unregister the application and its services from DBus & Bluez.
+ // Calling this doesn't invalidate the services
+ void unregisterApplication();
+ // Unregister and release all resources, invalidates services
+ void reset();
+
+ void addService(const QLowEnergyServiceData &serviceData,
+ QSharedPointer<QLowEnergyServicePrivate> servicePrivate,
+ QLowEnergyHandle serviceHandle);
+
+ // Call these when the user application has updated the attribute value
+ // Returns whether the new value was accepted
+ bool localCharacteristicWrite(QLowEnergyHandle handle, const QByteArray& value);
+ bool localDescriptorWrite(QLowEnergyHandle handle, const QByteArray& value);
+
+ // Returns true if application has services and is not registered
+ bool registrationNeeded();
+
+ // org.freedesktop.DBus.ObjectManager
+ Q_INVOKABLE ManagedObjectList GetManagedObjects();
+
+signals:
+ void errorOccurred();
+ void registered();
+
+ // Emitted when remote device reads a characteristic
+ void remoteDeviceAccessEvent(const QString& remoteDeviceObjectPath, quint16 mtu);
+
+ // These are emitted when remote has written a new value
+ void characteristicValueUpdatedByRemote(QLowEnergyHandle handle, const QByteArray& value);
+ void descriptorValueUpdatedByRemote(QLowEnergyHandle characteristicHandle,
+ QLowEnergyHandle descriptorHandle,
+ const QByteArray& value);
+private:
+ void registerServices();
+ void unregisterServices();
+
+ QLowEnergyHandle handleForCharacteristic(QBluetoothUuid uuid,
+ QSharedPointer<QLowEnergyServicePrivate> service);
+ QLowEnergyHandle handleForDescriptor(QBluetoothUuid uuid,
+ QSharedPointer<QLowEnergyServicePrivate> service,
+ QLowEnergyHandle characteristicHandle);
+
+ QMap<QLowEnergyHandle, QtBluezPeripheralService*> m_services;
+ QMap<QLowEnergyHandle, QtBluezPeripheralCharacteristic*> m_characteristics;
+ QMap<QLowEnergyHandle, QtBluezPeripheralDescriptor*> m_descriptors;
+
+ QString m_objectPath;
+ OrgFreedesktopDBusObjectManagerAdaptor* m_objectManager{};
+ OrgBluezGattManager1Interface* m_gattManager{};
+ bool m_applicationRegistered{false};
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/bluetooth/bluez/bluezperipheralconnectionmanager.cpp b/src/bluetooth/bluez/bluezperipheralconnectionmanager.cpp
new file mode 100644
index 00000000..64350d2d
--- /dev/null
+++ b/src/bluetooth/bluez/bluezperipheralconnectionmanager.cpp
@@ -0,0 +1,96 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "bluezperipheralconnectionmanager_p.h"
+#include "device1_bluez5_p.h"
+
+#include <QtBluetooth/QBluetoothLocalDevice>
+#include <QtDBus/QDBusConnection>
+#include <QtCore/QLoggingCategory>
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_LOGGING_CATEGORY(QT_BT_BLUEZ)
+
+using namespace Qt::StringLiterals;
+
+QtBluezPeripheralConnectionManager::QtBluezPeripheralConnectionManager(
+ const QBluetoothAddress& localAddress, QObject* parent)
+ : QObject(parent),
+ m_localDevice(new QBluetoothLocalDevice(localAddress, this))
+{
+ QObject::connect(m_localDevice, &QBluetoothLocalDevice::deviceDisconnected,
+ this, &QtBluezPeripheralConnectionManager::remoteDeviceDisconnected);
+}
+
+void QtBluezPeripheralConnectionManager::remoteDeviceAccessEvent(
+ const QString& remoteDeviceObjectPath, quint16 mtu)
+{
+ if (m_clients.contains(remoteDeviceObjectPath))
+ return; // Already aware of the client
+
+ std::unique_ptr<OrgBluezDevice1Interface> device{new OrgBluezDevice1Interface(
+ "org.bluez"_L1, remoteDeviceObjectPath,
+ QDBusConnection::systemBus(), this)};
+
+ qCDebug(QT_BT_BLUEZ) << "New LE Gatt client connected: " << remoteDeviceObjectPath
+ << device->address() << device->name() << "mtu:" << mtu;
+
+ RemoteDeviceDetails details{QBluetoothAddress{device->address()}, device->name(), mtu};
+
+ m_clients.insert(remoteDeviceObjectPath, details);
+ if (!m_connected) {
+ m_connected = true;
+ emit connectivityStateChanged(true);
+ }
+ emit remoteDeviceChanged(details.address, details.name, details.mtu);
+}
+
+void QtBluezPeripheralConnectionManager::remoteDeviceDisconnected(const QBluetoothAddress& address)
+{
+ // Find if the disconnected device was gatt client
+ bool remoteDetailsChanged{false};
+ for (auto it = m_clients.begin(); it != m_clients.end(); it++) {
+ if (it.value().address == address) {
+ qCDebug(QT_BT_BLUEZ) << "LE Gatt client disconnected:" << address;
+ remoteDetailsChanged = true;
+ m_clients.remove(it.key());
+ break;
+ }
+ }
+
+ if (!remoteDetailsChanged)
+ return;
+
+ if (m_clients.isEmpty() && m_connected) {
+ m_connected = false;
+ emit connectivityStateChanged(false);
+ }
+
+ // If a client disconnected but there are others, pick any other.
+ // Qt API doesn't distinguish between clients
+ if (!m_clients.isEmpty()) {
+ emit remoteDeviceChanged(m_clients.last().address,
+ m_clients.last().name, m_clients.last().mtu);
+ }
+}
+
+void QtBluezPeripheralConnectionManager::disconnectDevices()
+{
+ for (auto it = m_clients.begin(); it != m_clients.end(); it++) {
+ std::unique_ptr<OrgBluezDevice1Interface> device{new OrgBluezDevice1Interface(
+ "org.bluez"_L1, it.key(), QDBusConnection::systemBus())};
+ device->Disconnect();
+ }
+ reset();
+}
+
+void QtBluezPeripheralConnectionManager::reset()
+{
+ m_connected = false;
+ m_clients.clear();
+}
+
+QT_END_NAMESPACE
+
+#include "moc_bluezperipheralconnectionmanager_p.cpp"
diff --git a/src/bluetooth/bluez/bluezperipheralconnectionmanager_p.h b/src/bluetooth/bluez/bluezperipheralconnectionmanager_p.h
new file mode 100644
index 00000000..42e839cc
--- /dev/null
+++ b/src/bluetooth/bluez/bluezperipheralconnectionmanager_p.h
@@ -0,0 +1,68 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef BLUEZ_PERIPHERAL_CONNECTION_MANAGER_P_H
+#define BLUEZ_PERIPHERAL_CONNECTION_MANAGER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtBluetooth/QBluetoothAddress>
+#include <QtBluetooth/QBluetoothUuid>
+#include <QtCore/QObject>
+
+QT_BEGIN_NAMESPACE
+
+class QBluetoothLocalDevice;
+
+/*
+ QtBluezPeripheralConnectionManager determines
+ - when remote Gatt client(s) connect and disconnect
+ - the remote device details (name, address, mtu)
+
+ 'Connected' state is assumed when first client reads a characteristic.
+ 'Disconnected' state is assumed when all such clients have disconnected.
+*/
+
+class QtBluezPeripheralConnectionManager : public QObject
+{
+ Q_OBJECT
+public:
+ QtBluezPeripheralConnectionManager(const QBluetoothAddress& localAddress,
+ QObject* parent = nullptr);
+ void reset();
+ void disconnectDevices();
+
+public slots:
+ void remoteDeviceAccessEvent(const QString& remoteDeviceObjectPath, quint16 mtu);
+
+signals:
+ void connectivityStateChanged(bool connected);
+ void remoteDeviceChanged(const QBluetoothAddress& address, const QString& name, quint16 mtu);
+
+private slots:
+ void remoteDeviceDisconnected(const QBluetoothAddress& address);
+
+private:
+ struct RemoteDeviceDetails {
+ QBluetoothAddress address;
+ QString name;
+ quint16 mtu;
+ };
+ bool m_connected{false};
+ QString m_hostAdapterPath;
+ QMap<QString, RemoteDeviceDetails> m_clients;
+ QBluetoothLocalDevice* m_localDevice;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/bluetooth/bluez/bluezperipheralobjects.cpp b/src/bluetooth/bluez/bluezperipheralobjects.cpp
new file mode 100644
index 00000000..1caa42cd
--- /dev/null
+++ b/src/bluetooth/bluez/bluezperipheralobjects.cpp
@@ -0,0 +1,403 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "bluezperipheralobjects_p.h"
+
+#include "propertiesadaptor_p.h"
+#include "gattservice1adaptor_p.h"
+#include "gattcharacteristic1adaptor_p.h"
+#include "gattdescriptor1adaptor_p.h"
+
+#include <QtCore/QLoggingCategory>
+#include <QtDBus/QDBusConnection>
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_LOGGING_CATEGORY(QT_BT_BLUEZ)
+
+using namespace Qt::StringLiterals;
+
+static constexpr auto characteristicPathTemplate{"%1/char%2"_L1};
+static constexpr auto descriptorPathTemplate{"%1/desc%2"_L1};
+static constexpr auto servicePathTemplate{"%1/service%2"_L1};
+
+// The interface names and error values are from BlueZ "gatt-api" documentation
+static constexpr auto bluezServiceInterface{"org.bluez.GattService1"_L1};
+static constexpr auto bluezCharacteristicInterface{"org.bluez.GattCharacteristic1"_L1};
+static constexpr auto bluezDescriptorInterface{"org.bluez.GattDescriptor1"_L1};
+
+static constexpr auto bluezErrorInvalidValueLength{"org.bluez.Error.InvalidValueLength"_L1};
+static constexpr auto bluezErrorInvalidOffset{"org.bluez.Error.InvalidOffset"_L1};
+static constexpr auto bluezErrorNotAuthorized{"org.bluez.Error.NotAuthorized"_L1};
+// Bluetooth Core v5.3, 3.2.9, Vol 3, Part F
+static constexpr int maximumAttributeLength{512};
+
+
+QtBluezPeripheralGattObject::QtBluezPeripheralGattObject(const QString& objectPath,
+ const QString& uuid, QLowEnergyHandle handle, QObject* parent)
+ : QObject(parent), objectPath(objectPath), uuid(uuid), handle(handle),
+ propertiesAdaptor(new OrgFreedesktopDBusPropertiesAdaptor(this))
+{}
+
+QtBluezPeripheralGattObject::~QtBluezPeripheralGattObject()
+{
+ unregisterObject();
+}
+
+bool QtBluezPeripheralGattObject::registerObject()
+{
+ if (m_registered)
+ return true;
+
+ if (QDBusConnection::systemBus().registerObject(objectPath, this)) {
+ qCDebug(QT_BT_BLUEZ) << "Registered object on DBus:" << objectPath << uuid;
+ m_registered = true;
+ return true;
+ } else {
+ qCWarning(QT_BT_BLUEZ) << "Failed to register object on DBus:" << objectPath << uuid;
+ return false;
+ }
+}
+
+void QtBluezPeripheralGattObject::unregisterObject()
+{
+ if (!m_registered)
+ return;
+ QDBusConnection::systemBus().unregisterObject(objectPath);
+ qCDebug(QT_BT_BLUEZ) << "Unregistered object on DBus:" << objectPath << uuid;
+ m_registered = false;
+}
+
+void QtBluezPeripheralGattObject::accessEvent(const QVariantMap& options)
+{
+ // Report this event for connection management purposes
+ const auto remoteDevice = options.value("device"_L1).value<QDBusObjectPath>().path();
+ if (!remoteDevice.isEmpty())
+ emit remoteDeviceAccessEvent(remoteDevice, options.value("mtu"_L1).toUInt());
+}
+
+QtBluezPeripheralDescriptor::QtBluezPeripheralDescriptor(
+ const QLowEnergyDescriptorData& descriptorData,
+ const QString& characteristicPath, quint16 ordinal,
+ QLowEnergyHandle handle, QLowEnergyHandle characteristicHandle,
+ QObject* parent)
+ : QtBluezPeripheralGattObject(descriptorPathTemplate.arg(characteristicPath).arg(ordinal),
+ descriptorData.uuid().toString(QUuid::WithoutBraces), handle, parent),
+ m_adaptor(new OrgBluezGattDescriptor1Adaptor(this)),
+ m_characteristicPath(characteristicPath),
+ m_characteristicHandle(characteristicHandle)
+{
+ if (descriptorData.value().size() > maximumAttributeLength) {
+ qCWarning(QT_BT_BLUEZ) << "Descriptor value is too large, cropping it to"
+ << maximumAttributeLength;
+ m_value = descriptorData.value().sliced(0, maximumAttributeLength);
+ } else {
+ m_value = descriptorData.value();
+ }
+ initializeFlags(descriptorData);
+}
+
+InterfaceList QtBluezPeripheralDescriptor::properties() const
+{
+ InterfaceList properties;
+ properties.insert(bluezDescriptorInterface,
+ {
+ {"UUID"_L1, uuid},
+ {"Characteristic"_L1, QDBusObjectPath(m_characteristicPath)},
+ {"Flags"_L1, m_flags}
+ });
+ return properties;
+}
+
+// org.bluez.GattDescriptor1
+// This function is invoked when remote device reads the value
+QByteArray QtBluezPeripheralDescriptor::ReadValue(const QVariantMap &options, QString& error)
+{
+ accessEvent(options);
+ // Offset is set by Bluez when the value size is more than MTU size.
+ // Bluez deduces the value size from the first ReadValue. If the
+ // received data size is larger than MTU, Bluez will take the first MTU bytes and
+ // issue more ReadValue calls with the 'offset' set
+ const quint16 offset = options.value("offset"_L1).toUInt();
+ const quint16 mtu = options.value("mtu"_L1).toUInt();
+
+ if (offset > m_value.length() - 1) {
+ qCWarning(QT_BT_BLUEZ) << "Invalid offset" << offset << ", value len:" << m_value.length();
+ error = bluezErrorInvalidOffset;
+ return {};
+ }
+
+ if (offset > 0)
+ return m_value.mid(offset, mtu);
+ else
+ return m_value;
+}
+
+// org.bluez.GattDescriptor1
+// This function is invoked when remote device writes a value
+QString QtBluezPeripheralDescriptor::WriteValue(const QByteArray &value,
+ const QVariantMap &options)
+{
+ accessEvent(options);
+
+ if (options.value("prepare-authorize"_L1).toBool()) {
+ // Qt API doesn't provide the means for application to authorize
+ qCWarning(QT_BT_BLUEZ) << "Descriptor write requires authorization."
+ << "The client device needs to be trusted beforehand";
+ return bluezErrorNotAuthorized;
+ }
+
+ if (value.size() > maximumAttributeLength) {
+ qCWarning(QT_BT_BLUEZ) << "Descriptor value is too large:" << value.size();
+ return bluezErrorInvalidValueLength;
+ }
+ m_value = value;
+ emit valueUpdatedByRemote(m_characteristicHandle, handle, value);
+ return {};
+}
+
+// This function is called when the value has been updated locally (server-side)
+bool QtBluezPeripheralDescriptor::localValueUpdate(const QByteArray& value)
+{
+ if (value.size() > maximumAttributeLength) {
+ qCWarning(QT_BT_BLUEZ) << "Descriptor value is too large:" << value.size();
+ return false;
+ }
+ m_value = value;
+ return true;
+}
+
+void QtBluezPeripheralDescriptor::initializeFlags(const QLowEnergyDescriptorData& data)
+{
+ // Flag tokens are from org.bluez.GattDescriptor1 documentation
+ if (data.isReadable())
+ m_flags.append("read"_L1);
+ if (data.readConstraints() & QBluetooth::AttAccessConstraint::AttEncryptionRequired)
+ m_flags.append("encrypt-read"_L1);
+ if (data.readConstraints() & QBluetooth::AttAccessConstraint::AttAuthenticationRequired)
+ m_flags.append("encrypt-authenticated-read"_L1);
+
+ if (data.isWritable())
+ m_flags.append("write"_L1);
+ if (data.writeConstraints() & QBluetooth::AttAccessConstraint::AttEncryptionRequired)
+ m_flags.append("encrypt-write"_L1);
+ if (data.writeConstraints() & QBluetooth::AttAccessConstraint::AttAuthenticationRequired)
+ m_flags.append("encrypt-authenticated-write"_L1);
+
+ if (data.readConstraints() & QBluetooth::AttAccessConstraint::AttAuthorizationRequired
+ || data.writeConstraints() & QBluetooth::AttAccessConstraint::AttAuthorizationRequired)
+ m_flags.append("authorize"_L1);
+
+ if (m_flags.isEmpty()) {
+ qCWarning(QT_BT_BLUEZ) << "Descriptor property flags not set" << uuid
+ << "Peripheral may fail to register";
+ }
+}
+
+QtBluezPeripheralCharacteristic::QtBluezPeripheralCharacteristic(
+ const QLowEnergyCharacteristicData& characteristicData,
+ const QString& servicePath, quint16 ordinal,
+ QLowEnergyHandle handle, QObject* parent)
+ : QtBluezPeripheralGattObject(characteristicPathTemplate.arg(servicePath).arg(ordinal),
+ characteristicData.uuid().toString(QUuid::WithoutBraces), handle, parent),
+ m_adaptor(new OrgBluezGattCharacteristic1Adaptor(this)),
+ m_servicePath(servicePath),
+ m_minimumValueLength(std::min(characteristicData.minimumValueLength(),
+ maximumAttributeLength)),
+ m_maximumValueLength(std::min(characteristicData.maximumValueLength(),
+ maximumAttributeLength))
+{
+ initializeFlags(characteristicData);
+ initializeValue(characteristicData.value());
+}
+
+InterfaceList QtBluezPeripheralCharacteristic::properties() const
+{
+ InterfaceList properties;
+ properties.insert(bluezCharacteristicInterface,
+ {
+ {"UUID"_L1, uuid},
+ {"Service"_L1, QDBusObjectPath(m_servicePath)},
+ {"Flags"_L1, m_flags}
+ });
+ return properties;
+}
+
+// org.bluez.GattCharacteristic1
+// This function is invoked when remote device reads the value
+QByteArray QtBluezPeripheralCharacteristic::ReadValue(const QVariantMap &options, QString& error)
+{
+ accessEvent(options);
+ // Offset is set by Bluez when the value size is more than MTU size.
+ // Bluez deduces the value size from the first ReadValue. If the
+ // received data size is larger than MTU, Bluez will take the first MTU bytes and
+ // issue more ReadValue calls with the 'offset' set
+ const quint16 offset = options.value("offset"_L1).toUInt();
+ const quint16 mtu = options.value("mtu"_L1).toUInt();
+
+ if (offset > m_value.length() - 1) {
+ qCWarning(QT_BT_BLUEZ) << "Invalid offset" << offset << ", value len:" << m_value.length();
+ error = bluezErrorInvalidOffset;
+ return {};
+ }
+
+ if (offset > 0)
+ return m_value.mid(offset, mtu);
+ else
+ return m_value;
+}
+
+// org.bluez.GattCharacteristic1
+// This function is invoked when remote device writes a value
+QString QtBluezPeripheralCharacteristic::WriteValue(const QByteArray &value,
+ const QVariantMap &options)
+{
+ accessEvent(options);
+
+ if (options.value("prepare-authorize"_L1).toBool()) {
+ // Qt API doesn't provide the means for application to authorize
+ qCWarning(QT_BT_BLUEZ) << "Characteristic write requires authorization."
+ << "The client device needs to be trusted beforehand";
+ return bluezErrorNotAuthorized;
+ }
+
+ if (value.size() < m_minimumValueLength || value.size() > m_maximumValueLength) {
+ qCWarning(QT_BT_BLUEZ) << "Characteristic value has invalid length" << value.size()
+ << "min:" << m_minimumValueLength
+ << "max:" << m_maximumValueLength;
+ return bluezErrorInvalidValueLength;
+ }
+ m_value = value;
+ emit valueUpdatedByRemote(handle, value);
+ return {};
+}
+
+// This function is called when the value has been updated locally (server-side)
+bool QtBluezPeripheralCharacteristic::localValueUpdate(const QByteArray& value)
+{
+ if (value.size() < m_minimumValueLength || value.size() > m_maximumValueLength) {
+ qCWarning(QT_BT_BLUEZ) << "Characteristic value has invalid length" << value.size()
+ << "min:" << m_minimumValueLength
+ << "max:" << m_maximumValueLength;
+ return false;
+ }
+ m_value = value;
+ if (m_notifying) {
+ emit propertiesAdaptor->PropertiesChanged(
+ bluezCharacteristicInterface, {{"Value"_L1, m_value}}, {});
+ }
+ return true;
+}
+
+// org.bluez.GattCharacteristic1
+// These are called when remote client enables or disables NTF/IND
+void QtBluezPeripheralCharacteristic::StartNotify()
+{
+ qCDebug(QT_BT_BLUEZ) << "NTF or IND enabled for characteristic" << uuid;
+ m_notifying = true;
+}
+
+void QtBluezPeripheralCharacteristic::StopNotify()
+{
+ qCDebug(QT_BT_BLUEZ) << "NTF or IND disabled for characteristic" << uuid;
+ m_notifying = false;
+}
+
+
+void QtBluezPeripheralCharacteristic::initializeValue(const QByteArray& value)
+{
+ const auto valueSize = value.size();
+ if (valueSize < m_minimumValueLength || valueSize > m_maximumValueLength) {
+ qCWarning(QT_BT_BLUEZ) << "Characteristic value has invalid length" << valueSize
+ << "min:" << m_minimumValueLength
+ << "max:" << m_maximumValueLength;
+ m_value = QByteArray(m_minimumValueLength, 0);
+ } else {
+ m_value = value;
+ }
+}
+
+void QtBluezPeripheralCharacteristic::initializeFlags(const QLowEnergyCharacteristicData& data)
+{
+ // Flag tokens are from org.bluez.GattCharacteristic1 documentation
+ if (data.properties() & QLowEnergyCharacteristic::PropertyType::Broadcasting)
+ m_flags.append("broadcast"_L1);
+ if (data.properties() & QLowEnergyCharacteristic::PropertyType::WriteNoResponse)
+ m_flags.append("write-without-response"_L1);
+ if (data.properties() & QLowEnergyCharacteristic::PropertyType::Read)
+ m_flags.append("read"_L1);
+ if (data.properties() & QLowEnergyCharacteristic::PropertyType::Write)
+ m_flags.append("write"_L1);
+ if (data.properties() & QLowEnergyCharacteristic::PropertyType::Notify)
+ m_flags.append("notify"_L1);
+ if (data.properties() & QLowEnergyCharacteristic::PropertyType::Indicate)
+ m_flags.append("indicate"_L1);
+ if (data.properties() & QLowEnergyCharacteristic::PropertyType::WriteSigned)
+ m_flags.append("authenticated-signed-writes"_L1);
+ if (data.properties() & QLowEnergyCharacteristic::PropertyType::ExtendedProperty) {
+ // If extended properties property is set, check if we have the descriptor
+ // describing them. Bluez will generate the actual descriptor based on these
+ // flags. For clarity: the 'extended-properties' token mentioned in the Bluez
+ // API is implied by these flags.
+ for (const auto& descriptor : data.descriptors()) {
+ // Core Bluetooth v5.3 Vol 3, Part G, 3.3.3.1
+ if (descriptor.uuid()
+ == QBluetoothUuid::DescriptorType::CharacteristicExtendedProperties
+ && descriptor.value().size() == 2) {
+ const auto properties = descriptor.value().at(0);
+ if (properties & 0x01)
+ m_flags.append("reliable-write"_L1);
+ if (properties & 0x02)
+ m_flags.append("writable-auxiliaries"_L1);
+ }
+ }
+ }
+
+ if (data.readConstraints() & QBluetooth::AttAccessConstraint::AttEncryptionRequired)
+ m_flags.append("encrypt-read"_L1);
+ if (data.readConstraints() & QBluetooth::AttAccessConstraint::AttAuthenticationRequired)
+ m_flags.append("encrypt-authenticated-read"_L1);
+ if (data.writeConstraints() & QBluetooth::AttAccessConstraint::AttEncryptionRequired)
+ m_flags.append("encrypt-write"_L1);
+ if (data.writeConstraints() & QBluetooth::AttAccessConstraint::AttAuthenticationRequired)
+ m_flags.append("encrypt-authenticated-write"_L1);
+
+ if (data.readConstraints() & QBluetooth::AttAccessConstraint::AttAuthorizationRequired
+ || data.writeConstraints() & QBluetooth::AttAccessConstraint::AttAuthorizationRequired)
+ m_flags.append("authorize"_L1);
+
+ if (m_flags.isEmpty()) {
+ qCWarning(QT_BT_BLUEZ) << "Characteristic property flags not set" << uuid
+ << "Peripheral may fail to register";
+ }
+}
+
+
+QtBluezPeripheralService::QtBluezPeripheralService(const QLowEnergyServiceData &serviceData,
+ const QString& applicationPath, quint16 ordinal,
+ QLowEnergyHandle handle, QObject* parent)
+ : QtBluezPeripheralGattObject(servicePathTemplate.arg(applicationPath).arg(ordinal),
+ serviceData.uuid().toString(QUuid::WithoutBraces), handle, parent),
+ m_isPrimary(serviceData.type() == QLowEnergyServiceData::ServiceTypePrimary),
+ m_adaptor(new OrgBluezGattService1Adaptor(this))
+{
+}
+
+void QtBluezPeripheralService::addIncludedService(const QString& objectPath) {
+ qCDebug(QT_BT_BLUEZ) << "Adding included service" << objectPath << "for" << uuid;
+ m_includedServices.append(QDBusObjectPath(objectPath));
+}
+
+InterfaceList QtBluezPeripheralService::properties() const {
+ InterfaceList interfaces;
+ interfaces.insert(bluezServiceInterface,{
+ {"UUID"_L1, uuid},
+ {"Primary"_L1, m_isPrimary},
+ {"Includes"_L1, QVariant::fromValue(m_includedServices)}
+ });
+ return interfaces;
+};
+
+QT_END_NAMESPACE
+
+#include "moc_bluezperipheralobjects_p.cpp"
diff --git a/src/bluetooth/bluez/bluezperipheralobjects_p.h b/src/bluetooth/bluez/bluezperipheralobjects_p.h
new file mode 100644
index 00000000..dbc9c4eb
--- /dev/null
+++ b/src/bluetooth/bluez/bluezperipheralobjects_p.h
@@ -0,0 +1,171 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef BLUEZ_PERIPHERAL_OBJECTS_P_H
+#define BLUEZ_PERIPHERAL_OBJECTS_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "bluez5_helper_p.h"
+
+#include <QtBluetooth/qbluetooth.h>
+#include <QtBluetooth/QBluetoothUuid>
+#include <QtBluetooth/QLowEnergyDescriptorData>
+#include <QtBluetooth/QLowEnergyCharacteristicData>
+#include <QtBluetooth/QLowEnergyServiceData>
+
+class OrgFreedesktopDBusPropertiesAdaptor;
+class OrgBluezGattCharacteristic1Adaptor;
+class OrgBluezGattDescriptor1Adaptor;
+class OrgBluezGattService1Adaptor;
+
+QT_BEGIN_NAMESPACE
+
+// The QtBluezPeripheralGattObject is the base class for services, characteristics, and descriptors
+class QtBluezPeripheralGattObject : public QObject
+{
+ Q_OBJECT
+
+public:
+ QtBluezPeripheralGattObject(const QString& objectPath, const QString& uuid,
+ QLowEnergyHandle handle, QObject* parent = nullptr);
+ virtual ~QtBluezPeripheralGattObject();
+
+ // List of properties exposed by this object, used when Bluez inquiries details
+ virtual InterfaceList properties() const = 0;
+
+ bool registerObject();
+ void unregisterObject();
+
+public:
+ // DBus object path
+ QString objectPath;
+ // UUID of the gatt object
+ QString uuid;
+ // QtBluetooth internal handle and reference to the application
+ // to read and write values towards the Qt API
+ QLowEnergyHandle handle;
+ // Bluez DBus Gatt objects need to provide this
+ OrgFreedesktopDBusPropertiesAdaptor* propertiesAdaptor{};
+
+signals:
+ void remoteDeviceAccessEvent(const QString& remoteDeviceObjectPath, quint16 mtu);
+
+protected:
+ void accessEvent(const QVariantMap& options);
+
+private:
+ bool m_registered = false;
+};
+
+class QtBluezPeripheralDescriptor : public QtBluezPeripheralGattObject
+{
+ Q_OBJECT
+
+public:
+ QtBluezPeripheralDescriptor(const QLowEnergyDescriptorData& descriptorData,
+ const QString& characteristicPath, quint16 ordinal,
+ QLowEnergyHandle handle, QLowEnergyHandle characteristicHandle,
+ QObject* parent);
+
+ InterfaceList properties() const final;
+
+ // org.bluez.GattDescriptor1
+ // This function is invoked when remote device reads the value. Sets error if any
+ Q_INVOKABLE QByteArray ReadValue(const QVariantMap &options, QString &error);
+
+ // org.bluez.GattDescriptor1
+ // This function is invoked when remote device writes a value. Returns Bluez DBus error if any
+ Q_INVOKABLE QString WriteValue(const QByteArray &value, const QVariantMap &options);
+
+ // Call this function when value has been updated locally (server/user application side)
+ bool localValueUpdate(const QByteArray& value);
+
+signals:
+ void valueUpdatedByRemote(QLowEnergyHandle characteristicHandle,
+ QLowEnergyHandle descriptorHandle, const QByteArray& value);
+
+private:
+ void initializeFlags(const QLowEnergyDescriptorData& data);
+
+ OrgBluezGattDescriptor1Adaptor* m_adaptor{};
+ QString m_characteristicPath;
+ QByteArray m_value;
+ QStringList m_flags;
+ QLowEnergyHandle m_characteristicHandle;
+};
+
+
+class QtBluezPeripheralCharacteristic : public QtBluezPeripheralGattObject
+{
+ Q_OBJECT
+
+public:
+ QtBluezPeripheralCharacteristic(const QLowEnergyCharacteristicData& characteristicData,
+ const QString& servicePath, quint16 ordinal,
+ QLowEnergyHandle handle, QObject* parent);
+
+ InterfaceList properties() const final;
+
+ // org.bluez.GattCharacteristic1
+ // This function is invoked when remote device reads the value. Sets error if any
+ Q_INVOKABLE QByteArray ReadValue(const QVariantMap &options, QString& error);
+
+ // org.bluez.GattCharacteristic1
+ // This function is invoked when remote device writes a value. Returns Bluez DBus error if any
+ Q_INVOKABLE QString WriteValue(const QByteArray &value, const QVariantMap &options);
+
+ // org.bluez.GattCharacteristic1
+ // These are called when remote client enables or disables NTF/IND
+ Q_INVOKABLE void StartNotify();
+ Q_INVOKABLE void StopNotify();
+
+ // Call this function when value has been updated locally (server/user application side)
+ bool localValueUpdate(const QByteArray& value);
+
+signals:
+ void valueUpdatedByRemote(QLowEnergyHandle handle, const QByteArray& value);
+
+private:
+ void initializeValue(const QByteArray& value);
+ void initializeFlags(const QLowEnergyCharacteristicData& data);
+
+ OrgBluezGattCharacteristic1Adaptor* m_adaptor{};
+ QString m_servicePath;
+ bool m_notifying{false};
+ QByteArray m_value;
+ QStringList m_flags;
+ int m_minimumValueLength;
+ int m_maximumValueLength;
+};
+
+class QtBluezPeripheralService : public QtBluezPeripheralGattObject
+{
+ Q_OBJECT
+public:
+ QtBluezPeripheralService(const QLowEnergyServiceData &serviceData,
+ const QString& applicationPath, quint16 ordinal,
+ QLowEnergyHandle handle, QObject* parent);
+
+ InterfaceList properties() const final;
+ void addIncludedService(const QString& objectPath);
+
+private:
+ const bool m_isPrimary;
+ OrgBluezGattService1Adaptor* m_adaptor{};
+ QList<QDBusObjectPath> m_includedServices;
+};
+
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/bluetooth/bluez/device.cpp b/src/bluetooth/bluez/device.cpp
deleted file mode 100644
index 14b91ad0..00000000
--- a/src/bluetooth/bluez/device.cpp
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * This file was generated by qdbusxml2cpp version 0.8
- * Command line was: qdbusxml2cpp -i servicemap_p.h -p device_p.h:device.cpp org.bluez.Device.xml org.bluez.Device
- *
- * qdbusxml2cpp is Copyright (C) 2017 The Qt Company Ltd.
- *
- * This is an auto-generated file.
- * This file may have been hand-edited. Look for HAND-EDIT comments
- * before re-generating it.
- */
-
-#include "device_p.h"
-
-/*
- * Implementation of interface class OrgBluezDeviceInterface
- */
-
-OrgBluezDeviceInterface::OrgBluezDeviceInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent)
- : QDBusAbstractInterface(service, path, staticInterfaceName(), connection, parent)
-{
-}
-
-OrgBluezDeviceInterface::~OrgBluezDeviceInterface()
-{
-}
-
diff --git a/src/bluetooth/bluez/device1_bluez5.cpp b/src/bluetooth/bluez/device1_bluez5.cpp
index cd6453ad..1dc644fb 100644
--- a/src/bluetooth/bluez/device1_bluez5.cpp
+++ b/src/bluetooth/bluez/device1_bluez5.cpp
@@ -1,8 +1,8 @@
/*
* This file was generated by qdbusxml2cpp version 0.8
- * Command line was: qdbusxml2cpp -p device1_bluez5_p.h:device1_bluez5.cpp org.bluez.Device1.xml
+ * Command line was: qdbusxml2cpp -i bluez5_helper_p.h -I QtCore/private/qglobal_p.h -p device1_bluez5_p.h:device1_bluez5.cpp org.bluez.Device1.xml
*
- * qdbusxml2cpp is Copyright (C) 2017 The Qt Company Ltd.
+ * qdbusxml2cpp is Copyright (C) 2022 The Qt Company Ltd.
*
* This is an auto-generated file.
* This file may have been hand-edited. Look for HAND-EDIT comments
@@ -24,3 +24,5 @@ OrgBluezDevice1Interface::~OrgBluezDevice1Interface()
{
}
+
+#include "moc_device1_bluez5_p.cpp"
diff --git a/src/bluetooth/bluez/device1_bluez5_p.h b/src/bluetooth/bluez/device1_bluez5_p.h
index b9523a56..281ae237 100644
--- a/src/bluetooth/bluez/device1_bluez5_p.h
+++ b/src/bluetooth/bluez/device1_bluez5_p.h
@@ -1,8 +1,8 @@
/*
* This file was generated by qdbusxml2cpp version 0.8
- * Command line was: qdbusxml2cpp -p device1_bluez5_p.h:device1_bluez5.cpp org.bluez.Device1.xml
+ * Command line was: qdbusxml2cpp -i bluez5_helper_p.h -I QtCore/private/qglobal_p.h -p device1_bluez5_p.h:device1_bluez5.cpp org.bluez.Device1.xml
*
- * qdbusxml2cpp is Copyright (C) 2017 The Qt Company Ltd.
+ * qdbusxml2cpp is Copyright (C) 2022 The Qt Company Ltd.
*
* This is an auto-generated file.
* Do not edit! All changes made to it will be lost.
@@ -11,6 +11,17 @@
#ifndef DEVICE1_BLUEZ5_P_H
#define DEVICE1_BLUEZ5_P_H
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
#include <QtCore/QObject>
#include <QtCore/QByteArray>
#include <QtCore/QList>
@@ -20,6 +31,7 @@
#include <QtCore/QVariant>
#include <QtDBus/QtDBus>
#include "bluez5_helper_p.h"
+#include <QtCore/private/qglobal_p.h>
/*
* Proxy class for interface org.bluez.Device1
@@ -96,9 +108,9 @@ public:
inline short rSSI() const
{ return qvariant_cast< short >(property("RSSI")); }
- Q_PROPERTY(QVariantMap ServiceData READ serviceData)
- inline QVariantMap serviceData() const
- { return qvariant_cast< QVariantMap >(property("ServiceData")); }
+ Q_PROPERTY(ServiceDataList ServiceData READ serviceData)
+ inline ServiceDataList serviceData() const
+ { return qvariant_cast< ServiceDataList >(property("ServiceData")); }
Q_PROPERTY(bool ServicesResolved READ servicesResolved)
inline bool servicesResolved() const
@@ -162,7 +174,7 @@ Q_SIGNALS: // SIGNALS
namespace org {
namespace bluez {
- typedef ::OrgBluezDevice1Interface Device1;
+ using Device1 = ::OrgBluezDevice1Interface;
}
}
#endif
diff --git a/src/bluetooth/bluez/device_p.h b/src/bluetooth/bluez/device_p.h
deleted file mode 100644
index 2e1e39ad..00000000
--- a/src/bluetooth/bluez/device_p.h
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * This file was generated by qdbusxml2cpp version 0.8
- * Command line was: qdbusxml2cpp -i servicemap_p.h -p device_p.h:device.cpp org.bluez.Device.xml org.bluez.Device
- *
- * qdbusxml2cpp is Copyright (C) 2017 The Qt Company Ltd.
- *
- * This is an auto-generated file.
- * Do not edit! All changes made to it will be lost.
- */
-
-#ifndef DEVICE_P_H
-#define DEVICE_P_H
-
-#include <QtCore/QObject>
-#include <QtCore/QByteArray>
-#include <QtCore/QList>
-#include <QtCore/QMap>
-#include <QtCore/QString>
-#include <QtCore/QStringList>
-#include <QtCore/QVariant>
-#include <QtDBus/QtDBus>
-#include "servicemap_p.h"
-
-/*
- * Proxy class for interface org.bluez.Device
- */
-class OrgBluezDeviceInterface: public QDBusAbstractInterface
-{
- Q_OBJECT
-public:
- static inline const char *staticInterfaceName()
- { return "org.bluez.Device"; }
-
-public:
- OrgBluezDeviceInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = nullptr);
-
- ~OrgBluezDeviceInterface();
-
-public Q_SLOTS: // METHODS
- inline QDBusPendingReply<> CancelDiscovery()
- {
- QList<QVariant> argumentList;
- return asyncCallWithArgumentList(QStringLiteral("CancelDiscovery"), argumentList);
- }
-
- inline QDBusPendingReply<QDBusObjectPath> CreateNode(const QString &in0)
- {
- QList<QVariant> argumentList;
- argumentList << QVariant::fromValue(in0);
- return asyncCallWithArgumentList(QStringLiteral("CreateNode"), argumentList);
- }
-
- inline QDBusPendingReply<> Disconnect()
- {
- QList<QVariant> argumentList;
- return asyncCallWithArgumentList(QStringLiteral("Disconnect"), argumentList);
- }
-
- inline QDBusPendingReply<ServiceMap> DiscoverServices(const QString &in0)
- {
- QList<QVariant> argumentList;
- argumentList << QVariant::fromValue(in0);
- return asyncCallWithArgumentList(QStringLiteral("DiscoverServices"), argumentList);
- }
-
- inline QDBusPendingReply<QVariantMap> GetProperties()
- {
- QList<QVariant> argumentList;
- return asyncCallWithArgumentList(QStringLiteral("GetProperties"), argumentList);
- }
-
- inline QDBusPendingReply<QList<QDBusObjectPath> > ListNodes()
- {
- QList<QVariant> argumentList;
- return asyncCallWithArgumentList(QStringLiteral("ListNodes"), argumentList);
- }
-
- inline QDBusPendingReply<> RemoveNode(const QDBusObjectPath &in0)
- {
- QList<QVariant> argumentList;
- argumentList << QVariant::fromValue(in0);
- return asyncCallWithArgumentList(QStringLiteral("RemoveNode"), argumentList);
- }
-
- inline QDBusPendingReply<> SetProperty(const QString &in0, const QDBusVariant &in1)
- {
- QList<QVariant> argumentList;
- argumentList << QVariant::fromValue(in0) << QVariant::fromValue(in1);
- return asyncCallWithArgumentList(QStringLiteral("SetProperty"), argumentList);
- }
-
-Q_SIGNALS: // SIGNALS
- void DisconnectRequested();
- void NodeCreated(const QDBusObjectPath &in0);
- void NodeRemoved(const QDBusObjectPath &in0);
- void PropertyChanged(const QString &in0, const QDBusVariant &in1);
-};
-
-namespace org {
- namespace bluez {
- typedef ::OrgBluezDeviceInterface Device;
- }
-}
-#endif
diff --git a/src/bluetooth/bluez/gattchar1.cpp b/src/bluetooth/bluez/gattchar1.cpp
index cdb3fc0d..3a358a0b 100644
--- a/src/bluetooth/bluez/gattchar1.cpp
+++ b/src/bluetooth/bluez/gattchar1.cpp
@@ -1,8 +1,8 @@
/*
* This file was generated by qdbusxml2cpp version 0.8
- * Command line was: qdbusxml2cpp -p gattchar1_p.h:gattchar1.cpp org.bluez.GattCharacteristic1.xml
+ * Command line was: qdbusxml2cpp -I QtCore/private/qglobal_p.h -p gattchar1_p.h:gattchar1.cpp org.bluez.GattCharacteristic1.xml
*
- * qdbusxml2cpp is Copyright (C) 2017 The Qt Company Ltd.
+ * qdbusxml2cpp is Copyright (C) 2022 The Qt Company Ltd.
*
* This is an auto-generated file.
* This file may have been hand-edited. Look for HAND-EDIT comments
@@ -24,3 +24,5 @@ OrgBluezGattCharacteristic1Interface::~OrgBluezGattCharacteristic1Interface()
{
}
+
+#include "moc_gattchar1_p.cpp"
diff --git a/src/bluetooth/bluez/gattchar1_p.h b/src/bluetooth/bluez/gattchar1_p.h
index c19e9f58..860002a4 100644
--- a/src/bluetooth/bluez/gattchar1_p.h
+++ b/src/bluetooth/bluez/gattchar1_p.h
@@ -1,8 +1,8 @@
/*
* This file was generated by qdbusxml2cpp version 0.8
- * Command line was: qdbusxml2cpp -p gattchar1_p.h:gattchar1.cpp org.bluez.GattCharacteristic1.xml
+ * Command line was: qdbusxml2cpp -I QtCore/private/qglobal_p.h -p gattchar1_p.h:gattchar1.cpp org.bluez.GattCharacteristic1.xml
*
- * qdbusxml2cpp is Copyright (C) 2017 The Qt Company Ltd.
+ * qdbusxml2cpp is Copyright (C) 2022 The Qt Company Ltd.
*
* This is an auto-generated file.
* Do not edit! All changes made to it will be lost.
@@ -11,6 +11,17 @@
#ifndef GATTCHAR1_P_H
#define GATTCHAR1_P_H
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
#include <QtCore/QObject>
#include <QtCore/QByteArray>
#include <QtCore/QList>
@@ -19,6 +30,7 @@
#include <QtCore/QStringList>
#include <QtCore/QVariant>
#include <QtDBus/QtDBus>
+#include <QtCore/private/qglobal_p.h>
/*
* Proxy class for interface org.bluez.GattCharacteristic1
@@ -87,7 +99,7 @@ Q_SIGNALS: // SIGNALS
namespace org {
namespace bluez {
- typedef ::OrgBluezGattCharacteristic1Interface GattCharacteristic1;
+ using GattCharacteristic1 = ::OrgBluezGattCharacteristic1Interface;
}
}
#endif
diff --git a/src/bluetooth/bluez/gattcharacteristic1adaptor.cpp b/src/bluetooth/bluez/gattcharacteristic1adaptor.cpp
new file mode 100644
index 00000000..d6eb0a1c
--- /dev/null
+++ b/src/bluetooth/bluez/gattcharacteristic1adaptor.cpp
@@ -0,0 +1,108 @@
+/*
+ * This file was generated by qdbusxml2cpp version 0.8
+ * Command line was: qdbusxml2cpp -a gattcharacteristic1adaptor_p.h:gattcharacteristic1adaptor.cpp -c OrgBluezGattCharacteristic1Adaptor -i bluez5_helper_p.h org.bluez.GattCharacteristic1.xml
+ *
+ * qdbusxml2cpp is Copyright (C) 2022 The Qt Company Ltd.
+ *
+ * This is an auto-generated file.
+ * Do not edit! All changes made to it will be lost.
+ */
+
+#include "gattcharacteristic1adaptor_p.h"
+#include <QtCore/QMetaObject>
+#include <QtCore/QByteArray>
+#include <QtCore/QList>
+#include <QtCore/QMap>
+#include <QtCore/QString>
+#include <QtCore/QStringList>
+#include <QtCore/QVariant>
+
+/*
+ * Implementation of adaptor class OrgBluezGattCharacteristic1Adaptor
+ */
+
+OrgBluezGattCharacteristic1Adaptor::OrgBluezGattCharacteristic1Adaptor(QObject *parent)
+ : QDBusAbstractAdaptor(parent)
+{
+ // constructor
+ setAutoRelaySignals(true);
+}
+
+OrgBluezGattCharacteristic1Adaptor::~OrgBluezGattCharacteristic1Adaptor()
+{
+ // destructor
+}
+
+QStringList OrgBluezGattCharacteristic1Adaptor::flags() const
+{
+ // get the value of property Flags
+ return qvariant_cast< QStringList >(parent()->property("Flags"));
+}
+
+bool OrgBluezGattCharacteristic1Adaptor::notifying() const
+{
+ // get the value of property Notifying
+ return qvariant_cast< bool >(parent()->property("Notifying"));
+}
+
+QDBusObjectPath OrgBluezGattCharacteristic1Adaptor::service() const
+{
+ // get the value of property Service
+ return qvariant_cast< QDBusObjectPath >(parent()->property("Service"));
+}
+
+QString OrgBluezGattCharacteristic1Adaptor::uUID() const
+{
+ // get the value of property UUID
+ return qvariant_cast< QString >(parent()->property("UUID"));
+}
+
+QByteArray OrgBluezGattCharacteristic1Adaptor::value() const
+{
+ // get the value of property Value
+ return qvariant_cast< QByteArray >(parent()->property("Value"));
+}
+
+QByteArray OrgBluezGattCharacteristic1Adaptor::ReadValue(const QVariantMap &options,
+ const QDBusMessage& msg)
+{
+ // handle method call org.bluez.GattCharacteristic1.ReadValue
+ QByteArray value;
+ QString error;
+ QMetaObject::invokeMethod(parent(), "ReadValue", Q_RETURN_ARG(QByteArray, value),
+ Q_ARG(QVariantMap, options), Q_ARG(QString&, error));
+ if (!error.isEmpty()) {
+ // Reply with error if needed
+ auto reply = msg.createErrorReply(error, {});
+ QDBusConnection::systemBus().send(reply);
+ }
+ return value;
+}
+
+void OrgBluezGattCharacteristic1Adaptor::StartNotify()
+{
+ // handle method call org.bluez.GattCharacteristic1.StartNotify
+ QMetaObject::invokeMethod(parent(), "StartNotify");
+}
+
+void OrgBluezGattCharacteristic1Adaptor::StopNotify()
+{
+ // handle method call org.bluez.GattCharacteristic1.StopNotify
+ QMetaObject::invokeMethod(parent(), "StopNotify");
+}
+
+void OrgBluezGattCharacteristic1Adaptor::WriteValue(const QByteArray &value,
+ const QVariantMap &options,
+ const QDBusMessage& msg)
+{
+ // handle method call org.bluez.GattCharacteristic1.WriteValue
+ QString error;
+ QMetaObject::invokeMethod(parent(), "WriteValue", Q_RETURN_ARG(QString, error),
+ Q_ARG(QByteArray, value), Q_ARG(QVariantMap, options));
+
+ if (!error.isEmpty()) {
+ // Reply with error if needed
+ auto reply = msg.createErrorReply(error, {});
+ QDBusConnection::systemBus().send(reply);
+ }
+}
diff --git a/src/bluetooth/bluez/gattcharacteristic1adaptor_p.h b/src/bluetooth/bluez/gattcharacteristic1adaptor_p.h
new file mode 100644
index 00000000..7f80e8f0
--- /dev/null
+++ b/src/bluetooth/bluez/gattcharacteristic1adaptor_p.h
@@ -0,0 +1,87 @@
+/*
+ * This file was generated by qdbusxml2cpp version 0.8
+ * Command line was: qdbusxml2cpp -a gattcharacteristic1adaptor_p.h:gattcharacteristic1adaptor.cpp -c OrgBluezGattCharacteristic1Adaptor -i bluez5_helper_p.h org.bluez.GattCharacteristic1.xml
+ *
+ * qdbusxml2cpp is Copyright (C) 2022 The Qt Company Ltd.
+ *
+ * This is an auto-generated file.
+ * This file may have been hand-edited. Look for HAND-EDIT comments
+ * before re-generating it.
+ */
+
+#ifndef GATTCHARACTERISTIC1ADAPTOR_P_H
+#define GATTCHARACTERISTIC1ADAPTOR_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/QObject>
+#include <QtDBus/QtDBus>
+#include "bluez5_helper_p.h"
+#include <QtCore/qcontainerfwd.h>
+
+/*
+ * Adaptor class for interface org.bluez.GattCharacteristic1
+ */
+class OrgBluezGattCharacteristic1Adaptor: public QDBusAbstractAdaptor
+{
+ Q_OBJECT
+ Q_CLASSINFO("D-Bus Interface", "org.bluez.GattCharacteristic1")
+ Q_CLASSINFO("D-Bus Introspection", ""
+" <interface name=\"org.bluez.GattCharacteristic1\">\n"
+" <method name=\"ReadValue\">\n"
+" <arg direction=\"in\" type=\"a{sv}\" name=\"options\"/>\n"
+" <annotation value=\"QVariantMap\" name=\"org.qtproject.QtDBus.QtTypeName.In0\"/>\n"
+" <arg direction=\"out\" type=\"ay\" name=\"value\"/>\n"
+" </method>\n"
+" <method name=\"WriteValue\">\n"
+" <arg direction=\"in\" type=\"ay\" name=\"value\"/>\n"
+" <arg direction=\"in\" type=\"a{sv}\" name=\"options\"/>\n"
+" <annotation value=\"QVariantMap\" name=\"org.qtproject.QtDBus.QtTypeName.In1\"/>\n"
+" </method>\n"
+" <method name=\"StartNotify\"/>\n"
+" <method name=\"StopNotify\"/>\n"
+" <property access=\"read\" type=\"s\" name=\"UUID\"/>\n"
+" <property access=\"read\" type=\"o\" name=\"Service\"/>\n"
+" <property access=\"read\" type=\"ay\" name=\"Value\"/>\n"
+" <property access=\"read\" type=\"b\" name=\"Notifying\"/>\n"
+" <property access=\"read\" type=\"as\" name=\"Flags\"/>\n"
+" </interface>\n"
+ "")
+public:
+ OrgBluezGattCharacteristic1Adaptor(QObject *parent);
+ virtual ~OrgBluezGattCharacteristic1Adaptor();
+
+public: // PROPERTIES
+ Q_PROPERTY(QStringList Flags READ flags)
+ QStringList flags() const;
+
+ Q_PROPERTY(bool Notifying READ notifying)
+ bool notifying() const;
+
+ Q_PROPERTY(QDBusObjectPath Service READ service)
+ QDBusObjectPath service() const;
+
+ Q_PROPERTY(QString UUID READ uUID)
+ QString uUID() const;
+
+ Q_PROPERTY(QByteArray Value READ value)
+ QByteArray value() const;
+
+public Q_SLOTS: // METHODS
+ QByteArray ReadValue(const QVariantMap &options, const QDBusMessage &msg);
+ void StartNotify();
+ void StopNotify();
+ void WriteValue(const QByteArray &value, const QVariantMap &options, const QDBusMessage& msg);
+Q_SIGNALS: // SIGNALS
+};
+
+#endif
diff --git a/src/bluetooth/bluez/gattdesc1.cpp b/src/bluetooth/bluez/gattdesc1.cpp
index 8447e49b..abe846a3 100644
--- a/src/bluetooth/bluez/gattdesc1.cpp
+++ b/src/bluetooth/bluez/gattdesc1.cpp
@@ -1,8 +1,8 @@
/*
* This file was generated by qdbusxml2cpp version 0.8
- * Command line was: qdbusxml2cpp -p gattdesc1_p.h:gattdesc1.cpp org.bluez.GattDescriptor1.xml
+ * Command line was: qdbusxml2cpp -I QtCore/private/qglobal_p.h -p gattdesc1_p.h:gattdesc1.cpp org.bluez.GattDescriptor1.xml
*
- * qdbusxml2cpp is Copyright (C) 2017 The Qt Company Ltd.
+ * qdbusxml2cpp is Copyright (C) 2022 The Qt Company Ltd.
*
* This is an auto-generated file.
* This file may have been hand-edited. Look for HAND-EDIT comments
@@ -24,3 +24,5 @@ OrgBluezGattDescriptor1Interface::~OrgBluezGattDescriptor1Interface()
{
}
+
+#include "moc_gattdesc1_p.cpp"
diff --git a/src/bluetooth/bluez/gattdesc1_p.h b/src/bluetooth/bluez/gattdesc1_p.h
index 6ade7a42..a054edfa 100644
--- a/src/bluetooth/bluez/gattdesc1_p.h
+++ b/src/bluetooth/bluez/gattdesc1_p.h
@@ -1,8 +1,8 @@
/*
* This file was generated by qdbusxml2cpp version 0.8
- * Command line was: qdbusxml2cpp -p gattdesc1_p.h:gattdesc1.cpp org.bluez.GattDescriptor1.xml
+ * Command line was: qdbusxml2cpp -I QtCore/private/qglobal_p.h -p gattdesc1_p.h:gattdesc1.cpp org.bluez.GattDescriptor1.xml
*
- * qdbusxml2cpp is Copyright (C) 2017 The Qt Company Ltd.
+ * qdbusxml2cpp is Copyright (C) 2022 The Qt Company Ltd.
*
* This is an auto-generated file.
* Do not edit! All changes made to it will be lost.
@@ -11,6 +11,17 @@
#ifndef GATTDESC1_P_H
#define GATTDESC1_P_H
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
#include <QtCore/QObject>
#include <QtCore/QByteArray>
#include <QtCore/QList>
@@ -19,6 +30,7 @@
#include <QtCore/QStringList>
#include <QtCore/QVariant>
#include <QtDBus/QtDBus>
+#include <QtCore/private/qglobal_p.h>
/*
* Proxy class for interface org.bluez.GattDescriptor1
@@ -67,7 +79,7 @@ Q_SIGNALS: // SIGNALS
namespace org {
namespace bluez {
- typedef ::OrgBluezGattDescriptor1Interface GattDescriptor1;
+ using GattDescriptor1 = ::OrgBluezGattDescriptor1Interface;
}
}
#endif
diff --git a/src/bluetooth/bluez/gattdescriptor1adaptor.cpp b/src/bluetooth/bluez/gattdescriptor1adaptor.cpp
new file mode 100644
index 00000000..b7177384
--- /dev/null
+++ b/src/bluetooth/bluez/gattdescriptor1adaptor.cpp
@@ -0,0 +1,84 @@
+/*
+ * This file was generated by qdbusxml2cpp version 0.8
+ * Command line was: qdbusxml2cpp -a gattdescriptor1adaptor_p.h:gattdescriptor1adaptor.cpp -c OrgBluezGattDescriptor1Adaptor -i bluez5_helper_p.h org.bluez.GattDescriptor1.xml
+ *
+ * qdbusxml2cpp is Copyright (C) 2022 The Qt Company Ltd.
+ *
+ * This is an auto-generated file.
+ * Do not edit! All changes made to it will be lost.
+ */
+
+#include "gattdescriptor1adaptor_p.h"
+#include <QtCore/QMetaObject>
+#include <QtCore/QByteArray>
+#include <QtCore/QList>
+#include <QtCore/QMap>
+#include <QtCore/QString>
+#include <QtCore/QStringList>
+#include <QtCore/QVariant>
+
+/*
+ * Implementation of adaptor class OrgBluezGattDescriptor1Adaptor
+ */
+
+OrgBluezGattDescriptor1Adaptor::OrgBluezGattDescriptor1Adaptor(QObject *parent)
+ : QDBusAbstractAdaptor(parent)
+{
+ // constructor
+ setAutoRelaySignals(true);
+}
+
+OrgBluezGattDescriptor1Adaptor::~OrgBluezGattDescriptor1Adaptor()
+{
+ // destructor
+}
+
+QDBusObjectPath OrgBluezGattDescriptor1Adaptor::characteristic() const
+{
+ // get the value of property Characteristic
+ return qvariant_cast< QDBusObjectPath >(parent()->property("Characteristic"));
+}
+
+QString OrgBluezGattDescriptor1Adaptor::uUID() const
+{
+ // get the value of property UUID
+ return qvariant_cast< QString >(parent()->property("UUID"));
+}
+
+QByteArray OrgBluezGattDescriptor1Adaptor::value() const
+{
+ // get the value of property Value
+ return qvariant_cast< QByteArray >(parent()->property("Value"));
+}
+
+QByteArray OrgBluezGattDescriptor1Adaptor::ReadValue(const QVariantMap &options,
+ const QDBusMessage& msg)
+{
+ // handle method call org.bluez.GattDescriptor1.ReadValue
+ QByteArray value;
+ QString error;
+ QMetaObject::invokeMethod(parent(), "ReadValue", Q_RETURN_ARG(QByteArray, value),
+ Q_ARG(QVariantMap, options), Q_ARG(QString&, error));
+ if (!error.isEmpty()) {
+ // Reply with error if needed
+ auto reply = msg.createErrorReply(error, {});
+ QDBusConnection::systemBus().send(reply);
+ }
+ return value;
+}
+
+void OrgBluezGattDescriptor1Adaptor::WriteValue(const QByteArray &value,
+ const QVariantMap &options,
+ const QDBusMessage& msg)
+{
+ // handle method call org.bluez.GattDescriptor1.WriteValue
+ QString error;
+ QMetaObject::invokeMethod(parent(), "WriteValue", Q_RETURN_ARG(QString, error),
+ Q_ARG(QByteArray, value), Q_ARG(QVariantMap, options));
+
+ if (!error.isEmpty()) {
+ // Reply with error if needed
+ auto reply = msg.createErrorReply(error, {});
+ QDBusConnection::systemBus().send(reply);
+ }
+}
diff --git a/src/bluetooth/bluez/gattdescriptor1adaptor_p.h b/src/bluetooth/bluez/gattdescriptor1adaptor_p.h
new file mode 100644
index 00000000..a7eacb99
--- /dev/null
+++ b/src/bluetooth/bluez/gattdescriptor1adaptor_p.h
@@ -0,0 +1,75 @@
+/*
+ * This file was generated by qdbusxml2cpp version 0.8
+ * Command line was: qdbusxml2cpp -a gattdescriptor1adaptor_p.h:gattdescriptor1adaptor.cpp -c OrgBluezGattDescriptor1Adaptor -i bluez5_helper_p.h org.bluez.GattDescriptor1.xml
+ *
+ * qdbusxml2cpp is Copyright (C) 2022 The Qt Company Ltd.
+ *
+ * This is an auto-generated file.
+ * This file may have been hand-edited. Look for HAND-EDIT comments
+ * before re-generating it.
+ */
+
+#ifndef GATTDESCRIPTOR1ADAPTOR_P_H
+#define GATTDESCRIPTOR1ADAPTOR_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/QObject>
+#include <QtDBus/QtDBus>
+#include "bluez5_helper_p.h"
+#include <QtCore/qcontainerfwd.h>
+
+/*
+ * Adaptor class for interface org.bluez.GattDescriptor1
+ */
+class OrgBluezGattDescriptor1Adaptor: public QDBusAbstractAdaptor
+{
+ Q_OBJECT
+ Q_CLASSINFO("D-Bus Interface", "org.bluez.GattDescriptor1")
+ Q_CLASSINFO("D-Bus Introspection", ""
+" <interface name=\"org.bluez.GattDescriptor1\">\n"
+" <method name=\"ReadValue\">\n"
+" <arg direction=\"in\" type=\"a{sv}\" name=\"options\"/>\n"
+" <annotation value=\"QVariantMap\" name=\"org.qtproject.QtDBus.QtTypeName.In0\"/>\n"
+" <arg direction=\"out\" type=\"ay\" name=\"value\"/>\n"
+" </method>\n"
+" <method name=\"WriteValue\">\n"
+" <arg direction=\"in\" type=\"ay\" name=\"value\"/>\n"
+" <arg direction=\"in\" type=\"a{sv}\" name=\"options\"/>\n"
+" <annotation value=\"QVariantMap\" name=\"org.qtproject.QtDBus.QtTypeName.In1\"/>\n"
+" </method>\n"
+" <property access=\"read\" type=\"s\" name=\"UUID\"/>\n"
+" <property access=\"read\" type=\"o\" name=\"Characteristic\"/>\n"
+" <property access=\"read\" type=\"ay\" name=\"Value\"/>\n"
+" </interface>\n"
+ "")
+public:
+ OrgBluezGattDescriptor1Adaptor(QObject *parent);
+ virtual ~OrgBluezGattDescriptor1Adaptor();
+
+public: // PROPERTIES
+ Q_PROPERTY(QDBusObjectPath Characteristic READ characteristic)
+ QDBusObjectPath characteristic() const;
+
+ Q_PROPERTY(QString UUID READ uUID)
+ QString uUID() const;
+
+ Q_PROPERTY(QByteArray Value READ value)
+ QByteArray value() const;
+
+public Q_SLOTS: // METHODS
+ QByteArray ReadValue(const QVariantMap &options, const QDBusMessage &msg);
+ void WriteValue(const QByteArray &value, const QVariantMap &options, const QDBusMessage& msg);
+Q_SIGNALS: // SIGNALS
+};
+
+#endif
diff --git a/src/bluetooth/bluez/gattmanager1.cpp b/src/bluetooth/bluez/gattmanager1.cpp
new file mode 100644
index 00000000..66558b0e
--- /dev/null
+++ b/src/bluetooth/bluez/gattmanager1.cpp
@@ -0,0 +1,28 @@
+/*
+ * This file was generated by qdbusxml2cpp version 0.8
+ * Command line was: qdbusxml2cpp -I QtCore/private/qglobal_p.h -p gattmanager1_p.h:gattmanager1.cpp org.bluez.GattManager1.xml --moc
+ *
+ * qdbusxml2cpp is Copyright (C) 2022 The Qt Company Ltd.
+ *
+ * This is an auto-generated file.
+ * This file may have been hand-edited. Look for HAND-EDIT comments
+ * before re-generating it.
+ */
+
+#include "gattmanager1_p.h"
+
+/*
+ * Implementation of interface class OrgBluezGattManager1Interface
+ */
+
+OrgBluezGattManager1Interface::OrgBluezGattManager1Interface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent)
+ : QDBusAbstractInterface(service, path, staticInterfaceName(), connection, parent)
+{
+}
+
+OrgBluezGattManager1Interface::~OrgBluezGattManager1Interface()
+{
+}
+
+
+#include "moc_gattmanager1_p.cpp"
diff --git a/src/bluetooth/bluez/gattmanager1_p.h b/src/bluetooth/bluez/gattmanager1_p.h
new file mode 100644
index 00000000..43f81272
--- /dev/null
+++ b/src/bluetooth/bluez/gattmanager1_p.h
@@ -0,0 +1,73 @@
+/*
+ * This file was generated by qdbusxml2cpp version 0.8
+ * Command line was: qdbusxml2cpp -I QtCore/private/qglobal_p.h -p gattmanager1_p.h:gattmanager1.cpp org.bluez.GattManager1.xml --moc
+ *
+ * qdbusxml2cpp is Copyright (C) 2022 The Qt Company Ltd.
+ *
+ * This is an auto-generated file.
+ * Do not edit! All changes made to it will be lost.
+ */
+
+#ifndef GATTMANAGER1_P_H
+#define GATTMANAGER1_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/QObject>
+#include <QtCore/QByteArray>
+#include <QtCore/QList>
+#include <QtCore/QMap>
+#include <QtCore/QString>
+#include <QtCore/QStringList>
+#include <QtCore/QVariant>
+#include <QtDBus/QtDBus>
+#include <QtCore/private/qglobal_p.h>
+
+/*
+ * Proxy class for interface org.bluez.GattManager1
+ */
+class OrgBluezGattManager1Interface: public QDBusAbstractInterface
+{
+ Q_OBJECT
+public:
+ static inline const char *staticInterfaceName()
+ { return "org.bluez.GattManager1"; }
+
+public:
+ OrgBluezGattManager1Interface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = nullptr);
+
+ ~OrgBluezGattManager1Interface();
+
+public Q_SLOTS: // METHODS
+ inline QDBusPendingReply<> RegisterApplication(const QDBusObjectPath &application, const QVariantMap &options)
+ {
+ QList<QVariant> argumentList;
+ argumentList << QVariant::fromValue(application) << QVariant::fromValue(options);
+ return asyncCallWithArgumentList(QStringLiteral("RegisterApplication"), argumentList);
+ }
+
+ inline QDBusPendingReply<> UnregisterApplication(const QDBusObjectPath &application)
+ {
+ QList<QVariant> argumentList;
+ argumentList << QVariant::fromValue(application);
+ return asyncCallWithArgumentList(QStringLiteral("UnregisterApplication"), argumentList);
+ }
+
+Q_SIGNALS: // SIGNALS
+};
+
+namespace org {
+ namespace bluez {
+ using GattManager1 = ::OrgBluezGattManager1Interface;
+ }
+}
+#endif
diff --git a/src/bluetooth/bluez/gattservice1.cpp b/src/bluetooth/bluez/gattservice1.cpp
index 0b80ac90..4a490c56 100644
--- a/src/bluetooth/bluez/gattservice1.cpp
+++ b/src/bluetooth/bluez/gattservice1.cpp
@@ -1,8 +1,8 @@
/*
* This file was generated by qdbusxml2cpp version 0.8
- * Command line was: qdbusxml2cpp -p gattservice1_p.h:gattservice1.cpp org.bluez.GattService1.xml
+ * Command line was: qdbusxml2cpp -I QtCore/private/qglobal_p.h -p gattservice1_p.h:gattservice1.cpp org.bluez.GattService1.xml
*
- * qdbusxml2cpp is Copyright (C) 2017 The Qt Company Ltd.
+ * qdbusxml2cpp is Copyright (C) 2022 The Qt Company Ltd.
*
* This is an auto-generated file.
* This file may have been hand-edited. Look for HAND-EDIT comments
@@ -24,3 +24,5 @@ OrgBluezGattService1Interface::~OrgBluezGattService1Interface()
{
}
+
+#include "moc_gattservice1_p.cpp"
diff --git a/src/bluetooth/bluez/gattservice1_p.h b/src/bluetooth/bluez/gattservice1_p.h
index 128305f1..3b2e1194 100644
--- a/src/bluetooth/bluez/gattservice1_p.h
+++ b/src/bluetooth/bluez/gattservice1_p.h
@@ -1,8 +1,8 @@
/*
* This file was generated by qdbusxml2cpp version 0.8
- * Command line was: qdbusxml2cpp -p gattservice1_p.h:gattservice1.cpp org.bluez.GattService1.xml
+ * Command line was: qdbusxml2cpp -I QtCore/private/qglobal_p.h -p gattservice1_p.h:gattservice1.cpp org.bluez.GattService1.xml
*
- * qdbusxml2cpp is Copyright (C) 2017 The Qt Company Ltd.
+ * qdbusxml2cpp is Copyright (C) 2022 The Qt Company Ltd.
*
* This is an auto-generated file.
* Do not edit! All changes made to it will be lost.
@@ -11,6 +11,17 @@
#ifndef GATTSERVICE1_P_H
#define GATTSERVICE1_P_H
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
#include <QtCore/QObject>
#include <QtCore/QByteArray>
#include <QtCore/QList>
@@ -19,6 +30,7 @@
#include <QtCore/QStringList>
#include <QtCore/QVariant>
#include <QtDBus/QtDBus>
+#include <QtCore/private/qglobal_p.h>
/*
* Proxy class for interface org.bluez.GattService1
@@ -57,7 +69,7 @@ Q_SIGNALS: // SIGNALS
namespace org {
namespace bluez {
- typedef ::OrgBluezGattService1Interface GattService1;
+ using GattService1 = ::OrgBluezGattService1Interface;
}
}
#endif
diff --git a/src/bluetooth/bluez/gattservice1adaptor.cpp b/src/bluetooth/bluez/gattservice1adaptor.cpp
new file mode 100644
index 00000000..365040c3
--- /dev/null
+++ b/src/bluetooth/bluez/gattservice1adaptor.cpp
@@ -0,0 +1,58 @@
+/*
+ * This file was generated by qdbusxml2cpp version 0.8
+ * Command line was: qdbusxml2cpp -a gattservice1adaptor_p.h:gattservice1adaptor.cpp -c OrgBluezGattService1Adaptor -i bluez5_helper_p.h org.bluez.GattService1.xml
+ *
+ * qdbusxml2cpp is Copyright (C) 2022 The Qt Company Ltd.
+ *
+ * This is an auto-generated file.
+ * Do not edit! All changes made to it will be lost.
+ */
+
+#include "gattservice1adaptor_p.h"
+#include <QtCore/QMetaObject>
+#include <QtCore/QByteArray>
+#include <QtCore/QList>
+#include <QtCore/QMap>
+#include <QtCore/QString>
+#include <QtCore/QStringList>
+#include <QtCore/QVariant>
+
+/*
+ * Implementation of adaptor class OrgBluezGattService1Adaptor
+ */
+
+OrgBluezGattService1Adaptor::OrgBluezGattService1Adaptor(QObject *parent)
+ : QDBusAbstractAdaptor(parent)
+{
+ // constructor
+ setAutoRelaySignals(true);
+}
+
+OrgBluezGattService1Adaptor::~OrgBluezGattService1Adaptor()
+{
+ // destructor
+}
+
+QDBusObjectPath OrgBluezGattService1Adaptor::device() const
+{
+ // get the value of property Device
+ return qvariant_cast< QDBusObjectPath >(parent()->property("Device"));
+}
+
+QList<QDBusObjectPath> OrgBluezGattService1Adaptor::includes() const
+{
+ // get the value of property Includes
+ return qvariant_cast< QList<QDBusObjectPath> >(parent()->property("Includes"));
+}
+
+bool OrgBluezGattService1Adaptor::primary() const
+{
+ // get the value of property Primary
+ return qvariant_cast< bool >(parent()->property("Primary"));
+}
+
+QString OrgBluezGattService1Adaptor::uUID() const
+{
+ // get the value of property UUID
+ return qvariant_cast< QString >(parent()->property("UUID"));
+}
diff --git a/src/bluetooth/bluez/gattservice1adaptor_p.h b/src/bluetooth/bluez/gattservice1adaptor_p.h
new file mode 100644
index 00000000..b9bd85a7
--- /dev/null
+++ b/src/bluetooth/bluez/gattservice1adaptor_p.h
@@ -0,0 +1,67 @@
+/*
+ * This file was generated by qdbusxml2cpp version 0.8
+ * Command line was: qdbusxml2cpp -a gattservice1adaptor_p.h:gattservice1adaptor.cpp -c OrgBluezGattService1Adaptor -i bluez5_helper_p.h org.bluez.GattService1.xml
+ *
+ * qdbusxml2cpp is Copyright (C) 2022 The Qt Company Ltd.
+ *
+ * This is an auto-generated file.
+ * This file may have been hand-edited. Look for HAND-EDIT comments
+ * before re-generating it.
+ */
+
+#ifndef GATTSERVICE1ADAPTOR_P_H
+#define GATTSERVICE1ADAPTOR_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/QObject>
+#include <QtDBus/QtDBus>
+#include "bluez5_helper_p.h"
+#include <QtCore/qcontainerfwd.h>
+
+/*
+ * Adaptor class for interface org.bluez.GattService1
+ */
+class OrgBluezGattService1Adaptor: public QDBusAbstractAdaptor
+{
+ Q_OBJECT
+ Q_CLASSINFO("D-Bus Interface", "org.bluez.GattService1")
+ Q_CLASSINFO("D-Bus Introspection", ""
+" <interface name=\"org.bluez.GattService1\">\n"
+" <property access=\"read\" type=\"s\" name=\"UUID\"/>\n"
+" <property access=\"read\" type=\"o\" name=\"Device\"/>\n"
+" <property access=\"read\" type=\"b\" name=\"Primary\"/>\n"
+" <property access=\"read\" type=\"ao\" name=\"Includes\"/>\n"
+" </interface>\n"
+ "")
+public:
+ OrgBluezGattService1Adaptor(QObject *parent);
+ virtual ~OrgBluezGattService1Adaptor();
+
+public: // PROPERTIES
+ Q_PROPERTY(QDBusObjectPath Device READ device)
+ QDBusObjectPath device() const;
+
+ Q_PROPERTY(QList<QDBusObjectPath> Includes READ includes)
+ QList<QDBusObjectPath> includes() const;
+
+ Q_PROPERTY(bool Primary READ primary)
+ bool primary() const;
+
+ Q_PROPERTY(QString UUID READ uUID)
+ QString uUID() const;
+
+public Q_SLOTS: // METHODS
+Q_SIGNALS: // SIGNALS
+};
+
+#endif
diff --git a/src/bluetooth/bluez/generate b/src/bluetooth/bluez/generate
index b3db63ff..f009f232 100755
--- a/src/bluetooth/bluez/generate
+++ b/src/bluetooth/bluez/generate
@@ -1,28 +1,31 @@
#!/bin/sh
-#Bluez 4
-qdbusxml2cpp -p manager_p.h:manager.cpp org.bluez.Manager.xml org.bluez.Manager
-qdbusxml2cpp -p adapter_p.h:adapter.cpp org.bluez.all.xml org.bluez.Adapter
-qdbusxml2cpp -i servicemap_p.h -p device_p.h:device.cpp org.bluez.Device.xml org.bluez.Device
-qdbusxml2cpp -p service_p.h:service.cpp org.bluez.all.xml org.bluez.Service
-qdbusxml2cpp -c OrgBluezAgentAdaptor -a agent_p.h:agent.cpp org.bluez.Agent.xml org.bluez.Agent
-qdbusxml2cpp -p obex_manager_p.h:obex_manager.cpp org.openobex.all.xml org.openobex.Manager
-qdbusxml2cpp -p obex_client_p.h:obex_client.cpp org.openobex.client.xml org.openobex.Client
-qdbusxml2cpp -p obex_transfer_p.h:obex_transfer.cpp org.openobex.transfer.xml org.openobex.Transfer
-qdbusxml2cpp -a obex_agent_p.h:obex_agent.cpp org.openobex.agent.xml org.openobex.Agent
+QGLOBAL_P_H=QtCore/private/qglobal_p.h
+
+process() {
+ CPP_BASENAME=$1
+ shift
+ XML_FILE="$1"
+ shift
+
+ HEADER_FILE=${CPP_BASENAME}_p.h
+ CPP_FILE=${CPP_BASENAME}.cpp
+ qdbusxml2cpp "$@" -I "$QGLOBAL_P_H" -p $HEADER_FILE:$CPP_FILE "$XML_FILE" --moc
+}
#Bluez 5
-qdbusxml2cpp -p adapter1_bluez5_p.h:adapter1_bluez5.cpp org.bluez.Adapter1.xml
-qdbusxml2cpp -i bluez5_helper_p.h -p device1_bluez5_p.h:device1_bluez5.cpp org.bluez.Device1.xml
-qdbusxml2cpp -p profilemanager1_p.h:profilemanager1.cpp org.bluez.ProfileManager1.xml
-qdbusxml2cpp -p profile1_p.h:profile1.cpp org.bluez.Profile1.xml
-qdbusxml2cpp -i bluez5_helper_p.h -p objectmanager_p.h:objectmanager.cpp org.freedesktop.dbus.objectmanager.xml
-qdbusxml2cpp -p properties_p.h:properties.cpp org.freedesktop.dbus.properties.xml
-qdbusxml2cpp -p obex_client1_bluez5_p.h:obex_client1_bluez5_p.h org.bluez.Client1.xml
-qdbusxml2cpp -p obex_objectpush1_bluez5_p.h:obex_objectpush1_bluez5.cpp org.bluez.obex.ObjectPush1.xml
-qdbusxml2cpp -p obex_transfer1_bluez5_p.h:obex_transfer1_bluez5_p.h org.bluez.obex.Transfer1.xml
-qdbusxml2cpp -p gattchar1_p.h:gattchar1.cpp org.bluez.GattCharacteristic1.xml
-qdbusxml2cpp -p gattdesc1_p.h:gattdesc1.cpp org.bluez.GattDescriptor1.xml
-qdbusxml2cpp -p gattservice1_p.h:gattservice1.cpp org.bluez.GattService1.xml
-qdbusxml2cpp -p battery1_p.h:battery1.cpp org.bluez.Battery1.xml
+process adapter1_bluez5 org.bluez.Adapter1.xml
+process device1_bluez5 org.bluez.Device1.xml -i bluez5_helper_p.h
+process profilemanager1 org.bluez.ProfileManager1.xml
+process profile1 org.bluez.Profile1.xml
+
+process objectmanager org.freedesktop.dbus.objectmanager.xml -i bluez5_helper_p.h
+process properties org.freedesktop.dbus.properties.xml
+
+process gattchar1 org.bluez.GattCharacteristic1.xml
+process gattdesc1 org.bluez.GattDescriptor1.xml
+process gattservice1 org.bluez.GattService1.xml
+process battery1 org.bluez.Battery1.xml
+process gattmanager1 org.bluez.GattManager1.xml
+process leadvertisingmanager1 org.bluez.LEAdvertisingManager1.xml
diff --git a/src/bluetooth/bluez/hcimanager.cpp b/src/bluetooth/bluez/hcimanager.cpp
index 845dfec0..573d603c 100644
--- a/src/bluetooth/bluez/hcimanager.cpp
+++ b/src/bluetooth/bluez/hcimanager.cpp
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2016 Javier S. Pedro <maemo@javispedro.com>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2016 Javier S. Pedro <maemo@javispedro.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "hcimanager_p.h"
@@ -57,8 +21,8 @@ QT_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(QT_BT_BLUEZ)
-HciManager::HciManager(const QBluetoothAddress& deviceAdapter, QObject *parent) :
- QObject(parent), hciSocket(-1), hciDev(-1)
+HciManager::HciManager(const QBluetoothAddress& deviceAdapter) :
+ QObject(nullptr), hciSocket(-1), hciDev(-1)
{
hciSocket = ::socket(AF_BLUETOOTH, SOCK_RAW | SOCK_CLOEXEC, BTPROTO_HCI);
if (hciSocket < 0) {
@@ -88,7 +52,7 @@ HciManager::HciManager(const QBluetoothAddress& deviceAdapter, QObject *parent)
}
notifier = new QSocketNotifier(hciSocket, QSocketNotifier::Read, this);
- connect(notifier, SIGNAL(activated(int)), this, SLOT(_q_readNotify()));
+ connect(notifier, SIGNAL(activated(QSocketDescriptor)), this, SLOT(_q_readNotify()));
}
@@ -168,7 +132,7 @@ bool HciManager::monitorEvent(HciManager::HciEvent event)
}
hci_filter_set_ptype(HCI_EVENT_PKT, &filter);
- hci_filter_set_event(event, &filter);
+ hci_filter_set_event(static_cast<int>(event), &filter);
//hci_filter_all_events(&filter);
if (setsockopt(hciSocket, SOL_HCI, HCI_FILTER, &filter, sizeof(hci_filter)) < 0) {
@@ -202,13 +166,13 @@ bool HciManager::monitorAclPackets()
return true;
}
-bool HciManager::sendCommand(OpCodeGroupField ogf, OpCodeCommandField ocf, const QByteArray &parameters)
+bool HciManager::sendCommand(QBluezConst::OpCodeGroupField ogf, QBluezConst::OpCodeCommandField ocf, const QByteArray &parameters)
{
qCDebug(QT_BT_BLUEZ) << "sending command; ogf:" << ogf << "ocf:" << ocf;
quint8 packetType = HCI_COMMAND_PKT;
hci_command_hdr command = {
opCodePack(ogf, ocf),
- static_cast<uint8_t>(parameters.count())
+ static_cast<uint8_t>(parameters.size())
};
static_assert(sizeof command == 3, "unexpected struct size");
struct iovec iv[3];
@@ -219,7 +183,7 @@ bool HciManager::sendCommand(OpCodeGroupField ogf, OpCodeCommandField ocf, const
int ivn = 2;
if (!parameters.isEmpty()) {
iv[2].iov_base = const_cast<char *>(parameters.constData()); // const_cast is safe, since iov_base will not get modified.
- iv[2].iov_len = parameters.count();
+ iv[2].iov_len = parameters.size();
++ivn;
}
while (writev(hciSocket, iv, ivn) < 0) {
@@ -284,10 +248,10 @@ QBluetoothAddress HciManager::addressForConnectionHandle(quint16 handle) const
return QBluetoothAddress();
}
-QVector<quint16> HciManager::activeLowEnergyConnections() const
+QList<quint16> HciManager::activeLowEnergyConnections() const
{
if (!isValid())
- return QVector<quint16>();
+ return QList<quint16>();
hci_conn_info *info;
hci_conn_list_req *infoList;
@@ -297,7 +261,7 @@ QVector<quint16> HciManager::activeLowEnergyConnections() const
malloc(sizeof(hci_conn_list_req) + maxNoOfConnections * sizeof(hci_conn_info));
if (!infoList)
- return QVector<quint16>();
+ return QList<quint16>();
QScopedPointer<hci_conn_list_req, QScopedPointerPodDeleter> p(infoList);
p->conn_num = maxNoOfConnections;
@@ -306,10 +270,10 @@ QVector<quint16> HciManager::activeLowEnergyConnections() const
if (ioctl(hciSocket, HCIGETCONNLIST, (void *) infoList) < 0) {
qCWarning(QT_BT_BLUEZ) << "Cannot retrieve connection list";
- return QVector<quint16>();
+ return QList<quint16>();
}
- QVector<quint16> activeLowEnergyHandles;
+ QList<quint16> activeLowEnergyHandles;
for (int i = 0; i < infoList->conn_num; i++) {
switch (info[i].type) {
case SCO_LINK:
@@ -369,7 +333,7 @@ bool HciManager::sendConnectionUpdateCommand(quint16 handle,
commandParams.maxCeLength = qToLittleEndian(quint16(0xffff));
const QByteArray data = QByteArray::fromRawData(reinterpret_cast<char *>(&commandParams),
sizeof commandParams);
- return sendCommand(OgfLinkControl, OcfLeConnectionUpdate, data);
+ return sendCommand(QBluezConst::OgfLinkControl, QBluezConst::OcfLeConnectionUpdate, data);
}
bool HciManager::sendConnectionParameterUpdateRequest(quint16 handle,
@@ -428,9 +392,8 @@ bool HciManager::sendConnectionParameterUpdateRequest(quint16 handle,
void HciManager::_q_readNotify()
{
unsigned char buffer[qMax<int>(HCI_MAX_EVENT_SIZE, sizeof(AclData))];
- int size;
- size = ::read(hciSocket, buffer, sizeof(buffer));
+ const auto size = ::read(hciSocket, buffer, sizeof(buffer));
if (size < 0) {
if (errno != EAGAIN && errno != EINTR)
qCWarning(QT_BT_BLUEZ) << "Failed reading HCI events:" << qt_error_string(errno);
@@ -467,11 +430,11 @@ void HciManager::handleHciEventPacket(const quint8 *data, int size)
return;
}
- qCDebug(QT_BT_BLUEZ) << "HCI event triggered, type:" << Qt::hex << header->evt;
+ qCDebug(QT_BT_BLUEZ) << "HCI event triggered, type:" << (HciManager::HciEvent)header->evt
+ << "type code:" << Qt::hex << header->evt;
- switch (header->evt) {
- case EVT_ENCRYPT_CHANGE:
- {
+ switch ((HciManager::HciEvent)header->evt) {
+ case HciEvent::EVT_ENCRYPT_CHANGE: {
const evt_encrypt_change *event = (evt_encrypt_change *) data;
qCDebug(QT_BT_BLUEZ) << "HCI Encrypt change, status:"
<< (event->status == 0 ? "Success" : "Failed")
@@ -481,9 +444,8 @@ void HciManager::handleHciEventPacket(const quint8 *data, int size)
QBluetoothAddress remoteDevice = addressForConnectionHandle(event->handle);
if (!remoteDevice.isNull())
emit encryptionChangedEvent(remoteDevice, event->status == 0);
- }
- break;
- case EVT_CMD_COMPLETE: {
+ } break;
+ case HciEvent::EVT_CMD_COMPLETE: {
auto * const event = reinterpret_cast<const evt_cmd_complete *>(data);
static_assert(sizeof *event == 3, "unexpected struct size");
@@ -493,9 +455,8 @@ void HciManager::handleHciEventPacket(const quint8 *data, int size)
const auto additionalData = QByteArray(reinterpret_cast<const char *>(data)
+ sizeof *event + 1, size - sizeof *event - 1);
emit commandCompleted(event->opcode, status, additionalData);
- }
- break;
- case LeMetaEvent:
+ } break;
+ case HciEvent::EVT_LE_META_EVENT:
handleLeMetaEvent(data);
break;
default:
@@ -555,7 +516,7 @@ void HciManager::handleHciAclPacket(const quint8 *data, int size)
qCWarning(QT_BT_BLUEZ) << "Unexpected key size" << size << "in Signing Information packet";
return;
}
- quint128 csrk;
+ BluezUint128 csrk;
memcpy(&csrk, data + 1, sizeof csrk);
const bool isRemoteKey = aclData->pbFlag == 2;
emit signatureResolvingKeyReceived(aclData->handle, isRemoteKey, csrk);
@@ -563,9 +524,11 @@ void HciManager::handleHciAclPacket(const quint8 *data, int size)
void HciManager::handleLeMetaEvent(const quint8 *data)
{
- // Spec v4.2, Vol 2, part E, 7.7.65ff
+ // Spec v5.3, Vol 4, part E, 7.7.65.*
switch (*data) {
- case 0x1: {
+ case 0x1: // HCI_LE_Connection_Complete
+ case 0xA: // HCI_LE_Enhanced_Connection_Complete
+ {
const quint16 handle = bt_get_le16(data + 2);
emit connectionComplete(handle);
break;
@@ -597,3 +560,5 @@ void HciManager::handleLeMetaEvent(const quint8 *data)
}
QT_END_NAMESPACE
+
+#include "moc_hcimanager_p.cpp"
diff --git a/src/bluetooth/bluez/hcimanager_p.h b/src/bluetooth/bluez/hcimanager_p.h
index 15b8791e..67ed900d 100644
--- a/src/bluetooth/bluez/hcimanager_p.h
+++ b/src/bluetooth/bluez/hcimanager_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef HCIMANAGER_P_H
#define HCIMANAGER_P_H
@@ -51,11 +15,11 @@
// We mean it.
//
-#include <QObject>
+#include <QtCore/QObject>
+#include <QtCore/QList>
#include <QtCore/QSet>
#include <QtCore/QSocketNotifier>
#include <QtBluetooth/QBluetoothAddress>
-#include <QVector>
#include "bluez/bluez_data_p.h"
QT_BEGIN_NAMESPACE
@@ -66,25 +30,145 @@ class HciManager : public QObject
{
Q_OBJECT
public:
- enum HciEvent {
- EncryptChangeEvent = EVT_ENCRYPT_CHANGE,
- CommandCompleteEvent = EVT_CMD_COMPLETE,
- LeMetaEvent = 0x3e,
+ enum class HciEvent {
+ EVT_INQUIRY_COMPLETE = 0x01,
+ EVT_INQUIRY_RESULT = 0x02,
+ EVT_CONN_COMPLETE = 0x03,
+ EVT_CONN_REQUEST = 0x04,
+ EVT_DISCONN_COMPLETE = 0x05,
+ EVT_AUTH_COMPLETE = 0x06,
+ EVT_REMOTE_NAME_REQ_COMPLETE = 0x07,
+ EVT_ENCRYPT_CHANGE = 0x08,
+ EVT_CHANGE_CONN_LINK_KEY_COMPLETE = 0x09,
+ EVT_MASTER_LINK_KEY_COMPLETE = 0x0A,
+ EVT_READ_REMOTE_FEATURES_COMPLETE = 0x0B,
+ EVT_READ_REMOTE_VERSION_COMPLETE = 0x0C,
+ EVT_QOS_SETUP_COMPLETE = 0x0D,
+ EVT_CMD_COMPLETE = 0x0E,
+ EVT_CMD_STATUS = 0x0F,
+ EVT_HARDWARE_ERROR = 0x10,
+ EVT_FLUSH_OCCURRED = 0x11,
+ EVT_ROLE_CHANGE = 0x12,
+ EVT_NUM_COMP_PKTS = 0x13,
+ EVT_MODE_CHANGE = 0x14,
+ EVT_RETURN_LINK_KEYS = 0x15,
+ EVT_PIN_CODE_REQ = 0x16,
+ EVT_LINK_KEY_REQ = 0x17,
+ EVT_LINK_KEY_NOTIFY = 0x18,
+ EVT_LOOPBACK_COMMAND = 0x19,
+ EVT_DATA_BUFFER_OVERFLOW = 0x1A,
+ EVT_MAX_SLOTS_CHANGE = 0x1B,
+ EVT_READ_CLOCK_OFFSET_COMPLETE = 0x1C,
+ EVT_CONN_PTYPE_CHANGED = 0x1D,
+ EVT_QOS_VIOLATION = 0x1E,
+ EVT_PSCAN_REP_MODE_CHANGE = 0x20,
+ EVT_FLOW_SPEC_COMPLETE = 0x21,
+ EVT_INQUIRY_RESULT_WITH_RSSI = 0x22,
+ EVT_READ_REMOTE_EXT_FEATURES_COMPLETE = 0x23,
+ EVT_SYNC_CONN_COMPLETE = 0x2C,
+ EVT_SYNC_CONN_CHANGED = 0x2D,
+ EVT_SNIFF_SUBRATING = 0x2E,
+ EVT_EXTENDED_INQUIRY_RESULT = 0x2F,
+ EVT_ENCRYPTION_KEY_REFRESH_COMPLETE = 0x30,
+ EVT_IO_CAPABILITY_REQUEST = 0x31,
+ EVT_IO_CAPABILITY_RESPONSE = 0x32,
+ EVT_USER_CONFIRM_REQUEST = 0x33,
+ EVT_USER_PASSKEY_REQUEST = 0x34,
+ EVT_REMOTE_OOB_DATA_REQUEST = 0x35,
+ EVT_SIMPLE_PAIRING_COMPLETE = 0x36,
+ EVT_LINK_SUPERVISION_TIMEOUT_CHANGED = 0x38,
+ EVT_ENHANCED_FLUSH_COMPLETE = 0x39,
+ EVT_USER_PASSKEY_NOTIFY = 0x3B,
+ EVT_KEYPRESS_NOTIFY = 0x3C,
+ EVT_REMOTE_HOST_FEATURES_NOTIFY = 0x3D,
+ EVT_LE_META_EVENT = 0x3E,
+ EVT_PHYSICAL_LINK_COMPLETE = 0x40,
+ EVT_CHANNEL_SELECTED = 0x41,
+ EVT_DISCONNECT_PHYSICAL_LINK_COMPLETE = 0x42,
+ EVT_PHYSICAL_LINK_LOSS_EARLY_WARNING = 0x43,
+ EVT_PHYSICAL_LINK_RECOVERY = 0x44,
+ EVT_LOGICAL_LINK_COMPLETE = 0x45,
+ EVT_DISCONNECT_LOGICAL_LINK_COMPLETE = 0x46,
+ EVT_FLOW_SPEC_MODIFY_COMPLETE = 0x47,
+ EVT_NUMBER_COMPLETED_BLOCKS = 0x48,
+ EVT_AMP_STATUS_CHANGE = 0x4D,
+ EVT_TESTING = 0xFE,
+ EVT_VENDOR = 0xFF,
+ EVT_STACK_INTERNAL = 0xFD
};
+ Q_ENUM(HciEvent);
+
+ enum class HciError {
+ HCI_SUCCESS = 0x00, // added for convenience, not in bluez code
+ HCI_UNKNOWN_COMMAND = 0x01,
+ HCI_NO_CONNECTION = 0x02,
+ HCI_HARDWARE_FAILURE = 0x03,
+ HCI_PAGE_TIMEOUT = 0x04,
+ HCI_AUTHENTICATION_FAILURE = 0x05,
+ HCI_PIN_OR_KEY_MISSING = 0x06,
+ HCI_MEMORY_FULL = 0x07,
+ HCI_CONNECTION_TIMEOUT = 0x08,
+ HCI_MAX_NUMBER_OF_CONNECTIONS = 0x09,
+ HCI_MAX_NUMBER_OF_SCO_CONNECTIONS = 0x0a,
+ HCI_ACL_CONNECTION_EXISTS = 0x0b,
+ HCI_COMMAND_DISALLOWED = 0x0c,
+ HCI_REJECTED_LIMITED_RESOURCES = 0x0d,
+ HCI_REJECTED_SECURITY = 0x0e,
+ HCI_REJECTED_PERSONAL = 0x0f,
+ HCI_HOST_TIMEOUT = 0x10,
+ HCI_UNSUPPORTED_FEATURE = 0x11,
+ HCI_INVALID_PARAMETERS = 0x12,
+ HCI_OE_USER_ENDED_CONNECTION = 0x13,
+ HCI_OE_LOW_RESOURCES = 0x14,
+ HCI_OE_POWER_OFF = 0x15,
+ HCI_CONNECTION_TERMINATED = 0x16,
+ HCI_REPEATED_ATTEMPTS = 0x17,
+ HCI_PAIRING_NOT_ALLOWED = 0x18,
+ HCI_UNKNOWN_LMP_PDU = 0x19,
+ HCI_UNSUPPORTED_REMOTE_FEATURE = 0x1a,
+ HCI_SCO_OFFSET_REJECTED = 0x1b,
+ HCI_SCO_INTERVAL_REJECTED = 0x1c,
+ HCI_AIR_MODE_REJECTED = 0x1d,
+ HCI_INVALID_LMP_PARAMETERS = 0x1e,
+ HCI_UNSPECIFIED_ERROR = 0x1f,
+ HCI_UNSUPPORTED_LMP_PARAMETER_VALUE = 0x20,
+ HCI_ROLE_CHANGE_NOT_ALLOWED = 0x21,
+ HCI_LMP_RESPONSE_TIMEOUT = 0x22,
+ HCI_LMP_ERROR_TRANSACTION_COLLISION = 0x23,
+ HCI_LMP_PDU_NOT_ALLOWED = 0x24,
+ HCI_ENCRYPTION_MODE_NOT_ACCEPTED = 0x25,
+ HCI_UNIT_LINK_KEY_USED = 0x26,
+ HCI_QOS_NOT_SUPPORTED = 0x27,
+ HCI_INSTANT_PASSED = 0x28,
+ HCI_PAIRING_NOT_SUPPORTED = 0x29,
+ HCI_TRANSACTION_COLLISION = 0x2a,
+ HCI_QOS_UNACCEPTABLE_PARAMETER = 0x2c,
+ HCI_QOS_REJECTED = 0x2d,
+ HCI_CLASSIFICATION_NOT_SUPPORTED = 0x2e,
+ HCI_INSUFFICIENT_SECURITY = 0x2f,
+ HCI_PARAMETER_OUT_OF_RANGE = 0x30,
+ HCI_ROLE_SWITCH_PENDING = 0x32,
+ HCI_SLOT_VIOLATION = 0x34,
+ HCI_ROLE_SWITCH_FAILED = 0x35,
+ HCI_EIR_TOO_LARGE = 0x36,
+ HCI_SIMPLE_PAIRING_NOT_SUPPORTED = 0x37,
+ HCI_HOST_BUSY_PAIRING = 0x38
+ };
+ Q_ENUM(HciError);
- explicit HciManager(const QBluetoothAddress &deviceAdapter, QObject *parent = nullptr);
+ explicit HciManager(const QBluetoothAddress &deviceAdapter);
~HciManager();
bool isValid() const;
bool monitorEvent(HciManager::HciEvent event);
bool monitorAclPackets();
- bool sendCommand(OpCodeGroupField ogf, OpCodeCommandField ocf, const QByteArray &parameters);
+ bool sendCommand(QBluezConst::OpCodeGroupField ogf, QBluezConst::OpCodeCommandField ocf, const QByteArray &parameters);
void stopEvents();
QBluetoothAddress addressForConnectionHandle(quint16 handle) const;
// active connections
- QVector<quint16> activeLowEnergyConnections() const;
+ QList<quint16> activeLowEnergyConnections() const;
bool sendConnectionUpdateCommand(quint16 handle, const QLowEnergyConnectionParameters &params);
bool sendConnectionParameterUpdateRequest(quint16 handle,
@@ -95,7 +179,7 @@ signals:
void commandCompleted(quint16 opCode, quint8 status, const QByteArray &data);
void connectionComplete(quint16 handle);
void connectionUpdate(quint16 handle, const QLowEnergyConnectionParameters &parameters);
- void signatureResolvingKeyReceived(quint16 connHandle, bool remoteKey, const quint128 &csrk);
+ void signatureResolvingKeyReceived(quint16 connHandle, bool remoteKey, BluezUint128 csrk);
private slots:
void _q_readNotify();
diff --git a/src/bluetooth/bluez/leadvertisement1.cpp b/src/bluetooth/bluez/leadvertisement1.cpp
new file mode 100644
index 00000000..e1b91c4a
--- /dev/null
+++ b/src/bluetooth/bluez/leadvertisement1.cpp
@@ -0,0 +1,136 @@
+/*
+ * This file was generated by qdbusxml2cpp version 0.8
+ * Command line was: qdbusxml2cpp -a leadvertisement1_p.h:leadvertisement1.cpp -c OrgBluezLEAdvertisement1Adaptor -i bluez5_helper_p.h org.bluez.LEAdvertisement1.xml
+ *
+ * qdbusxml2cpp is Copyright (C) 2022 The Qt Company Ltd.
+ *
+ * This is an auto-generated file.
+ * Do not edit! All changes made to it will be lost.
+ */
+
+#include "leadvertisement1_p.h"
+#include <QtCore/QMetaObject>
+#include <QtCore/QByteArray>
+#include <QtCore/QList>
+#include <QtCore/QMap>
+#include <QtCore/QString>
+#include <QtCore/QStringList>
+#include <QtCore/QVariant>
+
+/*
+ * Implementation of adaptor class OrgBluezLEAdvertisement1Adaptor
+ */
+
+OrgBluezLEAdvertisement1Adaptor::OrgBluezLEAdvertisement1Adaptor(QObject *parent)
+ : QDBusAbstractAdaptor(parent)
+{
+ // constructor
+ setAutoRelaySignals(true);
+}
+
+OrgBluezLEAdvertisement1Adaptor::~OrgBluezLEAdvertisement1Adaptor()
+{
+ // destructor
+}
+
+bool OrgBluezLEAdvertisement1Adaptor::discoverable() const
+{
+ // get the value of property Discoverable
+ return qvariant_cast< bool >(parent()->property("Discoverable"));
+}
+
+void OrgBluezLEAdvertisement1Adaptor::setDiscoverable(bool value)
+{
+ // set the value of property Discoverable
+ parent()->setProperty("Discoverable", QVariant::fromValue(value));
+}
+
+QStringList OrgBluezLEAdvertisement1Adaptor::includes() const
+{
+ // get the value of property Includes
+ return qvariant_cast< QStringList >(parent()->property("Includes"));
+}
+
+void OrgBluezLEAdvertisement1Adaptor::setIncludes(const QStringList &value)
+{
+ // set the value of property Includes
+ parent()->setProperty("Includes", QVariant::fromValue(value));
+}
+
+QString OrgBluezLEAdvertisement1Adaptor::localName() const
+{
+ // get the value of property LocalName
+ return qvariant_cast< QString >(parent()->property("LocalName"));
+}
+
+void OrgBluezLEAdvertisement1Adaptor::setLocalName(const QString &value)
+{
+ // set the value of property LocalName
+ parent()->setProperty("LocalName", QVariant::fromValue(value));
+}
+
+ManufacturerDataList OrgBluezLEAdvertisement1Adaptor::manufacturerData() const
+{
+ // get the value of property ManufacturerData
+ return qvariant_cast< ManufacturerDataList >(parent()->property("ManufacturerData"));
+}
+
+void OrgBluezLEAdvertisement1Adaptor::setManufacturerData(ManufacturerDataList value)
+{
+ // set the value of property ManufacturerData
+ parent()->setProperty("ManufacturerData", QVariant::fromValue(value));
+}
+
+uint OrgBluezLEAdvertisement1Adaptor::maxInterval() const
+{
+ // get the value of property MaxInterval
+ return qvariant_cast< uint >(parent()->property("MaxInterval"));
+}
+
+void OrgBluezLEAdvertisement1Adaptor::setMaxInterval(uint value)
+{
+ // set the value of property MaxInterval
+ parent()->setProperty("MaxInterval", QVariant::fromValue(value));
+}
+
+uint OrgBluezLEAdvertisement1Adaptor::minInterval() const
+{
+ // get the value of property MinInterval
+ return qvariant_cast< uint >(parent()->property("MinInterval"));
+}
+
+void OrgBluezLEAdvertisement1Adaptor::setMinInterval(uint value)
+{
+ // set the value of property MinInterval
+ parent()->setProperty("MinInterval", QVariant::fromValue(value));
+}
+
+QStringList OrgBluezLEAdvertisement1Adaptor::serviceUUIDs() const
+{
+ // get the value of property ServiceUUIDs
+ return qvariant_cast< QStringList >(parent()->property("ServiceUUIDs"));
+}
+
+void OrgBluezLEAdvertisement1Adaptor::setServiceUUIDs(const QStringList &value)
+{
+ // set the value of property ServiceUUIDs
+ parent()->setProperty("ServiceUUIDs", QVariant::fromValue(value));
+}
+
+QString OrgBluezLEAdvertisement1Adaptor::type() const
+{
+ // get the value of property Type
+ return qvariant_cast< QString >(parent()->property("Type"));
+}
+
+void OrgBluezLEAdvertisement1Adaptor::setType(const QString &value)
+{
+ // set the value of property Type
+ parent()->setProperty("Type", QVariant::fromValue(value));
+}
+
+void OrgBluezLEAdvertisement1Adaptor::Release()
+{
+ // handle method call org.bluez.LEAdvertisement1.Release
+ QMetaObject::invokeMethod(parent(), "Release");
+}
diff --git a/src/bluetooth/bluez/leadvertisement1_p.h b/src/bluetooth/bluez/leadvertisement1_p.h
new file mode 100644
index 00000000..8931e43c
--- /dev/null
+++ b/src/bluetooth/bluez/leadvertisement1_p.h
@@ -0,0 +1,97 @@
+/*
+ * This file was generated by qdbusxml2cpp version 0.8
+ * Command line was: qdbusxml2cpp -a leadvertisement1_p.h:leadvertisement1.cpp -c OrgBluezLEAdvertisement1Adaptor -i bluez5_helper_p.h org.bluez.LEAdvertisement1.xml
+ *
+ * qdbusxml2cpp is Copyright (C) 2022 The Qt Company Ltd.
+ *
+ * This is an auto-generated file.
+ * This file may have been hand-edited. Look for HAND-EDIT comments
+ * before re-generating it.
+ */
+
+#ifndef LEADVERTISEMENT1_P_H
+#define LEADVERTISEMENT1_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/QObject>
+#include <QtDBus/QtDBus>
+#include "bluez5_helper_p.h"
+#include <QtCore/qcontainerfwd.h>
+
+/*
+ * Adaptor class for interface org.bluez.LEAdvertisement1
+ */
+class OrgBluezLEAdvertisement1Adaptor: public QDBusAbstractAdaptor
+{
+ Q_OBJECT
+ Q_CLASSINFO("D-Bus Interface", "org.bluez.LEAdvertisement1")
+ Q_CLASSINFO("D-Bus Introspection", ""
+" <interface name=\"org.bluez.LEAdvertisement1\">\n"
+" <method name=\"Release\">\n"
+" <annotation value=\"true\" name=\"org.freedesktop.DBus.Method.NoReply\"/>\n"
+" </method>\n"
+" <property access=\"readwrite\" type=\"s\" name=\"Type\"/>\n"
+" <property access=\"readwrite\" type=\"as\" name=\"ServiceUUIDs\"/>\n"
+" <property access=\"readwrite\" type=\"a{qv}\" name=\"ManufacturerData\">\n"
+" <annotation value=\"ManufacturerDataList\" name=\"org.qtproject.QtDBus.QtTypeName\"/>\n"
+" </property>\n"
+" <property access=\"readwrite\" type=\"b\" name=\"Discoverable\"/>\n"
+" <property access=\"readwrite\" type=\"as\" name=\"Includes\"/>\n"
+" <property access=\"readwrite\" type=\"s\" name=\"LocalName\"/>\n"
+" <property access=\"readwrite\" type=\"u\" name=\"MinInterval\"/>\n"
+" <property access=\"readwrite\" type=\"u\" name=\"MaxInterval\"/>\n"
+" </interface>\n"
+ "")
+public:
+ OrgBluezLEAdvertisement1Adaptor(QObject *parent);
+ virtual ~OrgBluezLEAdvertisement1Adaptor();
+
+public: // PROPERTIES
+ Q_PROPERTY(bool Discoverable READ discoverable WRITE setDiscoverable)
+ bool discoverable() const;
+ void setDiscoverable(bool value);
+
+ Q_PROPERTY(QStringList Includes READ includes WRITE setIncludes)
+ QStringList includes() const;
+ void setIncludes(const QStringList &value);
+
+ Q_PROPERTY(QString LocalName READ localName WRITE setLocalName)
+ QString localName() const;
+ void setLocalName(const QString &value);
+
+ Q_PROPERTY(ManufacturerDataList ManufacturerData READ manufacturerData WRITE setManufacturerData)
+ ManufacturerDataList manufacturerData() const;
+ void setManufacturerData(ManufacturerDataList value);
+
+ Q_PROPERTY(uint MaxInterval READ maxInterval WRITE setMaxInterval)
+ uint maxInterval() const;
+ void setMaxInterval(uint value);
+
+ Q_PROPERTY(uint MinInterval READ minInterval WRITE setMinInterval)
+ uint minInterval() const;
+ void setMinInterval(uint value);
+
+ Q_PROPERTY(QStringList ServiceUUIDs READ serviceUUIDs WRITE setServiceUUIDs)
+ QStringList serviceUUIDs() const;
+ void setServiceUUIDs(const QStringList &value);
+
+ Q_PROPERTY(QString Type READ type WRITE setType)
+ QString type() const;
+ void setType(const QString &value);
+
+public Q_SLOTS: // METHODS
+ Q_NOREPLY void Release();
+Q_SIGNALS: // SIGNALS
+};
+
+#endif
diff --git a/src/bluetooth/bluez/leadvertisingmanager1.cpp b/src/bluetooth/bluez/leadvertisingmanager1.cpp
new file mode 100644
index 00000000..29690163
--- /dev/null
+++ b/src/bluetooth/bluez/leadvertisingmanager1.cpp
@@ -0,0 +1,28 @@
+/*
+ * This file was generated by qdbusxml2cpp version 0.8
+ * Command line was: qdbusxml2cpp -I QtCore/private/qglobal_p.h -p leadvertisingmanager1_p.h:leadvertisingmanager1.cpp org.bluez.LEAdvertisingManager1.xml --moc
+ *
+ * qdbusxml2cpp is Copyright (C) 2022 The Qt Company Ltd.
+ *
+ * This is an auto-generated file.
+ * This file may have been hand-edited. Look for HAND-EDIT comments
+ * before re-generating it.
+ */
+
+#include "leadvertisingmanager1_p.h"
+
+/*
+ * Implementation of interface class OrgBluezLEAdvertisingManager1Interface
+ */
+
+OrgBluezLEAdvertisingManager1Interface::OrgBluezLEAdvertisingManager1Interface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent)
+ : QDBusAbstractInterface(service, path, staticInterfaceName(), connection, parent)
+{
+}
+
+OrgBluezLEAdvertisingManager1Interface::~OrgBluezLEAdvertisingManager1Interface()
+{
+}
+
+
+#include "moc_leadvertisingmanager1_p.cpp"
diff --git a/src/bluetooth/bluez/leadvertisingmanager1_p.h b/src/bluetooth/bluez/leadvertisingmanager1_p.h
new file mode 100644
index 00000000..06a299b3
--- /dev/null
+++ b/src/bluetooth/bluez/leadvertisingmanager1_p.h
@@ -0,0 +1,85 @@
+/*
+ * This file was generated by qdbusxml2cpp version 0.8
+ * Command line was: qdbusxml2cpp -I QtCore/private/qglobal_p.h -p leadvertisingmanager1_p.h:leadvertisingmanager1.cpp org.bluez.LEAdvertisingManager1.xml --moc
+ *
+ * qdbusxml2cpp is Copyright (C) 2022 The Qt Company Ltd.
+ *
+ * This is an auto-generated file.
+ * Do not edit! All changes made to it will be lost.
+ */
+
+#ifndef LEADVERTISINGMANAGER1_P_H
+#define LEADVERTISINGMANAGER1_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/QObject>
+#include <QtCore/QByteArray>
+#include <QtCore/QList>
+#include <QtCore/QMap>
+#include <QtCore/QString>
+#include <QtCore/QStringList>
+#include <QtCore/QVariant>
+#include <QtDBus/QtDBus>
+#include <QtCore/private/qglobal_p.h>
+
+/*
+ * Proxy class for interface org.bluez.LEAdvertisingManager1
+ */
+class OrgBluezLEAdvertisingManager1Interface: public QDBusAbstractInterface
+{
+ Q_OBJECT
+public:
+ static inline const char *staticInterfaceName()
+ { return "org.bluez.LEAdvertisingManager1"; }
+
+public:
+ OrgBluezLEAdvertisingManager1Interface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = nullptr);
+
+ ~OrgBluezLEAdvertisingManager1Interface();
+
+ Q_PROPERTY(uchar ActiveInstances READ activeInstances)
+ inline uchar activeInstances() const
+ { return qvariant_cast< uchar >(property("ActiveInstances")); }
+
+ Q_PROPERTY(QStringList SupportedIncludes READ supportedIncludes)
+ inline QStringList supportedIncludes() const
+ { return qvariant_cast< QStringList >(property("SupportedIncludes")); }
+
+ Q_PROPERTY(uchar SupportedInstances READ supportedInstances)
+ inline uchar supportedInstances() const
+ { return qvariant_cast< uchar >(property("SupportedInstances")); }
+
+public Q_SLOTS: // METHODS
+ inline QDBusPendingReply<> RegisterAdvertisement(const QDBusObjectPath &advertisement, const QVariantMap &options)
+ {
+ QList<QVariant> argumentList;
+ argumentList << QVariant::fromValue(advertisement) << QVariant::fromValue(options);
+ return asyncCallWithArgumentList(QStringLiteral("RegisterAdvertisement"), argumentList);
+ }
+
+ inline QDBusPendingReply<> UnregisterAdvertisement(const QDBusObjectPath &advertisement)
+ {
+ QList<QVariant> argumentList;
+ argumentList << QVariant::fromValue(advertisement);
+ return asyncCallWithArgumentList(QStringLiteral("UnregisterAdvertisement"), argumentList);
+ }
+
+Q_SIGNALS: // SIGNALS
+};
+
+namespace org {
+ namespace bluez {
+ using LEAdvertisingManager1 = ::OrgBluezLEAdvertisingManager1Interface;
+ }
+}
+#endif
diff --git a/src/bluetooth/bluez/manager.cpp b/src/bluetooth/bluez/manager.cpp
deleted file mode 100644
index 8ca6fb42..00000000
--- a/src/bluetooth/bluez/manager.cpp
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * This file was generated by qdbusxml2cpp version 0.8
- * Command line was: qdbusxml2cpp -p manager_p.h:manager.cpp org.bluez.Manager.xml org.bluez.Manager
- *
- * qdbusxml2cpp is Copyright (C) 2017 The Qt Company Ltd.
- *
- * This is an auto-generated file.
- * This file may have been hand-edited. Look for HAND-EDIT comments
- * before re-generating it.
- */
-
-#include "manager_p.h"
-
-/*
- * Implementation of interface class OrgBluezManagerInterface
- */
-
-OrgBluezManagerInterface::OrgBluezManagerInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent)
- : QDBusAbstractInterface(service, path, staticInterfaceName(), connection, parent)
-{
-}
-
-OrgBluezManagerInterface::~OrgBluezManagerInterface()
-{
-}
-
diff --git a/src/bluetooth/bluez/manager_p.h b/src/bluetooth/bluez/manager_p.h
deleted file mode 100644
index a969e067..00000000
--- a/src/bluetooth/bluez/manager_p.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * This file was generated by qdbusxml2cpp version 0.8
- * Command line was: qdbusxml2cpp -p manager_p.h:manager.cpp org.bluez.Manager.xml org.bluez.Manager
- *
- * qdbusxml2cpp is Copyright (C) 2017 The Qt Company Ltd.
- *
- * This is an auto-generated file.
- * Do not edit! All changes made to it will be lost.
- */
-
-#ifndef MANAGER_P_H
-#define MANAGER_P_H
-
-#include <QtCore/QObject>
-#include <QtCore/QByteArray>
-#include <QtCore/QList>
-#include <QtCore/QMap>
-#include <QtCore/QString>
-#include <QtCore/QStringList>
-#include <QtCore/QVariant>
-#include <QtDBus/QtDBus>
-
-/*
- * Proxy class for interface org.bluez.Manager
- */
-class OrgBluezManagerInterface: public QDBusAbstractInterface
-{
- Q_OBJECT
-public:
- static inline const char *staticInterfaceName()
- { return "org.bluez.Manager"; }
-
-public:
- OrgBluezManagerInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = nullptr);
-
- ~OrgBluezManagerInterface();
-
-public Q_SLOTS: // METHODS
- inline QDBusPendingReply<QDBusObjectPath> DefaultAdapter()
- {
- QList<QVariant> argumentList;
- return asyncCallWithArgumentList(QStringLiteral("DefaultAdapter"), argumentList);
- }
-
- inline QDBusPendingReply<QDBusObjectPath> FindAdapter(const QString &in0)
- {
- QList<QVariant> argumentList;
- argumentList << QVariant::fromValue(in0);
- return asyncCallWithArgumentList(QStringLiteral("FindAdapter"), argumentList);
- }
-
- inline QDBusPendingReply<QList<QDBusObjectPath> > ListAdapters()
- {
- QList<QVariant> argumentList;
- return asyncCallWithArgumentList(QStringLiteral("ListAdapters"), argumentList);
- }
-
-Q_SIGNALS: // SIGNALS
- void AdapterAdded(const QDBusObjectPath &in0);
- void AdapterRemoved(const QDBusObjectPath &in0);
- void DefaultAdapterChanged(const QDBusObjectPath &in0);
-};
-
-namespace org {
- namespace bluez {
- typedef ::OrgBluezManagerInterface Manager;
- }
-}
-#endif
diff --git a/src/bluetooth/bluez/obex_agent.cpp b/src/bluetooth/bluez/obex_agent.cpp
deleted file mode 100644
index 5bc05f87..00000000
--- a/src/bluetooth/bluez/obex_agent.cpp
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * This file was generated by qdbusxml2cpp version 0.8
- * Command line was: qdbusxml2cpp -a obex_agent_p.h:obex_agent.cpp org.openobex.agent.xml org.openobex.Agent
- *
- * qdbusxml2cpp is Copyright (C) 2017 The Qt Company Ltd.
- *
- * This is an auto-generated file.
- * Do not edit! All changes made to it will be lost.
- */
-
-#include "obex_agent_p.h"
-#include <QtCore/QMetaObject>
-#include <QtCore/QByteArray>
-#include <QtCore/QList>
-#include <QtCore/QMap>
-#include <QtCore/QString>
-#include <QtCore/QStringList>
-#include <QtCore/QVariant>
-
-/*
- * Implementation of adaptor class AgentAdaptor
- */
-
-AgentAdaptor::AgentAdaptor(QObject *parent)
- : QDBusAbstractAdaptor(parent)
-{
- // constructor
- setAutoRelaySignals(true);
-}
-
-AgentAdaptor::~AgentAdaptor()
-{
- // destructor
-}
-
-void AgentAdaptor::Complete(const QDBusObjectPath &in0)
-{
- // handle method call org.openobex.Agent.Complete
- QMetaObject::invokeMethod(parent(), "Complete", Q_ARG(QDBusObjectPath, in0));
-}
-
-void AgentAdaptor::Error(const QDBusObjectPath &in0, const QString &in1)
-{
- // handle method call org.openobex.Agent.Error
- QMetaObject::invokeMethod(parent(), "Error", Q_ARG(QDBusObjectPath, in0), Q_ARG(QString, in1));
-}
-
-void AgentAdaptor::Progress(const QDBusObjectPath &in0, qulonglong in1)
-{
- // handle method call org.openobex.Agent.Progress
- QMetaObject::invokeMethod(parent(), "Progress", Q_ARG(QDBusObjectPath, in0), Q_ARG(qulonglong, in1));
-}
-
-void AgentAdaptor::Release()
-{
- // handle method call org.openobex.Agent.Release
- QMetaObject::invokeMethod(parent(), "Release");
-}
-
-QString AgentAdaptor::Request(const QDBusObjectPath &in0)
-{
- // handle method call org.openobex.Agent.Request
- QString out0;
- QMetaObject::invokeMethod(parent(), "Request", Q_RETURN_ARG(QString, out0), Q_ARG(QDBusObjectPath, in0));
- return out0;
-}
-
diff --git a/src/bluetooth/bluez/obex_agent_p.h b/src/bluetooth/bluez/obex_agent_p.h
deleted file mode 100644
index b370810d..00000000
--- a/src/bluetooth/bluez/obex_agent_p.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * This file was generated by qdbusxml2cpp version 0.8
- * Command line was: qdbusxml2cpp -a obex_agent_p.h:obex_agent.cpp org.openobex.agent.xml org.openobex.Agent
- *
- * qdbusxml2cpp is Copyright (C) 2017 The Qt Company Ltd.
- *
- * This is an auto-generated file.
- * This file may have been hand-edited. Look for HAND-EDIT comments
- * before re-generating it.
- */
-
-#ifndef OBEX_AGENT_P_H
-#define OBEX_AGENT_P_H
-
-#include <QtCore/QObject>
-#include <QtCore/qcontainerfwd.h>
-#include <QtDBus/QtDBus>
-QT_BEGIN_NAMESPACE
-class QByteArray;
-class QString;
-class QStringList;
-class QVariant;
-QT_END_NAMESPACE
-
-/*
- * Adaptor class for interface org.openobex.Agent
- */
-class AgentAdaptor: public QDBusAbstractAdaptor
-{
- Q_OBJECT
- Q_CLASSINFO("D-Bus Interface", "org.openobex.Agent")
- Q_CLASSINFO("D-Bus Introspection", ""
-" <interface name=\"org.openobex.Agent\">\n"
-" <method name=\"Release\"/>\n"
-" <method name=\"Request\">\n"
-" <arg direction=\"in\" type=\"o\"/>\n"
-" <arg direction=\"out\" type=\"s\"/>\n"
-" </method>\n"
-" <method name=\"Progress\">\n"
-" <arg direction=\"in\" type=\"o\"/>\n"
-" <arg direction=\"in\" type=\"t\"/>\n"
-" </method>\n"
-" <method name=\"Complete\">\n"
-" <arg direction=\"in\" type=\"o\"/>\n"
-" </method>\n"
-" <method name=\"Error\">\n"
-" <arg direction=\"in\" type=\"o\"/>\n"
-" <arg direction=\"in\" type=\"s\"/>\n"
-" </method>\n"
-" </interface>\n"
- "")
-public:
- AgentAdaptor(QObject *parent);
- virtual ~AgentAdaptor();
-
-public: // PROPERTIES
-public Q_SLOTS: // METHODS
- void Complete(const QDBusObjectPath &in0);
- void Error(const QDBusObjectPath &in0, const QString &in1);
- void Progress(const QDBusObjectPath &in0, qulonglong in1);
- void Release();
- QString Request(const QDBusObjectPath &in0);
-Q_SIGNALS: // SIGNALS
-};
-
-#endif
diff --git a/src/bluetooth/bluez/obex_client.cpp b/src/bluetooth/bluez/obex_client.cpp
deleted file mode 100644
index bef9155a..00000000
--- a/src/bluetooth/bluez/obex_client.cpp
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * This file was generated by qdbusxml2cpp version 0.8
- * Command line was: qdbusxml2cpp -p obex_client_p.h:obex_client.cpp org.openobex.client.xml org.openobex.Client
- *
- * qdbusxml2cpp is Copyright (C) 2017 The Qt Company Ltd.
- *
- * This is an auto-generated file.
- * This file may have been hand-edited. Look for HAND-EDIT comments
- * before re-generating it.
- */
-
-#include "obex_client_p.h"
-
-/*
- * Implementation of interface class OrgOpenobexClientInterface
- */
-
-OrgOpenobexClientInterface::OrgOpenobexClientInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent)
- : QDBusAbstractInterface(service, path, staticInterfaceName(), connection, parent)
-{
-}
-
-OrgOpenobexClientInterface::~OrgOpenobexClientInterface()
-{
-}
-
diff --git a/src/bluetooth/bluez/obex_client1_bluez5.cpp b/src/bluetooth/bluez/obex_client1_bluez5.cpp
deleted file mode 100644
index fb66708a..00000000
--- a/src/bluetooth/bluez/obex_client1_bluez5.cpp
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * This file was generated by qdbusxml2cpp version 0.8
- * Command line was: qdbusxml2cpp org.bluez.Client1.xml -p asd
- *
- * qdbusxml2cpp is Copyright (C) 2015 The Qt Company Ltd.
- *
- * This is an auto-generated file.
- * This file may have been hand-edited. Look for HAND-EDIT comments
- * before re-generating it.
- */
-
-#include "obex_client1_bluez5_p.h"
-
-/*
- * Implementation of interface class OrgBluezObexClient1Interface
- */
-
-OrgBluezObexClient1Interface::OrgBluezObexClient1Interface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent)
- : QDBusAbstractInterface(service, path, staticInterfaceName(), connection, parent)
-{
-}
-
-OrgBluezObexClient1Interface::~OrgBluezObexClient1Interface()
-{
-}
-
diff --git a/src/bluetooth/bluez/obex_client1_bluez5_p.h b/src/bluetooth/bluez/obex_client1_bluez5_p.h
deleted file mode 100644
index ccd5b0d6..00000000
--- a/src/bluetooth/bluez/obex_client1_bluez5_p.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * This file was generated by qdbusxml2cpp version 0.8
- * Command line was: qdbusxml2cpp -p obex_client1_bluez5_p.h:obex_client1_bluez5_p.h org.bluez.Client1.xml
- *
- * qdbusxml2cpp is Copyright (C) 2017 The Qt Company Ltd.
- *
- * This is an auto-generated file.
- * Do not edit! All changes made to it will be lost.
- */
-
-#ifndef OBEX_CLIENT1_BLUEZ5_P_H
-#define OBEX_CLIENT1_BLUEZ5_P_H
-
-#include <QtCore/QObject>
-#include <QtCore/QByteArray>
-#include <QtCore/QList>
-#include <QtCore/QMap>
-#include <QtCore/QString>
-#include <QtCore/QStringList>
-#include <QtCore/QVariant>
-#include <QtDBus/QtDBus>
-
-/*
- * Proxy class for interface org.bluez.obex.Client1
- */
-class OrgBluezObexClient1Interface: public QDBusAbstractInterface
-{
- Q_OBJECT
-public:
- static inline const char *staticInterfaceName()
- { return "org.bluez.obex.Client1"; }
-
-public:
- OrgBluezObexClient1Interface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = nullptr);
-
- ~OrgBluezObexClient1Interface();
-
-public Q_SLOTS: // METHODS
- inline QDBusPendingReply<QDBusObjectPath> CreateSession(const QString &destination, const QVariantMap &args)
- {
- QList<QVariant> argumentList;
- argumentList << QVariant::fromValue(destination) << QVariant::fromValue(args);
- return asyncCallWithArgumentList(QStringLiteral("CreateSession"), argumentList);
- }
-
- inline QDBusPendingReply<> RemoveSession(const QDBusObjectPath &session)
- {
- QList<QVariant> argumentList;
- argumentList << QVariant::fromValue(session);
- return asyncCallWithArgumentList(QStringLiteral("RemoveSession"), argumentList);
- }
-
-Q_SIGNALS: // SIGNALS
-};
-
-namespace org {
- namespace bluez {
- namespace obex {
- typedef ::OrgBluezObexClient1Interface Client1;
- }
- }
-}
-#endif
diff --git a/src/bluetooth/bluez/obex_client_p.h b/src/bluetooth/bluez/obex_client_p.h
deleted file mode 100644
index 13b638b6..00000000
--- a/src/bluetooth/bluez/obex_client_p.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * This file was generated by qdbusxml2cpp version 0.8
- * Command line was: qdbusxml2cpp -p obex_client_p.h:obex_client.cpp org.openobex.client.xml org.openobex.Client
- *
- * qdbusxml2cpp is Copyright (C) 2017 The Qt Company Ltd.
- *
- * This is an auto-generated file.
- * Do not edit! All changes made to it will be lost.
- */
-
-#ifndef OBEX_CLIENT_P_H
-#define OBEX_CLIENT_P_H
-
-#include <QtCore/QObject>
-#include <QtCore/QByteArray>
-#include <QtCore/QList>
-#include <QtCore/QMap>
-#include <QtCore/QString>
-#include <QtCore/QStringList>
-#include <QtCore/QVariant>
-#include <QtDBus/QtDBus>
-
-/*
- * Proxy class for interface org.openobex.Client
- */
-class OrgOpenobexClientInterface: public QDBusAbstractInterface
-{
- Q_OBJECT
-public:
- static inline const char *staticInterfaceName()
- { return "org.openobex.Client"; }
-
-public:
- OrgOpenobexClientInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = nullptr);
-
- ~OrgOpenobexClientInterface();
-
-public Q_SLOTS: // METHODS
- inline QDBusPendingReply<QDBusObjectPath> CreateSession(const QVariantMap &in0)
- {
- QList<QVariant> argumentList;
- argumentList << QVariant::fromValue(in0);
- return asyncCallWithArgumentList(QStringLiteral("CreateSession"), argumentList);
- }
-
- inline QDBusPendingReply<> ExchangeBusinessCards(const QVariantMap &in0, const QString &in1, const QString &in2)
- {
- QList<QVariant> argumentList;
- argumentList << QVariant::fromValue(in0) << QVariant::fromValue(in1) << QVariant::fromValue(in2);
- return asyncCallWithArgumentList(QStringLiteral("ExchangeBusinessCards"), argumentList);
- }
-
- inline QDBusPendingReply<QString> GetCapabilities(const QVariantMap &in0)
- {
- QList<QVariant> argumentList;
- argumentList << QVariant::fromValue(in0);
- return asyncCallWithArgumentList(QStringLiteral("GetCapabilities"), argumentList);
- }
-
- inline QDBusPendingReply<> PullBusinessCard(const QVariantMap &in0, const QString &in1)
- {
- QList<QVariant> argumentList;
- argumentList << QVariant::fromValue(in0) << QVariant::fromValue(in1);
- return asyncCallWithArgumentList(QStringLiteral("PullBusinessCard"), argumentList);
- }
-
- inline QDBusPendingReply<> SendFiles(const QVariantMap &in0, const QStringList &in1, const QDBusObjectPath &in2)
- {
- QList<QVariant> argumentList;
- argumentList << QVariant::fromValue(in0) << QVariant::fromValue(in1) << QVariant::fromValue(in2);
- return asyncCallWithArgumentList(QStringLiteral("SendFiles"), argumentList);
- }
-
-Q_SIGNALS: // SIGNALS
-};
-
-namespace org {
- namespace openobex {
- typedef ::OrgOpenobexClientInterface Client;
- }
-}
-#endif
diff --git a/src/bluetooth/bluez/obex_manager.cpp b/src/bluetooth/bluez/obex_manager.cpp
deleted file mode 100644
index cc6e0ecb..00000000
--- a/src/bluetooth/bluez/obex_manager.cpp
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * This file was generated by qdbusxml2cpp version 0.8
- * Command line was: qdbusxml2cpp -p obex_manager_p.h:obex_manager.cpp org.openobex.all.xml org.openobex.Manager
- *
- * qdbusxml2cpp is Copyright (C) 2017 The Qt Company Ltd.
- *
- * This is an auto-generated file.
- * This file may have been hand-edited. Look for HAND-EDIT comments
- * before re-generating it.
- */
-
-#include "obex_manager_p.h"
-
-/*
- * Implementation of interface class OrgOpenobexManagerInterface
- */
-
-OrgOpenobexManagerInterface::OrgOpenobexManagerInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent)
- : QDBusAbstractInterface(service, path, staticInterfaceName(), connection, parent)
-{
-}
-
-OrgOpenobexManagerInterface::~OrgOpenobexManagerInterface()
-{
-}
-
diff --git a/src/bluetooth/bluez/obex_manager_p.h b/src/bluetooth/bluez/obex_manager_p.h
deleted file mode 100644
index 822954ab..00000000
--- a/src/bluetooth/bluez/obex_manager_p.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * This file was generated by qdbusxml2cpp version 0.8
- * Command line was: qdbusxml2cpp -p obex_manager_p.h:obex_manager.cpp org.openobex.all.xml org.openobex.Manager
- *
- * qdbusxml2cpp is Copyright (C) 2017 The Qt Company Ltd.
- *
- * This is an auto-generated file.
- * Do not edit! All changes made to it will be lost.
- */
-
-#ifndef OBEX_MANAGER_P_H
-#define OBEX_MANAGER_P_H
-
-#include <QtCore/QObject>
-#include <QtCore/QByteArray>
-#include <QtCore/QList>
-#include <QtCore/QMap>
-#include <QtCore/QString>
-#include <QtCore/QStringList>
-#include <QtCore/QVariant>
-#include <QtDBus/QtDBus>
-
-/*
- * Proxy class for interface org.openobex.Manager
- */
-class OrgOpenobexManagerInterface: public QDBusAbstractInterface
-{
- Q_OBJECT
-public:
- static inline const char *staticInterfaceName()
- { return "org.openobex.Manager"; }
-
-public:
- OrgOpenobexManagerInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = nullptr);
-
- ~OrgOpenobexManagerInterface();
-
-public Q_SLOTS: // METHODS
- inline QDBusPendingReply<> RegisterAgent(const QDBusObjectPath &in0)
- {
- QList<QVariant> argumentList;
- argumentList << QVariant::fromValue(in0);
- return asyncCallWithArgumentList(QStringLiteral("RegisterAgent"), argumentList);
- }
-
- inline QDBusPendingReply<> UnregisterAgent(const QDBusObjectPath &in0)
- {
- QList<QVariant> argumentList;
- argumentList << QVariant::fromValue(in0);
- return asyncCallWithArgumentList(QStringLiteral("UnregisterAgent"), argumentList);
- }
-
-Q_SIGNALS: // SIGNALS
- void SessionCreated(const QDBusObjectPath &in0);
- void SessionRemoved(const QDBusObjectPath &in0);
- void TransferCompleted(const QDBusObjectPath &in0, bool in1);
- void TransferStarted(const QDBusObjectPath &in0);
-};
-
-namespace org {
- namespace openobex {
- typedef ::OrgOpenobexManagerInterface Manager;
- }
-}
-#endif
diff --git a/src/bluetooth/bluez/obex_objectpush1_bluez5.cpp b/src/bluetooth/bluez/obex_objectpush1_bluez5.cpp
deleted file mode 100644
index 59b94e80..00000000
--- a/src/bluetooth/bluez/obex_objectpush1_bluez5.cpp
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * This file was generated by qdbusxml2cpp version 0.8
- * Command line was: qdbusxml2cpp -p obex_objectpush1_bluez5_p.h:obex_objectpush1_bluez5.cpp org.bluez.obex.ObjectPush1.xml
- *
- * qdbusxml2cpp is Copyright (C) 2017 The Qt Company Ltd.
- *
- * This is an auto-generated file.
- * This file may have been hand-edited. Look for HAND-EDIT comments
- * before re-generating it.
- */
-
-#include "obex_objectpush1_bluez5_p.h"
-
-/*
- * Implementation of interface class OrgBluezObexObjectPush1Interface
- */
-
-OrgBluezObexObjectPush1Interface::OrgBluezObexObjectPush1Interface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent)
- : QDBusAbstractInterface(service, path, staticInterfaceName(), connection, parent)
-{
-}
-
-OrgBluezObexObjectPush1Interface::~OrgBluezObexObjectPush1Interface()
-{
-}
-
diff --git a/src/bluetooth/bluez/obex_objectpush1_bluez5_p.h b/src/bluetooth/bluez/obex_objectpush1_bluez5_p.h
deleted file mode 100644
index 5fa1703b..00000000
--- a/src/bluetooth/bluez/obex_objectpush1_bluez5_p.h
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * This file was generated by qdbusxml2cpp version 0.8
- * Command line was: qdbusxml2cpp -p obex_objectpush1_bluez5_p.h:obex_objectpush1_bluez5.cpp org.bluez.obex.ObjectPush1.xml
- *
- * qdbusxml2cpp is Copyright (C) 2017 The Qt Company Ltd.
- *
- * This is an auto-generated file.
- * Do not edit! All changes made to it will be lost.
- */
-
-#ifndef OBEX_OBJECTPUSH1_BLUEZ5_P_H
-#define OBEX_OBJECTPUSH1_BLUEZ5_P_H
-
-#include <QtCore/QObject>
-#include <QtCore/QByteArray>
-#include <QtCore/QList>
-#include <QtCore/QMap>
-#include <QtCore/QString>
-#include <QtCore/QStringList>
-#include <QtCore/QVariant>
-#include <QtDBus/QtDBus>
-
-/*
- * Proxy class for interface org.bluez.obex.ObjectPush1
- */
-class OrgBluezObexObjectPush1Interface: public QDBusAbstractInterface
-{
- Q_OBJECT
-public:
- static inline const char *staticInterfaceName()
- { return "org.bluez.obex.ObjectPush1"; }
-
-public:
- OrgBluezObexObjectPush1Interface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = nullptr);
-
- ~OrgBluezObexObjectPush1Interface();
-
-public Q_SLOTS: // METHODS
- inline QDBusPendingReply<QDBusObjectPath, QVariantMap> ExchangeBusinessCards(const QString &clientfile, const QString &targetfile)
- {
- QList<QVariant> argumentList;
- argumentList << QVariant::fromValue(clientfile) << QVariant::fromValue(targetfile);
- return asyncCallWithArgumentList(QStringLiteral("ExchangeBusinessCards"), argumentList);
- }
- inline QDBusReply<QDBusObjectPath> ExchangeBusinessCards(const QString &clientfile, const QString &targetfile, QVariantMap &properties)
- {
- QList<QVariant> argumentList;
- argumentList << QVariant::fromValue(clientfile) << QVariant::fromValue(targetfile);
- QDBusMessage reply = callWithArgumentList(QDBus::Block, QStringLiteral("ExchangeBusinessCards"), argumentList);
- if (reply.type() == QDBusMessage::ReplyMessage && reply.arguments().count() == 2) {
- properties = qdbus_cast<QVariantMap>(reply.arguments().at(1));
- }
- return reply;
- }
-
- inline QDBusPendingReply<QDBusObjectPath, QVariantMap> PullBusinessCard(const QString &targetfile)
- {
- QList<QVariant> argumentList;
- argumentList << QVariant::fromValue(targetfile);
- return asyncCallWithArgumentList(QStringLiteral("PullBusinessCard"), argumentList);
- }
- inline QDBusReply<QDBusObjectPath> PullBusinessCard(const QString &targetfile, QVariantMap &properties)
- {
- QList<QVariant> argumentList;
- argumentList << QVariant::fromValue(targetfile);
- QDBusMessage reply = callWithArgumentList(QDBus::Block, QStringLiteral("PullBusinessCard"), argumentList);
- if (reply.type() == QDBusMessage::ReplyMessage && reply.arguments().count() == 2) {
- properties = qdbus_cast<QVariantMap>(reply.arguments().at(1));
- }
- return reply;
- }
-
- inline QDBusPendingReply<QDBusObjectPath, QVariantMap> SendFile(const QString &sourcefile)
- {
- QList<QVariant> argumentList;
- argumentList << QVariant::fromValue(sourcefile);
- return asyncCallWithArgumentList(QStringLiteral("SendFile"), argumentList);
- }
- inline QDBusReply<QDBusObjectPath> SendFile(const QString &sourcefile, QVariantMap &properties)
- {
- QList<QVariant> argumentList;
- argumentList << QVariant::fromValue(sourcefile);
- QDBusMessage reply = callWithArgumentList(QDBus::Block, QStringLiteral("SendFile"), argumentList);
- if (reply.type() == QDBusMessage::ReplyMessage && reply.arguments().count() == 2) {
- properties = qdbus_cast<QVariantMap>(reply.arguments().at(1));
- }
- return reply;
- }
-
-Q_SIGNALS: // SIGNALS
-};
-
-namespace org {
- namespace bluez {
- namespace obex {
- typedef ::OrgBluezObexObjectPush1Interface ObjectPush1;
- }
- }
-}
-#endif
diff --git a/src/bluetooth/bluez/obex_transfer.cpp b/src/bluetooth/bluez/obex_transfer.cpp
deleted file mode 100644
index be27362f..00000000
--- a/src/bluetooth/bluez/obex_transfer.cpp
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * This file was generated by qdbusxml2cpp version 0.8
- * Command line was: qdbusxml2cpp -p obex_transfer_p.h:obex_transfer.cpp org.openobex.transfer.xml org.openobex.Transfer
- *
- * qdbusxml2cpp is Copyright (C) 2017 The Qt Company Ltd.
- *
- * This is an auto-generated file.
- * This file may have been hand-edited. Look for HAND-EDIT comments
- * before re-generating it.
- */
-
-#include "obex_transfer_p.h"
-
-/*
- * Implementation of interface class OrgOpenobexTransferInterface
- */
-
-OrgOpenobexTransferInterface::OrgOpenobexTransferInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent)
- : QDBusAbstractInterface(service, path, staticInterfaceName(), connection, parent)
-{
-}
-
-OrgOpenobexTransferInterface::~OrgOpenobexTransferInterface()
-{
-}
-
diff --git a/src/bluetooth/bluez/obex_transfer1_bluez5.cpp b/src/bluetooth/bluez/obex_transfer1_bluez5.cpp
deleted file mode 100644
index 8cddd05e..00000000
--- a/src/bluetooth/bluez/obex_transfer1_bluez5.cpp
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * This file was generated by qdbusxml2cpp version 0.8
- * Command line was: qdbusxml2cpp org.bluez.obex.Transfer1.xml -p obex_transfer1_bluez5
- *
- * qdbusxml2cpp is Copyright (C) 2015 The Qt Company Ltd.
- *
- * This is an auto-generated file.
- * This file may have been hand-edited. Look for HAND-EDIT comments
- * before re-generating it.
- */
-
-#include "obex_transfer1_bluez5_p.h"
-
-/*
- * Implementation of interface class OrgBluezObexTransfer1Interface
- */
-
-OrgBluezObexTransfer1Interface::OrgBluezObexTransfer1Interface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent)
- : QDBusAbstractInterface(service, path, staticInterfaceName(), connection, parent)
-{
-}
-
-OrgBluezObexTransfer1Interface::~OrgBluezObexTransfer1Interface()
-{
-}
-
diff --git a/src/bluetooth/bluez/obex_transfer1_bluez5_p.h b/src/bluetooth/bluez/obex_transfer1_bluez5_p.h
deleted file mode 100644
index ccde588e..00000000
--- a/src/bluetooth/bluez/obex_transfer1_bluez5_p.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * This file was generated by qdbusxml2cpp version 0.8
- * Command line was: qdbusxml2cpp -p obex_transfer1_bluez5_p.h:obex_transfer1_bluez5_p.h org.bluez.obex.Transfer1.xml
- *
- * qdbusxml2cpp is Copyright (C) 2017 The Qt Company Ltd.
- *
- * This is an auto-generated file.
- * Do not edit! All changes made to it will be lost.
- */
-
-#ifndef OBEX_TRANSFER1_BLUEZ5_P_H
-#define OBEX_TRANSFER1_BLUEZ5_P_H
-
-#include <QtCore/QObject>
-#include <QtCore/QByteArray>
-#include <QtCore/QList>
-#include <QtCore/QMap>
-#include <QtCore/QString>
-#include <QtCore/QStringList>
-#include <QtCore/QVariant>
-#include <QtDBus/QtDBus>
-
-/*
- * Proxy class for interface org.bluez.obex.Transfer1
- */
-class OrgBluezObexTransfer1Interface: public QDBusAbstractInterface
-{
- Q_OBJECT
-public:
- static inline const char *staticInterfaceName()
- { return "org.bluez.obex.Transfer1"; }
-
-public:
- OrgBluezObexTransfer1Interface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = nullptr);
-
- ~OrgBluezObexTransfer1Interface();
-
- Q_PROPERTY(QString Filename READ filename)
- inline QString filename() const
- { return qvariant_cast< QString >(property("Filename")); }
-
- Q_PROPERTY(QString Name READ name)
- inline QString name() const
- { return qvariant_cast< QString >(property("Name")); }
-
- Q_PROPERTY(QDBusObjectPath Session READ session)
- inline QDBusObjectPath session() const
- { return qvariant_cast< QDBusObjectPath >(property("Session")); }
-
- Q_PROPERTY(qulonglong Size READ size)
- inline qulonglong size() const
- { return qvariant_cast< qulonglong >(property("Size")); }
-
- Q_PROPERTY(QString Status READ status)
- inline QString status() const
- { return qvariant_cast< QString >(property("Status")); }
-
- Q_PROPERTY(qulonglong Transferred READ transferred)
- inline qulonglong transferred() const
- { return qvariant_cast< qulonglong >(property("Transferred")); }
-
-public Q_SLOTS: // METHODS
- inline QDBusPendingReply<> Cancel()
- {
- QList<QVariant> argumentList;
- return asyncCallWithArgumentList(QStringLiteral("Cancel"), argumentList);
- }
-
- inline QDBusPendingReply<> Resume()
- {
- QList<QVariant> argumentList;
- return asyncCallWithArgumentList(QStringLiteral("Resume"), argumentList);
- }
-
- inline QDBusPendingReply<> Suspend()
- {
- QList<QVariant> argumentList;
- return asyncCallWithArgumentList(QStringLiteral("Suspend"), argumentList);
- }
-
-Q_SIGNALS: // SIGNALS
-};
-
-namespace org {
- namespace bluez {
- namespace obex {
- typedef ::OrgBluezObexTransfer1Interface Transfer1;
- }
- }
-}
-#endif
diff --git a/src/bluetooth/bluez/obex_transfer_p.h b/src/bluetooth/bluez/obex_transfer_p.h
deleted file mode 100644
index b8fa0a5d..00000000
--- a/src/bluetooth/bluez/obex_transfer_p.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * This file was generated by qdbusxml2cpp version 0.8
- * Command line was: qdbusxml2cpp -p obex_transfer_p.h:obex_transfer.cpp org.openobex.transfer.xml org.openobex.Transfer
- *
- * qdbusxml2cpp is Copyright (C) 2017 The Qt Company Ltd.
- *
- * This is an auto-generated file.
- * Do not edit! All changes made to it will be lost.
- */
-
-#ifndef OBEX_TRANSFER_P_H
-#define OBEX_TRANSFER_P_H
-
-#include <QtCore/QObject>
-#include <QtCore/QByteArray>
-#include <QtCore/QList>
-#include <QtCore/QMap>
-#include <QtCore/QString>
-#include <QtCore/QStringList>
-#include <QtCore/QVariant>
-#include <QtDBus/QtDBus>
-
-/*
- * Proxy class for interface org.openobex.Transfer
- */
-class OrgOpenobexTransferInterface: public QDBusAbstractInterface
-{
- Q_OBJECT
-public:
- static inline const char *staticInterfaceName()
- { return "org.openobex.Transfer"; }
-
-public:
- OrgOpenobexTransferInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = nullptr);
-
- ~OrgOpenobexTransferInterface();
-
-public Q_SLOTS: // METHODS
- inline QDBusPendingReply<> Cancel()
- {
- QList<QVariant> argumentList;
- return asyncCallWithArgumentList(QStringLiteral("Cancel"), argumentList);
- }
-
- inline QDBusPendingReply<QVariantMap> GetProperties()
- {
- QList<QVariant> argumentList;
- return asyncCallWithArgumentList(QStringLiteral("GetProperties"), argumentList);
- }
-
-Q_SIGNALS: // SIGNALS
-};
-
-namespace org {
- namespace openobex {
- typedef ::OrgOpenobexTransferInterface Transfer;
- }
-}
-#endif
diff --git a/src/bluetooth/bluez/objectmanager.cpp b/src/bluetooth/bluez/objectmanager.cpp
index 4484ea27..dd232c6d 100644
--- a/src/bluetooth/bluez/objectmanager.cpp
+++ b/src/bluetooth/bluez/objectmanager.cpp
@@ -1,8 +1,8 @@
/*
* This file was generated by qdbusxml2cpp version 0.8
- * Command line was: qdbusxml2cpp -p objectmanager_p.h:objectmanager.cpp org.freedesktop.dbus.objectmanager.xml
+ * Command line was: qdbusxml2cpp -i bluez5_helper_p.h -I QtCore/private/qglobal_p.h -p objectmanager_p.h:objectmanager.cpp org.freedesktop.dbus.objectmanager.xml
*
- * qdbusxml2cpp is Copyright (C) 2017 The Qt Company Ltd.
+ * qdbusxml2cpp is Copyright (C) 2022 The Qt Company Ltd.
*
* This is an auto-generated file.
* This file may have been hand-edited. Look for HAND-EDIT comments
@@ -24,3 +24,5 @@ OrgFreedesktopDBusObjectManagerInterface::~OrgFreedesktopDBusObjectManagerInterf
{
}
+
+#include "moc_objectmanager_p.cpp"
diff --git a/src/bluetooth/bluez/objectmanager_p.h b/src/bluetooth/bluez/objectmanager_p.h
index 7aa2f35b..d76eeb54 100644
--- a/src/bluetooth/bluez/objectmanager_p.h
+++ b/src/bluetooth/bluez/objectmanager_p.h
@@ -1,8 +1,8 @@
/*
* This file was generated by qdbusxml2cpp version 0.8
- * Command line was: qdbusxml2cpp -p objectmanager_p.h:objectmanager.cpp org.freedesktop.dbus.objectmanager.xml
+ * Command line was: qdbusxml2cpp -i bluez5_helper_p.h -I QtCore/private/qglobal_p.h -p objectmanager_p.h:objectmanager.cpp org.freedesktop.dbus.objectmanager.xml
*
- * qdbusxml2cpp is Copyright (C) 2017 The Qt Company Ltd.
+ * qdbusxml2cpp is Copyright (C) 2022 The Qt Company Ltd.
*
* This is an auto-generated file.
* Do not edit! All changes made to it will be lost.
@@ -11,6 +11,17 @@
#ifndef OBJECTMANAGER_P_H
#define OBJECTMANAGER_P_H
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
#include <QtCore/QObject>
#include <QtCore/QByteArray>
#include <QtCore/QList>
@@ -19,8 +30,8 @@
#include <QtCore/QStringList>
#include <QtCore/QVariant>
#include <QtDBus/QtDBus>
-
#include "bluez5_helper_p.h"
+#include <QtCore/private/qglobal_p.h>
/*
* Proxy class for interface org.freedesktop.DBus.ObjectManager
@@ -52,7 +63,7 @@ Q_SIGNALS: // SIGNALS
namespace org {
namespace freedesktop {
namespace DBus {
- typedef ::OrgFreedesktopDBusObjectManagerInterface ObjectManager;
+ using ObjectManager = ::OrgFreedesktopDBusObjectManagerInterface;
}
}
}
diff --git a/src/bluetooth/bluez/objectmanageradaptor.cpp b/src/bluetooth/bluez/objectmanageradaptor.cpp
new file mode 100644
index 00000000..575a7f22
--- /dev/null
+++ b/src/bluetooth/bluez/objectmanageradaptor.cpp
@@ -0,0 +1,42 @@
+/*
+ * This file was generated by qdbusxml2cpp version 0.8
+ * Command line was: qdbusxml2cpp -a objectmanageradaptor_p.h:objectmanageradaptor.cpp -c OrgFreedesktopDBusObjectManagerAdaptor -i bluez5_helper_p.h org.freedesktop.dbus.objectmanager.xml
+ *
+ * qdbusxml2cpp is Copyright (C) 2022 The Qt Company Ltd.
+ *
+ * This is an auto-generated file.
+ * Do not edit! All changes made to it will be lost.
+ */
+
+#include "objectmanageradaptor_p.h"
+#include <QtCore/QMetaObject>
+#include <QtCore/QByteArray>
+#include <QtCore/QList>
+#include <QtCore/QMap>
+#include <QtCore/QString>
+#include <QtCore/QStringList>
+#include <QtCore/QVariant>
+
+/*
+ * Implementation of adaptor class OrgFreedesktopDBusObjectManagerAdaptor
+ */
+
+OrgFreedesktopDBusObjectManagerAdaptor::OrgFreedesktopDBusObjectManagerAdaptor(QObject *parent)
+ : QDBusAbstractAdaptor(parent)
+{
+ // constructor
+ setAutoRelaySignals(true);
+}
+
+OrgFreedesktopDBusObjectManagerAdaptor::~OrgFreedesktopDBusObjectManagerAdaptor()
+{
+ // destructor
+}
+
+ManagedObjectList OrgFreedesktopDBusObjectManagerAdaptor::GetManagedObjects()
+{
+ // handle method call org.freedesktop.DBus.ObjectManager.GetManagedObjects
+ ManagedObjectList object_paths_interfaces_and_properties;
+ QMetaObject::invokeMethod(parent(), "GetManagedObjects", Q_RETURN_ARG(ManagedObjectList, object_paths_interfaces_and_properties));
+ return object_paths_interfaces_and_properties;
+}
diff --git a/src/bluetooth/bluez/objectmanageradaptor_p.h b/src/bluetooth/bluez/objectmanageradaptor_p.h
new file mode 100644
index 00000000..17579a25
--- /dev/null
+++ b/src/bluetooth/bluez/objectmanageradaptor_p.h
@@ -0,0 +1,67 @@
+/*
+ * This file was generated by qdbusxml2cpp version 0.8
+ * Command line was: qdbusxml2cpp -a objectmanageradaptor_p.h:objectmanageradaptor.cpp -c OrgFreedesktopDBusObjectManagerAdaptor -i bluez5_helper_p.h org.freedesktop.dbus.objectmanager.xml
+ *
+ * qdbusxml2cpp is Copyright (C) 2022 The Qt Company Ltd.
+ *
+ * This is an auto-generated file.
+ * This file may have been hand-edited. Look for HAND-EDIT comments
+ * before re-generating it.
+ */
+
+#ifndef OBJECTMANAGERADAPTOR_P_H
+#define OBJECTMANAGERADAPTOR_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/QObject>
+#include <QtDBus/QtDBus>
+#include "bluez5_helper_p.h"
+#include <QtCore/qcontainerfwd.h>
+
+/*
+ * Adaptor class for interface org.freedesktop.DBus.ObjectManager
+ */
+class OrgFreedesktopDBusObjectManagerAdaptor: public QDBusAbstractAdaptor
+{
+ Q_OBJECT
+ Q_CLASSINFO("D-Bus Interface", "org.freedesktop.DBus.ObjectManager")
+ Q_CLASSINFO("D-Bus Introspection", ""
+" <interface name=\"org.freedesktop.DBus.ObjectManager\">\n"
+" <method name=\"GetManagedObjects\">\n"
+" <arg direction=\"out\" type=\"a{oa{sa{sv}}}\" name=\"object_paths_interfaces_and_properties\"/>\n"
+" <annotation value=\"ManagedObjectList\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
+" </method>\n"
+" <signal name=\"InterfacesAdded\">\n"
+" <arg type=\"o\" name=\"object_path\"/>\n"
+" <arg type=\"a{sa{sv}}\" name=\"interfaces_and_properties\"/>\n"
+" <annotation value=\"InterfaceList\" name=\"org.qtproject.QtDBus.QtTypeName.Out1\"/>\n"
+" </signal>\n"
+" <signal name=\"InterfacesRemoved\">\n"
+" <arg type=\"o\" name=\"object_path\"/>\n"
+" <arg type=\"as\" name=\"interfaces\"/>\n"
+" </signal>\n"
+" </interface>\n"
+ "")
+public:
+ OrgFreedesktopDBusObjectManagerAdaptor(QObject *parent);
+ virtual ~OrgFreedesktopDBusObjectManagerAdaptor();
+
+public: // PROPERTIES
+public Q_SLOTS: // METHODS
+ ManagedObjectList GetManagedObjects();
+Q_SIGNALS: // SIGNALS
+ void InterfacesAdded(const QDBusObjectPath &object_path, InterfaceList interfaces_and_properties);
+ void InterfacesRemoved(const QDBusObjectPath &object_path, const QStringList &interfaces);
+};
+
+#endif
diff --git a/src/bluetooth/bluez/org.bluez.Agent.xml b/src/bluetooth/bluez/org.bluez.Agent.xml
deleted file mode 100644
index 9a77eb1b..00000000
--- a/src/bluetooth/bluez/org.bluez.Agent.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
-<node name="/">
- <interface name="org.bluez.Agent">
- <method name="Release" />
- <method name="RequestPinCode">
- <arg type="o" direction="in"/>
- <arg type="s" direction="out"/>
- </method>
- <method name="RequestPasskey">
- <arg type="o" direction="in"/>
- <arg type="u" direction="out"/>
- </method>
- <method name="DisplayPasskey">
- <arg type="o" direction="in"/>
- <arg type="u" direction="in"/>
- <arg type="y" direction="in"/>
- </method>
- <method name="RequestConfirmation">
- <arg type="o" direction="in"/>
- <arg type="u" direction="in"/>
- </method>
- <method name="Authorize">
- <arg type="o" direction="in"/>
- <arg type="s" direction="in"/>
- </method>
- <method name="ConfirmModeChange">
- <arg type="s" direction="in"/>
- </method>
- <method name="Cancel" />
- </interface>
- <node name="org"/>
-</node>
diff --git a/src/bluetooth/bluez/org.bluez.Client1.xml b/src/bluetooth/bluez/org.bluez.Client1.xml
deleted file mode 100644
index 8a5a25c1..00000000
--- a/src/bluetooth/bluez/org.bluez.Client1.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
- "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
-<node>
- <interface name="org.bluez.obex.Client1">
- <method name="CreateSession">
- <arg name="destination" type="s" direction="in"/>
- <arg name="args" type="a{sv}" direction="in"/>
- <annotation name="org.qtproject.QtDBus.QtTypeName.In1" value="QVariantMap"/>
- <arg name="session" type="o" direction="out"/>
- </method>
- <method name="RemoveSession">
- <arg name="session" type="o" direction="in"/>
- </method>
- </interface>
-</node>
diff --git a/src/bluetooth/bluez/org.bluez.Device.xml b/src/bluetooth/bluez/org.bluez.Device.xml
deleted file mode 100644
index 42351c97..00000000
--- a/src/bluetooth/bluez/org.bluez.Device.xml
+++ /dev/null
@@ -1,41 +0,0 @@
-<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
-<node name="/org/bluez/3003/hci0/dev_XX_XX_XX_XX_XX_XX">
- <interface name="org.bluez.Device">
- <method name="GetProperties">
- <arg type="a{sv}" direction="out"/>
- <annotation name="com.trolltech.QtDBus.QtTypeName.Out0" value="QVariantMap"/>
- </method>
- <method name="SetProperty">
- <arg type="s" direction="in"/>
- <arg type="v" direction="in"/>
- </method>
- <method name="DiscoverServices">
- <arg type="s" direction="in"/>
- <arg type="a{us}" direction="out"/>
- <annotation name="com.trolltech.QtDBus.QtTypeName.Out0" value="ServiceMap"/>
- </method>
- <method name="CancelDiscovery"/>
- <method name="Disconnect"/>
- <method name="ListNodes">
- <arg type="ao" direction="out"/>
- </method>
- <method name="CreateNode">
- <arg type="s" direction="in"/>
- <arg type="o" direction="out"/>
- </method>
- <method name="RemoveNode">
- <arg type="o" direction="in"/>
- </method>
- <signal name="PropertyChanged">
- <arg type="s"/>
- <arg type="v"/>
- </signal>
- <signal name="DisconnectRequested"/>
- <signal name="NodeCreated">
- <arg type="o"/>
- </signal>
- <signal name="NodeRemoved">
- <arg type="o"/>
- </signal>
- </interface>
-</node>
diff --git a/src/bluetooth/bluez/org.bluez.Device1.xml b/src/bluetooth/bluez/org.bluez.Device1.xml
index 554d0b53..cd4cba77 100644
--- a/src/bluetooth/bluez/org.bluez.Device1.xml
+++ b/src/bluetooth/bluez/org.bluez.Device1.xml
@@ -29,10 +29,10 @@
<property name="Adapter" type="o" access="read"></property>
<!-- ManufacturerData & ServiceData introduced by Bluez 5.31 -->
<property name="ManufacturerData" type="a{qv}" access="read">
- <annotation name="org.qtproject.QtDBus.QtTypeName" value="ManufacturerDataList"/>
+ <annotation name="org.qtproject.QtDBus.QtTypeName" value="ManufacturerDataList"/>
</property>
<property name="ServiceData" type="a{sv}" access="read">
- <annotation name="org.qtproject.QtDBus.QtTypeName" value="QVariantMap"/>
+ <annotation name="org.qtproject.QtDBus.QtTypeName" value="ServiceDataList"/>
</property>
<!-- TxPower and ServicesResolved introduced by Bluez 5.42 -->
<property name="TxPower" type="n" access="read"></property>
diff --git a/src/bluetooth/bluez/org.bluez.GattManager1.xml b/src/bluetooth/bluez/org.bluez.GattManager1.xml
new file mode 100644
index 00000000..ca7819b0
--- /dev/null
+++ b/src/bluetooth/bluez/org.bluez.GattManager1.xml
@@ -0,0 +1,14 @@
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
+<node>
+ <interface name="org.bluez.GattManager1">
+ <method name="RegisterApplication">
+ <arg name="application" type="o" direction="in"/>
+ <arg name="options" type="a{sv}" direction="in"/>
+ <annotation name="org.qtproject.QtDBus.QtTypeName.In1" value="QVariantMap"/>
+ </method>
+ <method name="UnregisterApplication">
+ <arg name="application" type="o" direction="in"/>
+ </method>
+ </interface>
+</node>
diff --git a/src/bluetooth/bluez/org.bluez.LEAdvertisement1.xml b/src/bluetooth/bluez/org.bluez.LEAdvertisement1.xml
new file mode 100644
index 00000000..845dbccf
--- /dev/null
+++ b/src/bluetooth/bluez/org.bluez.LEAdvertisement1.xml
@@ -0,0 +1,29 @@
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
+<node>
+ <interface name="org.bluez.LEAdvertisement1">
+ <method name="Release">
+ <annotation name="org.freedesktop.DBus.Method.NoReply" value="true"/>
+ </method>
+ <property name="Type" type="s" access="readwrite"/>
+ <property name="ServiceUUIDs" type="as" access="readwrite"/>
+ <property name="ManufacturerData" type="a{qv}" access="readwrite">
+ <annotation name="org.qtproject.QtDBus.QtTypeName" value="ManufacturerDataList"/>
+ </property>
+ <!-- SolicitUUIDs -->
+ <!-- ServiceData -->
+ <!-- Data experimental -->
+ <property name="Discoverable" type="b" access="readwrite"/>
+ <!-- DiscoverableTimeout experimental -->
+ <property name="Includes" type="as" access="readwrite"/>
+ <property name="LocalName" type="s" access="readwrite"/>
+ <!-- Appearance -->
+ <!-- Duration -->
+ <!-- Timeout -->
+ <!-- SecondaryChannel experimental -->
+ <!-- min max intervals are experimental -->
+ <property name="MinInterval" type="u" access="readwrite"/>
+ <property name="MaxInterval" type="u" access="readwrite"/>
+ <!-- TxPower experimental -->
+ </interface>
+</node>
diff --git a/src/bluetooth/bluez/org.bluez.LEAdvertisingManager1.xml b/src/bluetooth/bluez/org.bluez.LEAdvertisingManager1.xml
new file mode 100644
index 00000000..f8e1e49a
--- /dev/null
+++ b/src/bluetooth/bluez/org.bluez.LEAdvertisingManager1.xml
@@ -0,0 +1,20 @@
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
+<node>
+ <interface name="org.bluez.LEAdvertisingManager1">
+ <method name="RegisterAdvertisement">
+ <arg name="advertisement" type="o" direction="in"/>
+ <arg name="options" type="a{sv}" direction="in"/>
+ <annotation name="org.qtproject.QtDBus.QtTypeName.In1" value="QVariantMap"/>
+ </method>
+ <method name="UnregisterAdvertisement">
+ <arg name="advertisement" type="o" direction="in"/>
+ </method>
+ <property name="ActiveInstances" type="y" access="read"/>
+ <property name="SupportedInstances" type="y" access="read"/>
+ <property name="SupportedIncludes" type="as" access="read"/>
+ <!-- SupportedSecondaryChannels experimental -->
+ <!-- SupportedFeatures experimental -->
+ <!-- SupportedCapabilities experimental -->
+ </interface>
+</node>
diff --git a/src/bluetooth/bluez/org.bluez.Manager.xml b/src/bluetooth/bluez/org.bluez.Manager.xml
deleted file mode 100644
index 60b9baba..00000000
--- a/src/bluetooth/bluez/org.bluez.Manager.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
-<node name="/">
- <interface name="org.bluez.Manager">
- <method name="DefaultAdapter">
- <arg type="o" direction="out"/>
- </method>
- <method name="FindAdapter">
- <arg type="s" direction="in"/>
- <arg type="o" direction="out"/>
- </method>
- <method name="ListAdapters">
- <arg type="ao" direction="out"/>
- </method>
- <signal name="AdapterAdded">
- <arg type="o"/>
- </signal>
- <signal name="AdapterRemoved">
- <arg type="o"/>
- </signal>
- <signal name="DefaultAdapterChanged">
- <arg type="o"/>
- </signal>
- </interface>
- <node name="org"/>
-</node>
diff --git a/src/bluetooth/bluez/org.bluez.Service.xml b/src/bluetooth/bluez/org.bluez.Service.xml
deleted file mode 100644
index e18516a3..00000000
--- a/src/bluetooth/bluez/org.bluez.Service.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
-<node name="/org/bluez/3003/any">
- <interface name="org.bluez.Service">
- <method name="AddRecord">
- <arg type="s" direction="in"/>
- <arg type="u" direction="out"/>
- </method>
- <method name="UpdateRecord">
- <arg type="u" direction="in"/>
- <arg type="s" direction="in"/>
- </method>
- <method name="RemoveRecord">
- <arg type="u" direction="in"/>
- </method>
- <method name="RequestAuthorization">
- <arg type="s" direction="in"/>
- <arg type="u" direction="in"/>
- </method>
- <method name="CancelAuthorization"/>
- </interface>
-</node>
diff --git a/src/bluetooth/bluez/org.bluez.all.xml b/src/bluetooth/bluez/org.bluez.all.xml
deleted file mode 100644
index b48a01f3..00000000
--- a/src/bluetooth/bluez/org.bluez.all.xml
+++ /dev/null
@@ -1,145 +0,0 @@
-<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
-<node name="/org/bluez/3003/hci0">
- <interface name="org.bluez.Adapter">
- <method name="GetProperties">
- <arg type="a{sv}" direction="out"/>
- <annotation name="com.trolltech.QtDBus.QtTypeName.Out0" value="QVariantMap"/>
- </method>
- <method name="SetProperty">
- <arg type="s" direction="in"/>
- <arg type="v" direction="in"/>
- </method>
- <method name="RequestMode">
- <arg type="s" direction="in"/>
- </method>
- <method name="ReleaseMode"/>
- <method name="RequestSession"/>
- <method name="ReleaseSession"/>
- <method name="StartDiscovery"/>
- <method name="StopDiscovery"/>
- <method name="ListDevices">
- <arg type="ao" direction="out"/>
- </method>
- <method name="CreateDevice">
- <arg type="s" direction="in"/>
- <arg type="o" direction="out"/>
- </method>
- <method name="CreatePairedDevice">
- <arg type="s" direction="in"/>
- <arg type="o" direction="in"/>
- <arg type="s" direction="in"/>
- <arg type="o" direction="out"/>
- </method>
- <method name="CancelDeviceCreation">
- <arg type="s" direction="in"/>
- </method>
- <method name="RemoveDevice">
- <arg type="o" direction="in"/>
- </method>
- <method name="FindDevice">
- <arg type="s" direction="in"/>
- <arg type="o" direction="out"/>
- </method>
- <method name="RegisterAgent">
- <arg type="o" direction="in"/>
- <arg type="s" direction="in"/>
- </method>
- <method name="UnregisterAgent">
- <arg type="o" direction="in"/>
- </method>
- <signal name="DeviceCreated">
- <arg type="o"/>
- </signal>
- <signal name="DeviceRemoved">
- <arg type="o"/>
- </signal>
- <signal name="DeviceFound">
- <arg type="s"/>
- <arg type="a{sv}"/>
- <annotation name="com.trolltech.QtDBus.QtTypeName.In1" value="QVariantMap"/>
- </signal>
- <signal name="PropertyChanged">
- <arg type="s"/>
- <arg type="v"/>
- </signal>
- <signal name="DeviceDisappeared">
- <arg type="s"/>
- </signal>
- </interface>
- <interface name="org.bluez.Service">
- <method name="AddRecord">
- <arg type="s" direction="in"/>
- <arg type="u" direction="out"/>
- </method>
- <method name="UpdateRecord">
- <arg type="u" direction="in"/>
- <arg type="s" direction="in"/>
- </method>
- <method name="RemoveRecord">
- <arg type="u" direction="in"/>
- </method>
- <method name="RequestAuthorization">
- <arg type="s" direction="in"/>
- <arg type="u" direction="in"/>
- </method>
- <method name="CancelAuthorization"/>
- </interface>
- <interface name="org.bluez.SerialProxyManager">
- <method name="CreateProxy">
- <arg type="s" direction="in"/>
- <arg type="s" direction="in"/>
- <arg type="s" direction="out"/>
- </method>
- <method name="ListProxies">
- <arg type="as" direction="out"/>
- </method>
- <method name="RemoveProxy">
- <arg type="s" direction="in"/>
- </method>
- <signal name="ProxyCreated">
- <arg type="s"/>
- </signal>
- <signal name="ProxyRemoved">
- <arg type="s"/>
- </signal>
- </interface>
- <interface name="org.bluez.NetworkPeer">
- <method name="SetProperty">
- <arg type="s" direction="in"/>
- <arg type="v" direction="in"/>
- </method>
- <method name="GetProperties">
- <arg type="a{sv}" direction="out"/>
- </method>
- <signal name="PropertyChanged">
- <arg type="s"/>
- <arg type="v"/>
- </signal>
- </interface>
- <interface name="org.bluez.NetworkHub">
- <method name="SetProperty">
- <arg type="s" direction="in"/>
- <arg type="v" direction="in"/>
- </method>
- <method name="GetProperties">
- <arg type="a{sv}" direction="out"/>
- </method>
- <signal name="PropertyChanged">
- <arg type="s"/>
- <arg type="v"/>
- </signal>
- </interface>
- <interface name="org.bluez.NetworkRouter">
- <method name="SetProperty">
- <arg type="s" direction="in"/>
- <arg type="v" direction="in"/>
- </method>
- <method name="GetProperties">
- <arg type="a{sv}" direction="out"/>
- </method>
- <signal name="PropertyChanged">
- <arg type="s"/>
- <arg type="v"/>
- </signal>
- </interface>
-</node>
diff --git a/src/bluetooth/bluez/org.bluez.obex.ObjectPush1.xml b/src/bluetooth/bluez/org.bluez.obex.ObjectPush1.xml
deleted file mode 100644
index 651f21a5..00000000
--- a/src/bluetooth/bluez/org.bluez.obex.ObjectPush1.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
- "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
-<node>
- <interface name="org.bluez.obex.ObjectPush1">
- <method name="SendFile">
- <arg name="sourcefile" type="s" direction="in"/>
- <arg name="transfer" type="o" direction="out"/>
- <arg name="properties" type="a{sv}" direction="out"/>
- <annotation name="org.qtproject.QtDBus.QtTypeName.Out1" value="QVariantMap"/>
- </method>
- <method name="PullBusinessCard">
- <arg name="targetfile" type="s" direction="in"/>
- <arg name="transfer" type="o" direction="out"/>
- <arg name="properties" type="a{sv}" direction="out"/>
- <annotation name="org.qtproject.QtDBus.QtTypeName.Out1" value="QVariantMap"/>
- </method>
- <method name="ExchangeBusinessCards">
- <arg name="clientfile" type="s" direction="in"/>
- <arg name="targetfile" type="s" direction="in"/>
- <arg name="transfer" type="o" direction="out"/>
- <arg name="properties" type="a{sv}" direction="out"/>
- <annotation name="org.qtproject.QtDBus.QtTypeName.Out1" value="QVariantMap"/>
- </method>
- </interface>
-</node>
diff --git a/src/bluetooth/bluez/org.bluez.obex.Transfer1.xml b/src/bluetooth/bluez/org.bluez.obex.Transfer1.xml
deleted file mode 100644
index 4ee76f7d..00000000
--- a/src/bluetooth/bluez/org.bluez.obex.Transfer1.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
- "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
-<node>
- <interface name="org.bluez.obex.Transfer1">
- <method name="Suspend"/>
- <method name="Resume"/>
- <method name="Cancel"/>
- <property name="Status" type="s" access="read"/>
- <property name="Name" type="s" access="read"/>
- <property name="Size" type="t" access="read"/>
- <property name="Filename" type="s" access="read"/>
- <property name="Transferred" type="t" access="read"/>
- <property name="Session" type="o" access="read"/>
- </interface>
-</node>
-
diff --git a/src/bluetooth/bluez/org.openobex.agent.xml b/src/bluetooth/bluez/org.openobex.agent.xml
deleted file mode 100644
index d21f3149..00000000
--- a/src/bluetooth/bluez/org.openobex.agent.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
-"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
-<node>
- <interface name="org.openobex.Agent">
- <method name="Release">
- </method>
- <method name="Request">
- <arg type="o" direction="in"/>
- <arg type="s" direction="out"/>
- </method>
- <method name="Progress">
- <arg type="o" direction="in"/>
- <arg type="t" direction="in"/>
- </method>
- <method name="Complete">
- <arg type="o" direction="in"/>
- </method>
- <method name="Error">
- <arg type="o" direction="in"/>
- <arg type="s" direction="in"/>
- </method>
- </interface>
-</node>
-
diff --git a/src/bluetooth/bluez/org.openobex.all.xml b/src/bluetooth/bluez/org.openobex.all.xml
deleted file mode 100644
index 4e5b65b2..00000000
--- a/src/bluetooth/bluez/org.openobex.all.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
-"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
-<node name="/">
- <interface name="org.freedesktop.DBus.Introspectable">
- <method name="Introspect">
- <arg type="s" direction="out"/>
- </method>
- </interface>
- <interface name="org.openobex.Manager">
- <method name="RegisterAgent">
- <arg type="o" direction="in"/>
- </method>
- <method name="UnregisterAgent">
- <arg type="o" direction="in"/>
- </method>
- <signal name="TransferStarted">
- <arg type="o"/>
- </signal>
- <signal name="TransferCompleted">
- <arg type="o"/>
- <arg type="b"/>
- </signal>
- <signal name="SessionCreated">
- <arg type="o"/>
- </signal>
- <signal name="SessionRemoved">
- <arg type="o"/>
- </signal>
- </interface>
-</node>
-
diff --git a/src/bluetooth/bluez/org.openobex.client.xml b/src/bluetooth/bluez/org.openobex.client.xml
deleted file mode 100644
index fad2f6ef..00000000
--- a/src/bluetooth/bluez/org.openobex.client.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
-"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
-<node name="/">
- <interface name="org.freedesktop.DBus.Introspectable">
- <method name="Introspect">
- <arg type="s" direction="out"/>
- </method>
- </interface>
- <interface name="org.openobex.Client">
- <method name="SendFiles">
- <arg type="a{sv}" direction="in"/>
- <annotation name="com.trolltech.QtDBus.QtTypeName.In0" value="QVariantMap"/>
- <arg type="as" direction="in"/>
- <arg type="o" direction="in"/>
- </method>
- <method name="PullBusinessCard">
- <arg type="a{sv}" direction="in"/>
- <annotation name="com.trolltech.QtDBus.QtTypeName.In0" value="QVariantMap"/>
- <arg type="s" direction="in"/>
- </method>
- <method name="ExchangeBusinessCards">
- <arg type="a{sv}" direction="in"/>
- <annotation name="com.trolltech.QtDBus.QtTypeName.In0" value="QVariantMap"/>
- <arg type="s" direction="in"/>
- <arg type="s" direction="in"/>
- </method>
- <method name="CreateSession">
- <arg type="a{sv}" direction="in"/>
- <annotation name="com.trolltech.QtDBus.QtTypeName.In0" value="QVariantMap"/>
- <arg type="o" direction="out"/>
- </method>
- <method name="GetCapabilities">
- <arg type="a{sv}" direction="in"/>
- <annotation name="com.trolltech.QtDBus.QtTypeName.In0" value="QVariantMap"/>
- <arg type="s" direction="out"/>
- </method>
- </interface>
- <node name="org"/>
-</node>
-
diff --git a/src/bluetooth/bluez/org.openobex.transfer.xml b/src/bluetooth/bluez/org.openobex.transfer.xml
deleted file mode 100644
index 21033665..00000000
--- a/src/bluetooth/bluez/org.openobex.transfer.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
-"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
-<node name="/">
- <interface name="org.freedesktop.DBus.Introspectable">
- <method name="Introspect">
- <arg type="s" direction="out"/>
- </method>
- </interface>
- <interface name="org.openobex.Transfer">
- <method name="GetProperties">
- <arg type="a{sv}" direction="out"/>
- <annotation name="com.trolltech.QtDBus.QtTypeName.Out0" value="QVariantMap"/>
- </method>
- <method name="Cancel">
- </method>
- </interface>
- <node name="org"/>
-</node>
-
diff --git a/src/bluetooth/bluez/profile1.cpp b/src/bluetooth/bluez/profile1.cpp
index e74be807..7e67cf29 100644
--- a/src/bluetooth/bluez/profile1.cpp
+++ b/src/bluetooth/bluez/profile1.cpp
@@ -1,8 +1,8 @@
/*
* This file was generated by qdbusxml2cpp version 0.8
- * Command line was: qdbusxml2cpp -p profile1_p.h:profile1.cpp org.bluez.Profile1.xml
+ * Command line was: qdbusxml2cpp -I QtCore/private/qglobal_p.h -p profile1_p.h:profile1.cpp org.bluez.Profile1.xml
*
- * qdbusxml2cpp is Copyright (C) 2018 The Qt Company Ltd.
+ * qdbusxml2cpp is Copyright (C) 2022 The Qt Company Ltd.
*
* This is an auto-generated file.
* This file may have been hand-edited. Look for HAND-EDIT comments
@@ -24,3 +24,5 @@ OrgBluezProfile1Interface::~OrgBluezProfile1Interface()
{
}
+
+#include "moc_profile1_p.cpp"
diff --git a/src/bluetooth/bluez/profile1_p.h b/src/bluetooth/bluez/profile1_p.h
index 63ea40b8..bf263545 100644
--- a/src/bluetooth/bluez/profile1_p.h
+++ b/src/bluetooth/bluez/profile1_p.h
@@ -1,8 +1,8 @@
/*
* This file was generated by qdbusxml2cpp version 0.8
- * Command line was: qdbusxml2cpp -p profile1_p.h:profile1.cpp org.bluez.Profile1.xml
+ * Command line was: qdbusxml2cpp -I QtCore/private/qglobal_p.h -p profile1_p.h:profile1.cpp org.bluez.Profile1.xml
*
- * qdbusxml2cpp is Copyright (C) 2018 The Qt Company Ltd.
+ * qdbusxml2cpp is Copyright (C) 2022 The Qt Company Ltd.
*
* This is an auto-generated file.
* Do not edit! All changes made to it will be lost.
@@ -11,6 +11,17 @@
#ifndef PROFILE1_P_H
#define PROFILE1_P_H
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
#include <QtCore/QObject>
#include <QtCore/QByteArray>
#include <QtCore/QList>
@@ -19,6 +30,7 @@
#include <QtCore/QStringList>
#include <QtCore/QVariant>
#include <QtDBus/QtDBus>
+#include <QtCore/private/qglobal_p.h>
/*
* Proxy class for interface org.bluez.Profile1
@@ -61,7 +73,7 @@ Q_SIGNALS: // SIGNALS
namespace org {
namespace bluez {
- typedef ::OrgBluezProfile1Interface Profile1;
+ using Profile1 = ::OrgBluezProfile1Interface;
}
}
#endif
diff --git a/src/bluetooth/bluez/profile1context.cpp b/src/bluetooth/bluez/profile1context.cpp
index 5eeec56a..3bb7e1bd 100644
--- a/src/bluetooth/bluez/profile1context.cpp
+++ b/src/bluetooth/bluez/profile1context.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "profile1context_p.h"
@@ -70,3 +34,5 @@ void OrgBluezProfile1ContextInterface::Release()
}
QT_END_NAMESPACE
+
+#include "moc_profile1context_p.cpp"
diff --git a/src/bluetooth/bluez/profile1context_p.h b/src/bluetooth/bluez/profile1context_p.h
index bd7b7df3..99160bba 100644
--- a/src/bluetooth/bluez/profile1context_p.h
+++ b/src/bluetooth/bluez/profile1context_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef PROFILECONTEXT_P_H
#define PROFILECONTEXT_P_H
@@ -55,6 +19,7 @@
#include <QtDBus/qdbuscontext.h>
#include <QtDBus/qdbusextratypes.h>
#include <QtDBus/qdbusunixfiledescriptor.h>
+#include <QtCore/private/qglobal_p.h>
QT_BEGIN_NAMESPACE
diff --git a/src/bluetooth/bluez/profilemanager1.cpp b/src/bluetooth/bluez/profilemanager1.cpp
index fe685c63..4366a968 100644
--- a/src/bluetooth/bluez/profilemanager1.cpp
+++ b/src/bluetooth/bluez/profilemanager1.cpp
@@ -1,8 +1,8 @@
/*
* This file was generated by qdbusxml2cpp version 0.8
- * Command line was: qdbusxml2cpp -p profilemanager1_p.h:profilemanager1.cpp org.bluez.ProfileManager1.xml
+ * Command line was: qdbusxml2cpp -I QtCore/private/qglobal_p.h -p profilemanager1_p.h:profilemanager1.cpp org.bluez.ProfileManager1.xml
*
- * qdbusxml2cpp is Copyright (C) 2017 The Qt Company Ltd.
+ * qdbusxml2cpp is Copyright (C) 2022 The Qt Company Ltd.
*
* This is an auto-generated file.
* This file may have been hand-edited. Look for HAND-EDIT comments
@@ -24,3 +24,5 @@ OrgBluezProfileManager1Interface::~OrgBluezProfileManager1Interface()
{
}
+
+#include "moc_profilemanager1_p.cpp"
diff --git a/src/bluetooth/bluez/profilemanager1_p.h b/src/bluetooth/bluez/profilemanager1_p.h
index 5530783b..a02af3b6 100644
--- a/src/bluetooth/bluez/profilemanager1_p.h
+++ b/src/bluetooth/bluez/profilemanager1_p.h
@@ -1,8 +1,8 @@
/*
* This file was generated by qdbusxml2cpp version 0.8
- * Command line was: qdbusxml2cpp -p profilemanager1_p.h:profilemanager1.cpp org.bluez.ProfileManager1.xml
+ * Command line was: qdbusxml2cpp -I QtCore/private/qglobal_p.h -p profilemanager1_p.h:profilemanager1.cpp org.bluez.ProfileManager1.xml
*
- * qdbusxml2cpp is Copyright (C) 2017 The Qt Company Ltd.
+ * qdbusxml2cpp is Copyright (C) 2022 The Qt Company Ltd.
*
* This is an auto-generated file.
* Do not edit! All changes made to it will be lost.
@@ -11,6 +11,17 @@
#ifndef PROFILEMANAGER1_P_H
#define PROFILEMANAGER1_P_H
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
#include <QtCore/QObject>
#include <QtCore/QByteArray>
#include <QtCore/QList>
@@ -19,6 +30,7 @@
#include <QtCore/QStringList>
#include <QtCore/QVariant>
#include <QtDBus/QtDBus>
+#include <QtCore/private/qglobal_p.h>
/*
* Proxy class for interface org.bluez.ProfileManager1
@@ -55,7 +67,7 @@ Q_SIGNALS: // SIGNALS
namespace org {
namespace bluez {
- typedef ::OrgBluezProfileManager1Interface ProfileManager1;
+ using ProfileManager1 = ::OrgBluezProfileManager1Interface;
}
}
#endif
diff --git a/src/bluetooth/bluez/properties.cpp b/src/bluetooth/bluez/properties.cpp
index 1c10bfdc..0725d58f 100644
--- a/src/bluetooth/bluez/properties.cpp
+++ b/src/bluetooth/bluez/properties.cpp
@@ -1,8 +1,8 @@
/*
* This file was generated by qdbusxml2cpp version 0.8
- * Command line was: qdbusxml2cpp -p properties_p.h:properties.cpp org.freedesktop.dbus.properties.xml
+ * Command line was: qdbusxml2cpp -I QtCore/private/qglobal_p.h -p properties_p.h:properties.cpp org.freedesktop.dbus.properties.xml
*
- * qdbusxml2cpp is Copyright (C) 2017 The Qt Company Ltd.
+ * qdbusxml2cpp is Copyright (C) 2022 The Qt Company Ltd.
*
* This is an auto-generated file.
* This file may have been hand-edited. Look for HAND-EDIT comments
@@ -24,3 +24,5 @@ OrgFreedesktopDBusPropertiesInterface::~OrgFreedesktopDBusPropertiesInterface()
{
}
+
+#include "moc_properties_p.cpp"
diff --git a/src/bluetooth/bluez/properties_p.h b/src/bluetooth/bluez/properties_p.h
index 16a43e80..83286526 100644
--- a/src/bluetooth/bluez/properties_p.h
+++ b/src/bluetooth/bluez/properties_p.h
@@ -1,8 +1,8 @@
/*
* This file was generated by qdbusxml2cpp version 0.8
- * Command line was: qdbusxml2cpp -p properties_p.h:properties.cpp org.freedesktop.dbus.properties.xml
+ * Command line was: qdbusxml2cpp -I QtCore/private/qglobal_p.h -p properties_p.h:properties.cpp org.freedesktop.dbus.properties.xml
*
- * qdbusxml2cpp is Copyright (C) 2017 The Qt Company Ltd.
+ * qdbusxml2cpp is Copyright (C) 2022 The Qt Company Ltd.
*
* This is an auto-generated file.
* Do not edit! All changes made to it will be lost.
@@ -11,6 +11,17 @@
#ifndef PROPERTIES_P_H
#define PROPERTIES_P_H
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
#include <QtCore/QObject>
#include <QtCore/QByteArray>
#include <QtCore/QList>
@@ -19,6 +30,7 @@
#include <QtCore/QStringList>
#include <QtCore/QVariant>
#include <QtDBus/QtDBus>
+#include <QtCore/private/qglobal_p.h>
/*
* Proxy class for interface org.freedesktop.DBus.Properties
@@ -58,13 +70,14 @@ public Q_SLOTS: // METHODS
}
Q_SIGNALS: // SIGNALS
- void PropertiesChanged(const QString &interface, const QVariantMap &changed_properties, const QStringList &invalidated_properties);
+ void PropertiesChanged(const QString &interface, const QVariantMap &changed_properties, const QStringList &invalidated_properties,
+ const QDBusMessage &msg);
};
namespace org {
namespace freedesktop {
namespace DBus {
- typedef ::OrgFreedesktopDBusPropertiesInterface Properties;
+ using Properties = ::OrgFreedesktopDBusPropertiesInterface;
}
}
}
diff --git a/src/bluetooth/bluez/propertiesadaptor.cpp b/src/bluetooth/bluez/propertiesadaptor.cpp
new file mode 100644
index 00000000..177f839f
--- /dev/null
+++ b/src/bluetooth/bluez/propertiesadaptor.cpp
@@ -0,0 +1,56 @@
+/*
+ * This file was generated by qdbusxml2cpp version 0.8
+ * Command line was: qdbusxml2cpp -a propertiesadaptor_p.h:propertiesadaptor.cpp -c OrgFreedesktopDBusPropertiesAdaptor -i bluez5_helper_p.h org.freedesktop.dbus.properties.xml
+ *
+ * qdbusxml2cpp is Copyright (C) 2022 The Qt Company Ltd.
+ *
+ * This is an auto-generated file.
+ * Do not edit! All changes made to it will be lost.
+ */
+
+#include "propertiesadaptor_p.h"
+#include <QtCore/QMetaObject>
+#include <QtCore/QByteArray>
+#include <QtCore/QList>
+#include <QtCore/QMap>
+#include <QtCore/QString>
+#include <QtCore/QStringList>
+#include <QtCore/QVariant>
+
+/*
+ * Implementation of adaptor class OrgFreedesktopDBusPropertiesAdaptor
+ */
+
+OrgFreedesktopDBusPropertiesAdaptor::OrgFreedesktopDBusPropertiesAdaptor(QObject *parent)
+ : QDBusAbstractAdaptor(parent)
+{
+ // constructor
+ setAutoRelaySignals(true);
+}
+
+OrgFreedesktopDBusPropertiesAdaptor::~OrgFreedesktopDBusPropertiesAdaptor()
+{
+ // destructor
+}
+
+QDBusVariant OrgFreedesktopDBusPropertiesAdaptor::Get(const QString &interface, const QString &name)
+{
+ // handle method call org.freedesktop.DBus.Properties.Get
+ QDBusVariant value;
+ QMetaObject::invokeMethod(parent(), "Get", Q_RETURN_ARG(QDBusVariant, value), Q_ARG(QString, interface), Q_ARG(QString, name));
+ return value;
+}
+
+QVariantMap OrgFreedesktopDBusPropertiesAdaptor::GetAll(const QString &interface)
+{
+ // handle method call org.freedesktop.DBus.Properties.GetAll
+ QVariantMap properties;
+ QMetaObject::invokeMethod(parent(), "GetAll", Q_RETURN_ARG(QVariantMap, properties), Q_ARG(QString, interface));
+ return properties;
+}
+
+void OrgFreedesktopDBusPropertiesAdaptor::Set(const QString &interface, const QString &name, const QDBusVariant &value)
+{
+ // handle method call org.freedesktop.DBus.Properties.Set
+ QMetaObject::invokeMethod(parent(), "Set", Q_ARG(QString, interface), Q_ARG(QString, name), Q_ARG(QDBusVariant, value));
+}
diff --git a/src/bluetooth/bluez/propertiesadaptor_p.h b/src/bluetooth/bluez/propertiesadaptor_p.h
new file mode 100644
index 00000000..1be0fd0f
--- /dev/null
+++ b/src/bluetooth/bluez/propertiesadaptor_p.h
@@ -0,0 +1,76 @@
+/*
+ * This file was generated by qdbusxml2cpp version 0.8
+ * Command line was: qdbusxml2cpp -a propertiesadaptor_p.h:propertiesadaptor.cpp -c OrgFreedesktopDBusPropertiesAdaptor -i bluez5_helper_p.h org.freedesktop.dbus.properties.xml
+ *
+ * qdbusxml2cpp is Copyright (C) 2022 The Qt Company Ltd.
+ *
+ * This is an auto-generated file.
+ * This file may have been hand-edited. Look for HAND-EDIT comments
+ * before re-generating it.
+ */
+
+#ifndef PROPERTIESADAPTOR_P_H
+#define PROPERTIESADAPTOR_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/QObject>
+#include <QtDBus/QtDBus>
+#include "bluez5_helper_p.h"
+#include <QtCore/qcontainerfwd.h>
+
+/*
+ * Adaptor class for interface org.freedesktop.DBus.Properties
+ */
+class OrgFreedesktopDBusPropertiesAdaptor: public QDBusAbstractAdaptor
+{
+ Q_OBJECT
+ Q_CLASSINFO("D-Bus Interface", "org.freedesktop.DBus.Properties")
+ Q_CLASSINFO("D-Bus Introspection", ""
+" <interface name=\"org.freedesktop.DBus.Properties\">\n"
+" <method name=\"Get\">\n"
+" <arg direction=\"in\" type=\"s\" name=\"interface\"/>\n"
+" <arg direction=\"in\" type=\"s\" name=\"name\"/>\n"
+" <arg direction=\"out\" type=\"v\" name=\"value\"/>\n"
+" </method>\n"
+" <method name=\"Set\">\n"
+" <arg direction=\"in\" type=\"s\" name=\"interface\"/>\n"
+" <arg direction=\"in\" type=\"s\" name=\"name\"/>\n"
+" <arg direction=\"in\" type=\"v\" name=\"value\"/>\n"
+" </method>\n"
+" <method name=\"GetAll\">\n"
+" <arg direction=\"in\" type=\"s\" name=\"interface\"/>\n"
+" <arg direction=\"out\" type=\"a{sv}\" name=\"properties\"/>\n"
+" <annotation value=\"QVariantMap\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
+" </method>\n"
+" <signal name=\"PropertiesChanged\">\n"
+" <arg type=\"s\" name=\"interface\"/>\n"
+" <arg type=\"a{sv}\" name=\"changed_properties\"/>\n"
+" <annotation value=\"QVariantMap\" name=\"org.qtproject.QtDBus.QtTypeName.Out1\"/>\n"
+" <arg type=\"as\" name=\"invalidated_properties\"/>\n"
+" </signal>\n"
+" </interface>\n"
+ "")
+public:
+ OrgFreedesktopDBusPropertiesAdaptor(QObject *parent);
+ virtual ~OrgFreedesktopDBusPropertiesAdaptor();
+
+public: // PROPERTIES
+public Q_SLOTS: // METHODS
+ QDBusVariant Get(const QString &interface, const QString &name);
+ QVariantMap GetAll(const QString &interface);
+ void Set(const QString &interface, const QString &name, const QDBusVariant &value);
+Q_SIGNALS: // SIGNALS
+ void PropertiesChanged(const QString &interface, const QVariantMap &changed_properties, const QStringList &invalidated_properties);
+};
+
+#endif
diff --git a/src/bluetooth/bluez/remotedevicemanager.cpp b/src/bluetooth/bluez/remotedevicemanager.cpp
index 5d17d571..e8b13ce2 100644
--- a/src/bluetooth/bluez/remotedevicemanager.cpp
+++ b/src/bluetooth/bluez/remotedevicemanager.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtCore/QLoggingCategory>
@@ -58,8 +22,7 @@ RemoteDeviceManager::RemoteDeviceManager(
const QBluetoothAddress &address, QObject *parent)
: QObject(parent), localAddress(address)
{
- if (!isBluez5())
- return;
+ initializeBluez5();
bool ok = false;
adapterPath = findAdapterForAddress(address, &ok);
@@ -68,8 +31,7 @@ RemoteDeviceManager::RemoteDeviceManager(
}
}
-bool RemoteDeviceManager::scheduleJob(
- JobType job, const QVector<QBluetoothAddress> &remoteDevices)
+bool RemoteDeviceManager::scheduleJob(JobType job, const QList<QBluetoothAddress> &remoteDevices)
{
if (adapterPath.isEmpty())
return false;
@@ -106,7 +68,7 @@ void RemoteDeviceManager::prepareNextJob()
jobQueue.pop_front();
jobInProgress = false;
- qDebug(QT_BT_BLUEZ) << "RemoteDeviceManager job queue status:" << jobQueue.empty();
+ qCDebug(QT_BT_BLUEZ) << "RemoteDeviceManager job queue status:" << jobQueue.empty();
if (jobQueue.empty())
emit finished();
else
@@ -165,9 +127,11 @@ void RemoteDeviceManager::disconnectDevice(const QBluetoothAddress &remote)
}
if (!jobStarted) {
- qDebug(QT_BT_BLUEZ) << "RemoteDeviceManager JobDisconnectDevice failed";
+ qCDebug(QT_BT_BLUEZ) << "RemoteDeviceManager JobDisconnectDevice failed";
QTimer::singleShot(0, this, [this](){ prepareNextJob(); });
}
}
QT_END_NAMESPACE
+
+#include "moc_remotedevicemanager_p.cpp"
diff --git a/src/bluetooth/bluez/remotedevicemanager_p.h b/src/bluetooth/bluez/remotedevicemanager_p.h
index d177d74e..a41b1452 100644
--- a/src/bluetooth/bluez/remotedevicemanager_p.h
+++ b/src/bluetooth/bluez/remotedevicemanager_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef REMOTEDEVICEMANAGER_P_H
#define REMOTEDEVICEMANAGER_P_H
@@ -53,11 +17,12 @@
#include <deque>
+#include <QList>
#include <QMutex>
#include <QObject>
-#include <QVector>
#include <QtBluetooth/qbluetoothaddress.h>
+#include <QtCore/private/qglobal_p.h>
QT_BEGIN_NAMESPACE
@@ -76,7 +41,7 @@ public:
explicit RemoteDeviceManager(const QBluetoothAddress& localAddress, QObject *parent = nullptr);
bool isJobInProgress() const { return jobInProgress; }
- bool scheduleJob(JobType job, const QVector<QBluetoothAddress>& remoteDevices);
+ bool scheduleJob(JobType job, const QList<QBluetoothAddress> &remoteDevices);
signals:
void finished();
diff --git a/src/bluetooth/bluez/service.cpp b/src/bluetooth/bluez/service.cpp
deleted file mode 100644
index d2b15fc2..00000000
--- a/src/bluetooth/bluez/service.cpp
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * This file was generated by qdbusxml2cpp version 0.8
- * Command line was: qdbusxml2cpp -p service_p.h:service.cpp org.bluez.all.xml org.bluez.Service
- *
- * qdbusxml2cpp is Copyright (C) 2017 The Qt Company Ltd.
- *
- * This is an auto-generated file.
- * This file may have been hand-edited. Look for HAND-EDIT comments
- * before re-generating it.
- */
-
-#include "service_p.h"
-
-/*
- * Implementation of interface class OrgBluezServiceInterface
- */
-
-OrgBluezServiceInterface::OrgBluezServiceInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent)
- : QDBusAbstractInterface(service, path, staticInterfaceName(), connection, parent)
-{
-}
-
-OrgBluezServiceInterface::~OrgBluezServiceInterface()
-{
-}
-
diff --git a/src/bluetooth/bluez/service_p.h b/src/bluetooth/bluez/service_p.h
deleted file mode 100644
index 573265a8..00000000
--- a/src/bluetooth/bluez/service_p.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * This file was generated by qdbusxml2cpp version 0.8
- * Command line was: qdbusxml2cpp -p service_p.h:service.cpp org.bluez.all.xml org.bluez.Service
- *
- * qdbusxml2cpp is Copyright (C) 2017 The Qt Company Ltd.
- *
- * This is an auto-generated file.
- * Do not edit! All changes made to it will be lost.
- */
-
-#ifndef SERVICE_P_H
-#define SERVICE_P_H
-
-#include <QtCore/QObject>
-#include <QtCore/QByteArray>
-#include <QtCore/QList>
-#include <QtCore/QMap>
-#include <QtCore/QString>
-#include <QtCore/QStringList>
-#include <QtCore/QVariant>
-#include <QtDBus/QtDBus>
-
-/*
- * Proxy class for interface org.bluez.Service
- */
-class OrgBluezServiceInterface: public QDBusAbstractInterface
-{
- Q_OBJECT
-public:
- static inline const char *staticInterfaceName()
- { return "org.bluez.Service"; }
-
-public:
- OrgBluezServiceInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = nullptr);
-
- ~OrgBluezServiceInterface();
-
-public Q_SLOTS: // METHODS
- inline QDBusPendingReply<uint> AddRecord(const QString &in0)
- {
- QList<QVariant> argumentList;
- argumentList << QVariant::fromValue(in0);
- return asyncCallWithArgumentList(QStringLiteral("AddRecord"), argumentList);
- }
-
- inline QDBusPendingReply<> CancelAuthorization()
- {
- QList<QVariant> argumentList;
- return asyncCallWithArgumentList(QStringLiteral("CancelAuthorization"), argumentList);
- }
-
- inline QDBusPendingReply<> RemoveRecord(uint in0)
- {
- QList<QVariant> argumentList;
- argumentList << QVariant::fromValue(in0);
- return asyncCallWithArgumentList(QStringLiteral("RemoveRecord"), argumentList);
- }
-
- inline QDBusPendingReply<> RequestAuthorization(const QString &in0, uint in1)
- {
- QList<QVariant> argumentList;
- argumentList << QVariant::fromValue(in0) << QVariant::fromValue(in1);
- return asyncCallWithArgumentList(QStringLiteral("RequestAuthorization"), argumentList);
- }
-
- inline QDBusPendingReply<> UpdateRecord(uint in0, const QString &in1)
- {
- QList<QVariant> argumentList;
- argumentList << QVariant::fromValue(in0) << QVariant::fromValue(in1);
- return asyncCallWithArgumentList(QStringLiteral("UpdateRecord"), argumentList);
- }
-
-Q_SIGNALS: // SIGNALS
-};
-
-namespace org {
- namespace bluez {
- typedef ::OrgBluezServiceInterface Service;
- }
-}
-#endif
diff --git a/src/bluetooth/bluez/servicemap.cpp b/src/bluetooth/bluez/servicemap.cpp
index 46616cbe..8a8b6f44 100644
--- a/src/bluetooth/bluez/servicemap.cpp
+++ b/src/bluetooth/bluez/servicemap.cpp
@@ -1,44 +1,12 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "servicemap_p.h"
+QT_BEGIN_NAMESPACE
+
+QT_IMPL_METATYPE_EXTERN(ServiceMap)
+
const QDBusArgument &operator>>(const QDBusArgument &argument, ServiceMap &serviceMap)
{
argument.beginMap();
@@ -59,3 +27,5 @@ const QDBusArgument &operator>>(const QDBusArgument &argument, ServiceMap &servi
return argument;
}
+
+QT_END_NAMESPACE
diff --git a/src/bluetooth/bluez/servicemap_p.h b/src/bluetooth/bluez/servicemap_p.h
index 572c2790..773f9d0e 100644
--- a/src/bluetooth/bluez/servicemap_p.h
+++ b/src/bluetooth/bluez/servicemap_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef SERVICEMAP_P_H
#define SERVICEMAP_P_H
@@ -51,14 +15,21 @@
// We mean it.
//
+#include <QtBluetooth/qtbluetoothglobal.h>
+
#include <QtCore/QMap>
#include <QtCore/QString>
#include <QtDBus/QDBusArgument>
+#include <QtCore/private/qglobal_p.h>
+
+QT_BEGIN_NAMESPACE
typedef QMap<quint32, QString> ServiceMap;
const QDBusArgument &operator>>(const QDBusArgument &argument, ServiceMap &serviceMap);
-Q_DECLARE_METATYPE(ServiceMap)
+QT_END_NAMESPACE
+
+QT_DECL_METATYPE_EXTERN(ServiceMap, Q_BLUETOOTH_EXPORT)
#endif // SERVICEMAP_P_H
diff --git a/src/bluetooth/configure.cmake b/src/bluetooth/configure.cmake
new file mode 100644
index 00000000..a3ae8735
--- /dev/null
+++ b/src/bluetooth/configure.cmake
@@ -0,0 +1,76 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+
+
+#### Inputs
+
+
+
+#### Libraries
+
+qt_find_package(BlueZ PROVIDED_TARGETS PkgConfig::BLUEZ)
+
+
+#### Tests
+
+if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/../../config.tests/bluez/CMakeLists.txt")
+ qt_config_compile_test("bluez"
+ LABEL "BlueZ"
+ PROJECT_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../config.tests/bluez")
+endif()
+
+if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/../../config.tests/bluez_le/CMakeLists.txt")
+ qt_config_compile_test("bluez_le"
+ LABEL "BlueZ Low Energy"
+ PROJECT_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../config.tests/bluez_le")
+endif()
+
+if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/../../config.tests/linux_crypto_api/CMakeLists.txt")
+ qt_config_compile_test("linux_crypto_api"
+ LABEL "Linux Crypto API"
+ PROJECT_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../config.tests/linux_crypto_api")
+endif()
+
+if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/../../config.tests/winrt_bt/CMakeLists.txt")
+ qt_config_compile_test("winrt_bt"
+ LABEL "WinRT Bluetooth API"
+ PROJECT_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../config.tests/winrt_bt")
+endif()
+
+
+#### Features
+
+qt_feature("bluez" PUBLIC
+ LABEL "BlueZ"
+ CONDITION BLUEZ_FOUND AND TEST_bluez AND QT_FEATURE_dbus
+)
+qt_feature("bluez_le" PRIVATE
+ LABEL "BlueZ Low Energy"
+ CONDITION QT_FEATURE_bluez AND TEST_bluez_le
+)
+qt_feature("linux_crypto_api" PRIVATE
+ LABEL "Linux Crypto API"
+ CONDITION QT_FEATURE_bluez_le AND TEST_linux_crypto_api
+)
+qt_feature("winrt_bt" PRIVATE
+ LABEL "WinRT Bluetooth API"
+ CONDITION WIN32 AND TEST_winrt_bt
+)
+
+qt_configure_add_summary_section(NAME "Qt Bluetooth")
+qt_configure_add_summary_entry(ARGS bluez)
+qt_configure_add_summary_entry(ARGS bluez_le)
+qt_configure_add_summary_entry(ARGS linux_crypto_api)
+qt_configure_add_summary_entry(ARGS winrt_bt)
+qt_configure_end_summary_section()
+qt_configure_add_report_entry(
+ TYPE NOTE
+ MESSAGE "Bluez version is too old to support Bluetooth Low Energy. Only classic Bluetooth will be available."
+ CONDITION QT_FEATURE_bluez AND NOT QT_FEATURE_bluez_le
+)
+qt_configure_add_report_entry(
+ TYPE NOTE
+ MESSAGE "Linux crypto API not present. BTLE signed writes will not work."
+ CONDITION QT_FEATURE_bluez_le AND NOT QT_FEATURE_linux_crypto_api
+)
diff --git a/src/bluetooth/configure.json b/src/bluetooth/configure.json
deleted file mode 100644
index 3bd95903..00000000
--- a/src/bluetooth/configure.json
+++ /dev/null
@@ -1,107 +0,0 @@
-{
- "module": "bluetooth",
- "testDir": "../../config.tests",
-
- "commandline": {
- "options": {
- "native-win32-bluetooth": "boolean"
- }
- },
-
- "libraries": {
- "bluez": {
- "label": "BlueZ",
- "test": "bluez",
- "sources": [
- { "type": "pkgConfig", "args": "bluez" },
- "-lbluetooth"
- ]
- }
- },
-
- "tests": {
- "bluez_le": {
- "label": "BlueZ Low Energy",
- "type": "compile",
- "test": "bluez_le"
- },
- "linux_crypto_api": {
- "label": "Linux Crypto API",
- "type": "compile",
- "test": "linux_crypto_api"
- },
- "winrt_bt": {
- "label": "WinRT Bluetooth API",
- "type": "compile",
- "test": "winrt_bt"
- },
- "winrt_btle_no_pairing": {
- "label": "WinRT extended bluetooth low energy API",
- "type": "compile",
- "test": "winrt_btle_no_pairing"
- }
- },
-
- "features": {
- "bluez": {
- "label": "BlueZ",
- "condition": "libs.bluez && features.concurrent && features.dbus",
- "output": [ "publicFeature" ]
- },
- "bluez_le": {
- "label": "BlueZ Low Energy",
- "condition": "features.bluez && tests.bluez_le",
- "output": [ "privateFeature" ]
- },
- "linux_crypto_api": {
- "label": "Linux Crypto API",
- "condition": "features.bluez_le && tests.linux_crypto_api",
- "output": [ "privateFeature" ]
- },
- "native-win32-bluetooth": {
- "label": "Native Win32 Bluetooth",
- "purpose": "Uses the native Win32 Bluetooth backend.",
- "section": "Qt Bluetooth",
- "autoDetect": false,
- "output": [ "publicFeature", "feature" ]
- },
- "winrt_bt": {
- "label": "WinRT Bluetooth API (desktop & UWP)",
- "condition": "config.win32 && !features.native-win32-bluetooth && tests.winrt_bt",
- "output": [ "privateFeature" ]
- },
- "winrt_btle_no_pairing": {
- "label": "WinRT advanced bluetooth low energy API (desktop & UWP)",
- "condition": "config.win32 && features.winrt_bt && tests.winrt_btle_no_pairing",
- "output": [ "privateFeature" ]
- }
- },
-
- "report": [
- {
- "type": "note",
- "condition": "features.bluez_le && !features.linux_crypto_api",
- "message": "Linux crypto API not present. BTLE signed writes will not work."
- },
- {
- "type": "note",
- "condition": "features.bluez && !features.bluez_le",
- "message": "Bluez version is too old to support Bluetooth Low Energy.
-Only classic Bluetooth will be available."
- }
- ],
-
- "summary": [
- {
- "section": "Qt Bluetooth",
- "entries": [
- "bluez",
- "bluez_le",
- "linux_crypto_api",
- "native-win32-bluetooth",
- "winrt_bt",
- "winrt_btle_no_pairing"
- ]
- }
- ]
-}
diff --git a/src/bluetooth/darwin/btcentralmanager.mm b/src/bluetooth/darwin/btcentralmanager.mm
index 86950302..55eaf2a0 100644
--- a/src/bluetooth/darwin/btcentralmanager.mm
+++ b/src/bluetooth/darwin/btcentralmanager.mm
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qlowenergyserviceprivate_p.h"
#include "qlowenergycharacteristic.h"
@@ -45,6 +9,7 @@
#include <QtCore/qloggingcategory.h>
#include <QtCore/qdebug.h>
+#include <QtCore/qmap.h>
#include <algorithm>
#include <vector>
@@ -87,7 +52,7 @@ ObjCStrongReference<NSError> qt_timeoutNSError(OperationTimeout type)
// after all (except callbacks checking if an operation was successful
// or not).
Q_ASSERT(type != OperationTimeout::none);
- Q_UNUSED(type)
+ Q_UNUSED(type);
NSError *nsError = [[NSError alloc] initWithDomain:CBErrorDomain
code:CBErrorOperationCancelled
userInfo:nil];
@@ -106,7 +71,7 @@ QT_END_NAMESPACE
QT_USE_NAMESPACE
-@interface QT_MANGLE_NAMESPACE(DarwinBTCentralManager) (PrivateAPI)
+@interface DarwinBTCentralManager (PrivateAPI)
- (void)watchAfter:(id)object timeout:(DarwinBluetooth::OperationTimeout)type;
- (bool)objectIsUnderWatch:(id)object operation:(DarwinBluetooth::OperationTimeout)type;
@@ -138,7 +103,9 @@ QT_USE_NAMESPACE
@end
-@implementation QT_MANGLE_NAMESPACE(DarwinBTCentralManager)
+using DiscoveryMode = QLowEnergyService::DiscoveryMode;
+
+@implementation DarwinBTCentralManager
{
@private
CBCentralManager *manager;
@@ -159,7 +126,7 @@ QT_USE_NAMESPACE
// We'd like to avoid loops in a services' topology:
DarwinBluetooth::ObjCStrongReference<NSMutableSet> visitedServices;
- QList<QBluetoothUuid> servicesToDiscoverDetails;
+ QMap<QBluetoothUuid, DiscoveryMode> servicesToDiscoverDetails;
DarwinBluetooth::ServiceHash serviceMap;
DarwinBluetooth::CharHash charMap;
@@ -177,6 +144,7 @@ QT_USE_NAMESPACE
std::vector<DarwinBluetooth::GCDTimer> timeoutWatchdogs;
CBPeripheral *peripheral;
+ int lastKnownMtu;
}
- (id)initWith:(DarwinBluetooth::LECBManagerNotifier *)aNotifier
@@ -203,6 +171,8 @@ QT_USE_NAMESPACE
if (!timeoutMS)
timeoutMS = 20000;
+
+ lastKnownMtu = defaultMtu;
}
return self;
@@ -241,7 +211,7 @@ QT_USE_NAMESPACE
{
using namespace DarwinBluetooth;
- GCDTimer newWatcher([[GCDTimerObjC alloc] initWithDelegate:self], RetainPolicy::noInitialRetain);
+ GCDTimer newWatcher([[DarwinBTGCDTimer alloc] initWithDelegate:self], RetainPolicy::noInitialRetain);
[newWatcher watchAfter:object withTimeoutType:type];
timeoutWatchdogs.push_back(newWatcher);
[newWatcher startWithTimeout:timeoutMS step:200];
@@ -270,11 +240,11 @@ QT_USE_NAMESPACE
- (void)timeout:(id)sender
{
- Q_UNUSED(sender)
+ Q_UNUSED(sender);
using namespace DarwinBluetooth;
- GCDTimerObjC *watcher = static_cast<GCDTimerObjC *>(sender);
+ DarwinBTGCDTimer *watcher = static_cast<DarwinBTGCDTimer *>(sender);
id cbObject = [watcher objectUnderWatch];
const OperationTimeout type = [watcher timeoutType];
@@ -371,7 +341,7 @@ QT_USE_NAMESPACE
}
- const quint128 qtUuidData(deviceUuid.toUInt128());
+ const QUuid::Id128Bytes qtUuidData(deviceUuid.toBytes());
uuid_t uuidData = {};
std::copy(qtUuidData.data, qtUuidData.data + 16, uuidData);
const ObjCScopedPointer<NSUUID> nsUuid([[NSUUID alloc] initWithUUIDBytes:uuidData], RetainPolicy::noInitialRetain);
@@ -383,11 +353,11 @@ QT_USE_NAMESPACE
}
[uuids addObject:nsUuid];
- // With the latest CoreBluetooth, we can synchronously retrive peripherals:
+ // With the latest CoreBluetooth, we can synchronously retrieve peripherals:
QT_BT_MAC_AUTORELEASEPOOL;
NSArray *const peripherals = [manager retrievePeripheralsWithIdentifiers:uuids];
if (!peripherals || peripherals.count != 1) {
- qCWarning(QT_BT_DARWIN) << "failed to retrive a peripheral";
+ qCWarning(QT_BT_DARWIN) << "failed to retrieve a peripheral";
if (notifier)
emit notifier->CBManagerError(QLowEnergyController::UnknownRemoteDeviceError);
return;
@@ -411,6 +381,7 @@ QT_USE_NAMESPACE
if (notifier)
emit notifier->connected();
} else {
+ [self setMtu:defaultMtu];
qCDebug(QT_BT_DARWIN) << "trying to connect";
managerState = CentralManagerConnecting;
[manager connectPeripheral:peripheral options:nil];
@@ -469,7 +440,6 @@ QT_USE_NAMESPACE
//parameter to nil is considerably slower and is not recommended."
//
// ... but we'd like to have them all:
- [peripheral setDelegate:self];
managerState = CentralManagerDiscovering;
[self watchAfter:peripheral timeout:OperationTimeout::serviceDiscovery];
[peripheral discoverServices:nil];
@@ -506,6 +476,7 @@ QT_USE_NAMESPACE
}
- (void)discoverServiceDetails:(const QBluetoothUuid &)serviceUuid
+ readValues:(bool) read
{
// This function does not change 'managerState', since it
// can be called concurrently (not waiting for the previous
@@ -526,7 +497,8 @@ QT_USE_NAMESPACE
QT_BT_MAC_AUTORELEASEPOOL;
if (CBService *const service = [self serviceForUUID:serviceUuid]) {
- servicesToDiscoverDetails.append(serviceUuid);
+ const auto mode = read ? DiscoveryMode::FullDiscovery : DiscoveryMode::SkipValueDiscovery;
+ servicesToDiscoverDetails[serviceUuid] = mode;
[self watchAfter:service timeout:OperationTimeout::characteristicsDiscovery];
[peripheral discoverCharacteristics:nil forService:service];
return;
@@ -627,7 +599,8 @@ QT_USE_NAMESPACE
QT_BT_MAC_AUTORELEASEPOOL;
const QBluetoothUuid serviceUuid(qt_uuid(service.UUID));
- servicesToDiscoverDetails.removeAll(serviceUuid);
+ const bool skipValues = servicesToDiscoverDetails[serviceUuid] == DiscoveryMode::SkipValueDiscovery;
+ servicesToDiscoverDetails.remove(serviceUuid);
const NSUInteger nHandles = qt_countGATTEntries(service);
Q_ASSERT_X(nHandles, Q_FUNC_INFO, "unexpected number of GATT entires");
@@ -667,7 +640,8 @@ QT_USE_NAMESPACE
newChar.uuid = qt_uuid(c.UUID);
const int cbProps = c.properties & 0xff;
newChar.properties = static_cast<QLowEnergyCharacteristic::PropertyTypes>(cbProps);
- newChar.value = qt_bytearray(c.value);
+ if (!skipValues)
+ newChar.value = qt_bytearray(c.value);
newChar.valueHandle = lastValidHandle;
NSArray *const ds = c.descriptors;
@@ -683,7 +657,7 @@ QT_USE_NAMESPACE
newDesc.value = qt_bytearray(static_cast<NSObject *>(d.value));
descList[lastValidHandle] = newDesc;
// Check, if it's client characteristic configuration descriptor:
- if (newDesc.uuid == QBluetoothUuid::ClientCharacteristicConfiguration) {
+ if (newDesc.uuid == QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration) {
if (newDesc.value.size() && (newDesc.value[0] & 3))
[peripheral setNotifyValue:YES forCharacteristic:c];
}
@@ -807,7 +781,7 @@ QT_USE_NAMESPACE
CBCharacteristic *const characteristic = charMap[request.handle];
if (request.type == LERequest::ClientConfiguration) {
- const QBluetoothUuid qtUuid(QBluetoothUuid::ClientCharacteristicConfiguration);
+ const QBluetoothUuid qtUuid(QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration);
CBDescriptor *const descriptor = [self descriptor:qtUuid forCharacteristic:characteristic];
Q_ASSERT_X(descriptor, Q_FUNC_INFO, "no client characteristic "
"configuration descriptor found");
@@ -847,6 +821,41 @@ QT_USE_NAMESPACE
}
}
+- (void)setMtu:(int)newMtu
+{
+ if (lastKnownMtu == newMtu)
+ return;
+ lastKnownMtu = newMtu;
+ if (notifier)
+ emit notifier->mtuChanged(newMtu);
+}
+
+- (int)mtu
+{
+ using namespace DarwinBluetooth;
+
+ if (![self isConnected]) {
+ [self setMtu:defaultMtu];
+ return defaultMtu;
+ }
+
+ Q_ASSERT(peripheral);
+ const NSUInteger maxLen = [peripheral maximumWriteValueLengthForType:
+ CBCharacteristicWriteWithoutResponse];
+ if (maxLen > std::numeric_limits<int>::max() - 3)
+ [self setMtu:defaultMtu];
+ else
+ [self setMtu:int(maxLen) + 3];
+
+ return lastKnownMtu;
+}
+
+- (void)readRssi
+{
+ Q_ASSERT([self isConnected]);
+ [peripheral readRSSI];
+}
+
- (void)setNotifyValue:(const QByteArray &)value
forCharacteristic:(QLowEnergyHandle)charHandle
onService:(const QBluetoothUuid &)serviceUuid
@@ -868,7 +877,7 @@ QT_USE_NAMESPACE
// At the moment we call setNotifyValue _only_ from 'writeDescriptor';
// from Qt's API POV it's a descriptor write operation and we must report
// it back, so check _now_ that we really have this descriptor.
- const QBluetoothUuid qtUuid(QBluetoothUuid::ClientCharacteristicConfiguration);
+ const QBluetoothUuid qtUuid(QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration);
if (![self descriptor:qtUuid forCharacteristic:charMap[charHandle]]) {
qCWarning(QT_BT_DARWIN) << "no client characteristic configuration found";
if (notifier) {
@@ -1240,17 +1249,13 @@ QT_USE_NAMESPACE
// Let's check some states we do not like first:
if (state == CBManagerStateUnsupported || state == CBManagerStateUnauthorized) {
- if (managerState == CentralManagerUpdating) {
- // We tried to connect just to realize, LE is not supported. Report this.
- managerState = CentralManagerIdle;
- if (notifier)
+ managerState = CentralManagerIdle;
+ // The LE is not supported or its usage was not authorized
+ if (notifier) {
+ if (state == CBManagerStateUnsupported)
emit notifier->LEnotSupported();
- } else {
- // TODO: if we are here, LE _was_ supported and we first managed to update
- // and reset managerState from CentralManagerUpdating.
- managerState = CentralManagerIdle;
- if (notifier)
- emit notifier->CBManagerError(QLowEnergyController::InvalidBluetoothAdapterError);
+ else
+ emit notifier->CBManagerError(QLowEnergyController::MissingPermissionsError);
}
[self stopWatchers];
return;
@@ -1288,14 +1293,18 @@ QT_USE_NAMESPACE
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)aPeripheral
{
- Q_UNUSED(central)
- Q_UNUSED(aPeripheral)
+ Q_UNUSED(central);
+ Q_UNUSED(aPeripheral);
if (managerState != DarwinBluetooth::CentralManagerConnecting) {
// We called cancel but before disconnected, managed to connect?
return;
}
+ void([self mtu]);
+
+ [peripheral setDelegate:self];
+
managerState = DarwinBluetooth::CentralManagerIdle;
if (notifier)
emit notifier->connected();
@@ -1304,9 +1313,9 @@ QT_USE_NAMESPACE
- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)aPeripheral
error:(NSError *)error
{
- Q_UNUSED(central)
- Q_UNUSED(aPeripheral)
- Q_UNUSED(error)
+ Q_UNUSED(central);
+ Q_UNUSED(aPeripheral);
+ Q_UNUSED(error);
if (managerState != DarwinBluetooth::CentralManagerConnecting) {
// Canceled already.
@@ -1322,8 +1331,8 @@ QT_USE_NAMESPACE
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)aPeripheral
error:(NSError *)error
{
- Q_UNUSED(central)
- Q_UNUSED(aPeripheral)
+ Q_UNUSED(central);
+ Q_UNUSED(aPeripheral);
// Clear internal caches/data.
[self reset];
@@ -1344,7 +1353,7 @@ QT_USE_NAMESPACE
- (void)peripheral:(CBPeripheral *)aPeripheral didDiscoverServices:(NSError *)error
{
- Q_UNUSED(aPeripheral)
+ Q_UNUSED(aPeripheral);
using namespace DarwinBluetooth;
@@ -1365,8 +1374,10 @@ QT_USE_NAMESPACE
if (error) {
NSLog(@"%s failed with error %@", Q_FUNC_INFO, error);
// TODO: better error mapping required.
+ // Emit an error which also causes the service discovery finished() signal
if (notifier)
emit notifier->CBManagerError(QLowEnergyController::UnknownError);
+ return;
}
[self discoverIncludedServices];
@@ -1375,8 +1386,8 @@ QT_USE_NAMESPACE
- (void)peripheral:(CBPeripheral *)aPeripheral
didModifyServices:(NSArray<CBService *> *)invalidatedServices
{
- Q_UNUSED(aPeripheral)
- Q_UNUSED(invalidatedServices)
+ Q_UNUSED(aPeripheral);
+ Q_UNUSED(invalidatedServices);
qCWarning(QT_BT_DARWIN) << "The peripheral has modified its services.";
// "This method is invoked whenever one or more services of a peripheral have changed.
@@ -1400,7 +1411,7 @@ QT_USE_NAMESPACE
- (void)peripheral:(CBPeripheral *)aPeripheral didDiscoverIncludedServicesForService:(CBService *)service
error:(NSError *)error
{
- Q_UNUSED(aPeripheral)
+ Q_UNUSED(aPeripheral);
using namespace DarwinBluetooth;
@@ -1478,7 +1489,7 @@ QT_USE_NAMESPACE
{
// This method does not change 'managerState', we can have several
// discoveries active.
- Q_UNUSED(aPeripheral)
+ Q_UNUSED(aPeripheral);
if (!notifier) {
// Detached.
@@ -1494,15 +1505,22 @@ QT_USE_NAMESPACE
[self stopWatchingAfter:service operation:OperationTimeout::characteristicsDiscovery];
+ const auto qtUuid = qt_uuid(service.UUID);
+ const bool skipRead = servicesToDiscoverDetails[qtUuid] == DiscoveryMode::SkipValueDiscovery;
+
Q_ASSERT_X(managerState != CentralManagerUpdating, Q_FUNC_INFO, "invalid state");
if (error) {
NSLog(@"%s failed with error: %@", Q_FUNC_INFO, error);
// We did not discover any characteristics and can not discover descriptors,
// inform our delegate (it will set a service state also).
- emit notifier->CBManagerError(qt_uuid(service.UUID), QLowEnergyController::UnknownError);
+ emit notifier->CBManagerError(qtUuid, QLowEnergyController::UnknownError);
}
+ if (skipRead) {
+ [self serviceDetailsDiscoveryFinished:service];
+ return;
+ }
[self readCharacteristics:service];
}
@@ -1510,7 +1528,7 @@ QT_USE_NAMESPACE
didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic
error:(NSError *)error
{
- Q_UNUSED(aPeripheral)
+ Q_UNUSED(aPeripheral);
if (!notifier) // Detached.
return;
@@ -1592,7 +1610,7 @@ QT_USE_NAMESPACE
{
// This method does not change 'managerState', we can
// have several discoveries active at the same time.
- Q_UNUSED(aPeripheral)
+ Q_UNUSED(aPeripheral);
if (!notifier) {
// Detached, no need to continue ...
@@ -1628,7 +1646,7 @@ QT_USE_NAMESPACE
didUpdateValueForDescriptor:(CBDescriptor *)descriptor
error:(NSError *)error
{
- Q_UNUSED(aPeripheral)
+ Q_UNUSED(aPeripheral);
Q_ASSERT_X(peripheral, Q_FUNC_INFO, "invalid peripheral (nil)");
@@ -1713,8 +1731,8 @@ QT_USE_NAMESPACE
didWriteValueForCharacteristic:(CBCharacteristic *)characteristic
error:(NSError *)error
{
- Q_UNUSED(aPeripheral)
- Q_UNUSED(characteristic)
+ Q_UNUSED(aPeripheral);
+ Q_UNUSED(characteristic);
if (!notifier) {
// Detached.
@@ -1762,7 +1780,7 @@ QT_USE_NAMESPACE
didWriteValueForDescriptor:(CBDescriptor *)descriptor
error:(NSError *)error
{
- Q_UNUSED(aPeripheral)
+ Q_UNUSED(aPeripheral);
if (!notifier) {
// Detached already.
@@ -1798,7 +1816,7 @@ QT_USE_NAMESPACE
didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic
error:(NSError *)error
{
- Q_UNUSED(aPeripheral)
+ Q_UNUSED(aPeripheral);
if (!notifier)
return;
@@ -1809,7 +1827,7 @@ QT_USE_NAMESPACE
requestPending = false;
- const QBluetoothUuid qtUuid(QBluetoothUuid::ClientCharacteristicConfiguration);
+ const QBluetoothUuid qtUuid(QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration);
CBDescriptor *const descriptor = [self descriptor:qtUuid forCharacteristic:characteristic];
const QByteArray valueToReport(valuesToWrite.value(descriptor, QByteArray()));
const int nRemoved = valuesToWrite.remove(descriptor);
@@ -1827,6 +1845,26 @@ QT_USE_NAMESPACE
[self performNextRequest];
}
+- (void)peripheral:(CBPeripheral *)aPeripheral didReadRSSI:(NSNumber *)RSSI error:(nullable NSError *)error
+{
+ Q_UNUSED(aPeripheral);
+
+ if (!notifier) // This controller was detached.
+ return;
+
+ if (error) {
+ NSLog(@"Reading RSSI finished with error: %@", error);
+ return emit notifier->CBManagerError(QLowEnergyController::RssiReadError);
+ }
+
+ if (!RSSI) {
+ qCWarning(QT_BT_DARWIN, "Reading RSSI returned no value");
+ return emit notifier->CBManagerError(QLowEnergyController::RssiReadError);
+ }
+
+ emit notifier->rssiUpdated(qint16([RSSI shortValue]));
+}
+
- (void)detach
{
if (notifier) {
diff --git a/src/bluetooth/darwin/btcentralmanager_p.h b/src/bluetooth/darwin/btcentralmanager_p.h
index 0b5c8fbb..3986228e 100644
--- a/src/bluetooth/darwin/btcentralmanager_p.h
+++ b/src/bluetooth/darwin/btcentralmanager_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef BTCENTRALMANAGER_P_H
#define BTCENTRALMANAGER_P_H
@@ -52,11 +16,12 @@
//
#include "qlowenergycontroller.h"
-#include "qlowenergyservice.h"
#include "qbluetoothuuid.h"
#include "btgcdtimer_p.h"
#include "btutility_p.h"
+#include <QtCore/private/qcore_mac_p.h>
+
#include <QtCore/qbytearray.h>
#include <QtCore/qglobal.h>
#include <QtCore/qqueue.h>
@@ -68,8 +33,6 @@
QT_BEGIN_NAMESPACE
-class QLowEnergyServicePrivate;
-
namespace DarwinBluetooth {
class LECBManagerNotifier;
@@ -147,7 +110,11 @@ QT_END_NAMESPACE
- (void)disconnectFromDevice;
- (void)discoverServices;
-- (void)discoverServiceDetails:(const QT_PREPEND_NAMESPACE(QBluetoothUuid) &)serviceUuid;
+- (void)discoverServiceDetails:(const QT_PREPEND_NAMESPACE(QBluetoothUuid) &)serviceUuid
+ readValues:(bool)read;
+
+- (int)mtu;
+- (void)readRssi;
- (void)setNotifyValue:(const QT_PREPEND_NAMESPACE(QByteArray) &)value
forCharacteristic:(QT_PREPEND_NAMESPACE(QLowEnergyHandle))charHandle
@@ -172,4 +139,6 @@ QT_END_NAMESPACE
@end
+QT_NAMESPACE_ALIAS_OBJC_CLASS(DarwinBTCentralManager);
+
#endif
diff --git a/src/bluetooth/darwin/btconnectionmonitor.mm b/src/bluetooth/darwin/btconnectionmonitor.mm
index f9adfde8..12dd7884 100644
--- a/src/bluetooth/darwin/btconnectionmonitor.mm
+++ b/src/bluetooth/darwin/btconnectionmonitor.mm
@@ -1,57 +1,16 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "btconnectionmonitor_p.h"
#include "btutility_p.h"
-#include <QtCore/qdebug.h>
-
-QT_BEGIN_NAMESPACE
+#include "qbluetoothaddress.h"
+#include <QtCore/qdebug.h>
-QT_END_NAMESPACE
-
-#ifdef QT_NAMESPACE
-using namespace QT_NAMESPACE;
-#endif
+QT_USE_NAMESPACE
-@implementation QT_MANGLE_NAMESPACE(DarwinBTConnectionMonitor)
+@implementation DarwinBTConnectionMonitor
{
QT_PREPEND_NAMESPACE(DarwinBluetooth::ConnectionMonitor) *monitor;
IOBluetoothUserNotification *discoveryNotification;
@@ -74,27 +33,30 @@ using namespace QT_NAMESPACE;
- (void)dealloc
{
- [discoveryNotification unregister];
- [discoveryNotification release];
-
- for (IOBluetoothUserNotification *n in foundConnections)
- [n unregister];
-
- [foundConnections release];
-
+ Q_ASSERT_X(!monitor, "-dealloc",
+ "Connection monitor was not stopped, calling -stopMonitoring is required");
[super dealloc];
}
- (void)connectionNotification:(IOBluetoothUserNotification *)aNotification
withDevice:(IOBluetoothDevice *)device
{
- Q_UNUSED(aNotification)
+ Q_UNUSED(aNotification);
typedef IOBluetoothUserNotification Notification;
if (!device)
return;
+ if (!monitor) {
+ // Rather surprising: monitor == nullptr means we stopped monitoring.
+ // So apparently this thingie is still alive and keeps receiving
+ // notifications.
+ qCWarning(QT_BT_DARWIN,
+ "Connection notification received in a monitor that was cancelled");
+ return;
+ }
+
QT_BT_MAC_AUTORELEASEPOOL;
// All Obj-C objects are autoreleased.
@@ -130,4 +92,18 @@ using namespace QT_NAMESPACE;
monitor->deviceDisconnected(deviceAddress);
}
+-(void)stopMonitoring
+{
+ monitor = nullptr;
+ [discoveryNotification unregister];
+ [discoveryNotification release];
+ discoveryNotification = nil;
+
+ for (IOBluetoothUserNotification *n in foundConnections)
+ [n unregister];
+
+ [foundConnections release];
+ foundConnections = nil;
+}
+
@end
diff --git a/src/bluetooth/darwin/btconnectionmonitor_p.h b/src/bluetooth/darwin/btconnectionmonitor_p.h
index e3b7b90d..f4f5c7ea 100644
--- a/src/bluetooth/darwin/btconnectionmonitor_p.h
+++ b/src/bluetooth/darwin/btconnectionmonitor_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef BTCONNECTIONMONITOR_P_H
#define BTCONNECTIONMONITOR_P_H
@@ -51,9 +15,10 @@
// We mean it.
//
-#include "qbluetoothaddress.h"
#include "btdelegates_p.h"
+#include <QtCore/private/qcore_mac_p.h>
+
#include <QtCore/qglobal.h>
#include <Foundation/Foundation.h>
@@ -66,6 +31,9 @@
- (void)connectionNotification:(id)notification withDevice:(IOBluetoothDevice *)device;
- (void)connectionClosedNotification:(id)notification withDevice:(IOBluetoothDevice *)device;
+- (void)stopMonitoring;
@end
+QT_NAMESPACE_ALIAS_OBJC_CLASS(DarwinBTConnectionMonitor);
+
#endif
diff --git a/src/bluetooth/darwin/btdelegates.cpp b/src/bluetooth/darwin/btdelegates.cpp
index 531ca1df..fc86778f 100644
--- a/src/bluetooth/darwin/btdelegates.cpp
+++ b/src/bluetooth/darwin/btdelegates.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "btdelegates_p.h"
diff --git a/src/bluetooth/darwin/btdelegates_p.h b/src/bluetooth/darwin/btdelegates_p.h
index 11fbcc28..7dd9fde5 100644
--- a/src/bluetooth/darwin/btdelegates_p.h
+++ b/src/bluetooth/darwin/btdelegates_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef BTDELEGATES_P_H
#define BTDELEGATES_P_H
@@ -51,24 +15,18 @@
// We mean it.
//
-#include "qbluetoothdevicediscoveryagent.h"
-#include "qlowenergycontroller.h"
-#include "qbluetooth.h"
-
-#include <QtCore/qsharedpointer.h>
-#include <QtCore/qglobal.h>
+#include <QtCore/private/qglobal_p.h>
#if defined(Q_OS_MACOS)
#include <IOKit/IOReturn.h>
+#include <cstddef>
#include <cstdint>
QT_BEGIN_NAMESPACE
-class QLowEnergyServicePrivate;
class QBluetoothAddress;
-class QByteArray;
namespace DarwinBluetooth {
diff --git a/src/bluetooth/darwin/btdeviceinquiry.mm b/src/bluetooth/darwin/btdeviceinquiry.mm
index ad59a4a4..19401ee3 100644
--- a/src/bluetooth/darwin/btdeviceinquiry.mm
+++ b/src/bluetooth/darwin/btdeviceinquiry.mm
@@ -1,55 +1,26 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "btdeviceinquiry_p.h"
#include "btutility_p.h"
#include <QtCore/qloggingcategory.h>
+#include <QtCore/qtimer.h>
#include <QtCore/qdebug.h>
+#include <memory>
+
QT_USE_NAMESPACE
-@implementation QT_MANGLE_NAMESPACE(DarwinBTClassicDeviceInquiry)
+const uint8_t IOBlueoothInquiryLengthS = 15;
+
+@implementation DarwinBTClassicDeviceInquiry
{
IOBluetoothDeviceInquiry *m_inquiry;
bool m_active;
DarwinBluetooth::DeviceInquiryDelegate *m_delegate;//C++ "delegate"
+
+ std::unique_ptr<QTimer> watchDog;
}
- (id)initWithDelegate:(DarwinBluetooth::DeviceInquiryDelegate *)delegate
@@ -60,7 +31,13 @@ QT_USE_NAMESPACE
m_inquiry = [[IOBluetoothDeviceInquiry inquiryWithDelegate:self] retain];
if (m_inquiry) {
- [m_inquiry setInquiryLength:15];
+ // Inquiry length is 15 seconds. Starting from macOS 10.15.7
+ // (the lowest version I was able to test on, though initially
+ // the problem was found on macOS 11, arm64 machine and then
+ // confirmed on macOS 12 Beta 4), it seems to be ignored,
+ // thus scan never stops. See -start for how we try to prevent
+ // this.
+ [m_inquiry setInquiryLength:IOBlueoothInquiryLengthS];
[m_inquiry setUpdateNewDeviceNames:NO];//Useless, disable!
m_delegate = delegate;
} else {
@@ -99,12 +76,29 @@ QT_USE_NAMESPACE
m_active = true;
[m_inquiry clearFoundDevices];
+
+ qCDebug(QT_BT_DARWIN) << "Starting device inquiry with"
+ << IOBlueoothInquiryLengthS << "second timeout limit.";
const IOReturn result = [m_inquiry start];
if (result != kIOReturnSuccess) {
// QtBluetooth will probably convert an error into UnknownError,
- // loosing the actual information.
- qCWarning(QT_BT_DARWIN) << "failed with IOKit error code:" << result;
+ // losing the actual information.
+ qCWarning(QT_BT_DARWIN) << "device inquiry start failed with IOKit error code:" << result;
m_active = false;
+ } else {
+ // Docs say it's 10 s. by default, we set it to 15 s. (see -initWithDelegate:),
+ // and it may fail to finish.
+ watchDog.reset(new QTimer);
+ watchDog->connect(watchDog.get(), &QTimer::timeout, watchDog.get(), [self]{
+ qCWarning(QT_BT_DARWIN, "Manually interrupting IOBluetoothDeviceInquiry");
+ qCDebug(QT_BT_DARWIN) << "Found devices:" << [m_inquiry foundDevices];
+ [self stop];
+ });
+
+ watchDog->setSingleShot(true);
+ // +2 to give IOBluetooth a chance to stop it first:
+ watchDog->setInterval((IOBlueoothInquiryLengthS + 2) * 1000);
+ watchDog->start();
}
return result;
@@ -112,40 +106,38 @@ QT_USE_NAMESPACE
- (IOReturn)stop
{
- if (m_active) {
- Q_ASSERT_X(m_inquiry, Q_FUNC_INFO, "active but nil inquiry");
-
- m_active = false;
- const IOReturn res = [m_inquiry stop];
- if (res != kIOReturnSuccess)
- m_active = true;
- else
- qCDebug(QT_BT_DARWIN) << "-stop, success (waiting for 'inquiryComplete')";
+ if (!m_active)
+ return kIOReturnSuccess;
- return res;
- }
+ Q_ASSERT_X(m_inquiry, Q_FUNC_INFO, "active but nil inquiry");
- return kIOReturnSuccess;
+ return [m_inquiry stop];
}
- (void)deviceInquiryComplete:(IOBluetoothDeviceInquiry *)sender
error:(IOReturn)error aborted:(BOOL)aborted
{
- Q_UNUSED(aborted)
+ qCDebug(QT_BT_DARWIN) << "deviceInquiryComplete, error:" << error
+ << "user-stopped:" << aborted;
+ if (!m_active)
+ return;
if (sender != m_inquiry) // Can never happen in the current version.
return;
- m_active = false;
-
Q_ASSERT_X(m_delegate, Q_FUNC_INFO, "invalid device inquiry delegate (null)");
- if (error != kIOReturnSuccess) {
+ if (error != kIOReturnSuccess && !aborted) {
// QtBluetooth has not too many error codes, 'UnknownError' is not really
- // useful, report the actual error code here:
+ // useful, log the actual error code here:
qCWarning(QT_BT_DARWIN) << "IOKit error code: " << error;
- m_delegate->error(error);
+ // Let watchDog to stop it, calling -stop at timeout, otherwise,
+ // it looks like inquiry continues even after this error and
+ // keeps reporting new devices found.
} else {
+ // Either a normal completion or from a timer slot.
+ watchDog.reset();
+ m_active = false;
m_delegate->inquiryFinished();
}
}
@@ -153,16 +145,23 @@ QT_USE_NAMESPACE
- (void)deviceInquiryDeviceFound:(IOBluetoothDeviceInquiry *)sender
device:(IOBluetoothDevice *)device
{
+ qCDebug(QT_BT_DARWIN) << "deviceInquiryDeviceFound:" << [device nameOrAddress];
if (sender != m_inquiry) // Can never happen in the current version.
return;
+ if (!m_active) {
+ // We are not expecting new device(s) to be found after we reported 'finished'.
+ qCWarning(QT_BT_DARWIN, "IOBluetooth device found after inquiry complete/interrupted");
+ return;
+ }
+
Q_ASSERT_X(m_delegate, Q_FUNC_INFO, "invalid device inquiry delegate (null)");
m_delegate->classicDeviceFound(device);
}
- (void)deviceInquiryStarted:(IOBluetoothDeviceInquiry *)sender
{
- Q_UNUSED(sender)
+ Q_UNUSED(sender);
}
@end
diff --git a/src/bluetooth/darwin/btdeviceinquiry_p.h b/src/bluetooth/darwin/btdeviceinquiry_p.h
index fa4fd01c..66a91d53 100644
--- a/src/bluetooth/darwin/btdeviceinquiry_p.h
+++ b/src/bluetooth/darwin/btdeviceinquiry_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef BTDEVICEINQUIRY_P_H
#define BTDEVICEINQUIRY_P_H
@@ -53,6 +17,8 @@
#include "btdelegates_p.h"
+#include <QtCore/private/qcore_mac_p.h>
+
#include <QtCore/qglobal.h>
#include <Foundation/Foundation.h>
@@ -80,4 +46,6 @@
@end
+QT_NAMESPACE_ALIAS_OBJC_CLASS(DarwinBTClassicDeviceInquiry);
+
#endif
diff --git a/src/bluetooth/darwin/btdevicepair.mm b/src/bluetooth/darwin/btdevicepair.mm
index 947385f2..e76516fb 100644
--- a/src/bluetooth/darwin/btdevicepair.mm
+++ b/src/bluetooth/darwin/btdevicepair.mm
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "btdevicepair_p.h"
#include "btutility_p.h"
@@ -63,7 +27,7 @@ QT_END_NAMESPACE
QT_USE_NAMESPACE
-@implementation QT_MANGLE_NAMESPACE(DarwinBTClassicPairing)
+@implementation DarwinBTClassicPairing
{
QT_PREPEND_NAMESPACE(QBluetoothAddress) m_targetAddress;
@@ -160,17 +124,17 @@ QT_USE_NAMESPACE
- (void)devicePairingStarted:(id)sender
{
- Q_UNUSED(sender)
+ Q_UNUSED(sender);
}
- (void)devicePairingConnecting:(id)sender
{
- Q_UNUSED(sender)
+ Q_UNUSED(sender);
}
- (void)deviceParingPINCodeRequest:(id)sender
{
- Q_UNUSED(sender)
+ Q_UNUSED(sender);
}
- (void)devicePairingUserConfirmationRequest:(id)sender
@@ -187,8 +151,8 @@ QT_USE_NAMESPACE
- (void)devicePairingUserPasskeyNotification:(id)sender
passkey:(BluetoothPasskey)passkey
{
- Q_UNUSED(sender)
- Q_UNUSED(passkey)
+ Q_UNUSED(sender);
+ Q_UNUSED(passkey);
}
- (void)devicePairingFinished:(id)sender error:(IOReturn)error
@@ -208,8 +172,8 @@ QT_USE_NAMESPACE
- (void)deviceSimplePairingComplete:(id)sender
status:(BluetoothHCIEventStatus)status
{
- Q_UNUSED(sender)
- Q_UNUSED(status)
+ Q_UNUSED(sender);
+ Q_UNUSED(status);
}
@end
diff --git a/src/bluetooth/darwin/btdevicepair_p.h b/src/bluetooth/darwin/btdevicepair_p.h
index 1b361258..1b2f9ab6 100644
--- a/src/bluetooth/darwin/btdevicepair_p.h
+++ b/src/bluetooth/darwin/btdevicepair_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef BTDEVICEPAIR_P_H
#define BTDEVICEPAIR_P_H
@@ -55,6 +19,8 @@
#include "btdelegates_p.h"
#include "btutility_p.h"
+#include <QtCore/private/qcore_mac_p.h>
+
#include <QtCore/qglobal.h>
#include <Foundation/Foundation.h>
@@ -106,5 +72,6 @@ QT_END_NAMESPACE
@end
+QT_NAMESPACE_ALIAS_OBJC_CLASS(DarwinBTClassicPairing);
#endif
diff --git a/src/bluetooth/darwin/btgcdtimer.mm b/src/bluetooth/darwin/btgcdtimer.mm
index 9105a8fb..6b8633a4 100644
--- a/src/bluetooth/darwin/btgcdtimer.mm
+++ b/src/bluetooth/darwin/btgcdtimer.mm
@@ -1,45 +1,10 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "btgcdtimer_p.h"
#include "btutility_p.h"
+#include <QtCore/qelapsedtimer.h>
#include <QtCore/qdebug.h>
#include <algorithm>
@@ -47,7 +12,7 @@
QT_USE_NAMESPACE
using namespace DarwinBluetooth;
-@implementation QT_MANGLE_NAMESPACE(DarwinBTGCDTimer) {
+@implementation DarwinBTGCDTimer {
@private
qint64 timeoutMS;
qint64 timeoutStepMS;
diff --git a/src/bluetooth/darwin/btgcdtimer_p.h b/src/bluetooth/darwin/btgcdtimer_p.h
index dd67d6e8..b927336b 100644
--- a/src/bluetooth/darwin/btgcdtimer_p.h
+++ b/src/bluetooth/darwin/btgcdtimer_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef BTGCDTIMER_P_H
#define BTGCDTIMER_P_H
@@ -53,7 +17,8 @@
#include "btutility_p.h"
-#include <QtCore/qelapsedtimer.h>
+#include <QtCore/private/qcore_mac_p.h>
+
#include <QtCore/qglobal.h>
#include <Foundation/Foundation.h>
@@ -93,12 +58,13 @@ QT_END_NAMESPACE
- (QT_PREPEND_NAMESPACE(DarwinBluetooth)::OperationTimeout)timeoutType;
@end
+QT_NAMESPACE_ALIAS_OBJC_CLASS(DarwinBTGCDTimer);
+
QT_BEGIN_NAMESPACE
namespace DarwinBluetooth {
-using GCDTimerObjC = QT_MANGLE_NAMESPACE(DarwinBTGCDTimer);
-using GCDTimer = ObjCStrongReference<GCDTimerObjC>;
+using GCDTimer = ObjCStrongReference<DarwinBTGCDTimer>;
} // namespace DarwinBluetooth
diff --git a/src/bluetooth/darwin/btl2capchannel.mm b/src/bluetooth/darwin/btl2capchannel.mm
index e440a0ee..17c1d168 100644
--- a/src/bluetooth/darwin/btl2capchannel.mm
+++ b/src/bluetooth/darwin/btl2capchannel.mm
@@ -1,44 +1,8 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#include "btl2capchannel_p.h"
#include "qbluetoothaddress.h"
+#include "btl2capchannel_p.h"
#include "btdelegates_p.h"
#include "btutility_p.h"
@@ -47,7 +11,7 @@
QT_USE_NAMESPACE
-@implementation QT_MANGLE_NAMESPACE(DarwinBTL2CAPChannel)
+@implementation DarwinBTL2CAPChannel
{
QT_PREPEND_NAMESPACE(DarwinBluetooth)::ChannelDelegate *delegate;
IOBluetoothDevice *device;
@@ -148,7 +112,7 @@ QT_USE_NAMESPACE
- (void)l2capChannelData:(IOBluetoothL2CAPChannel*)l2capChannel
data:(void *)dataPointer length:(size_t)dataLength
{
- Q_UNUSED(l2capChannel)
+ Q_UNUSED(l2capChannel);
Q_ASSERT_X(delegate, Q_FUNC_INFO, "invalid delegate (null)");
@@ -159,7 +123,7 @@ QT_USE_NAMESPACE
- (void)l2capChannelOpenComplete:(IOBluetoothL2CAPChannel*)
l2capChannel status:(IOReturn)error
{
- Q_UNUSED(l2capChannel)
+ Q_UNUSED(l2capChannel);
Q_ASSERT_X(delegate, Q_FUNC_INFO, "invalid delegate (null)");
@@ -173,7 +137,7 @@ QT_USE_NAMESPACE
- (void)l2capChannelClosed:(IOBluetoothL2CAPChannel*)l2capChannel
{
- Q_UNUSED(l2capChannel)
+ Q_UNUSED(l2capChannel);
Q_ASSERT_X(delegate, Q_FUNC_INFO, "invalid delegate (null)");
delegate->channelClosed();
@@ -182,14 +146,14 @@ QT_USE_NAMESPACE
- (void)l2capChannelReconfigured:(IOBluetoothL2CAPChannel*)l2capChannel
{
- Q_UNUSED(l2capChannel)
+ Q_UNUSED(l2capChannel);
}
- (void)l2capChannelWriteComplete:(IOBluetoothL2CAPChannel*)l2capChannel
refcon:(void*)refcon status:(IOReturn)error
{
- Q_UNUSED(l2capChannel)
- Q_UNUSED(refcon)
+ Q_UNUSED(l2capChannel);
+ Q_UNUSED(refcon);
Q_ASSERT_X(delegate, Q_FUNC_INFO, "invalid delegate (null)");
@@ -201,7 +165,7 @@ QT_USE_NAMESPACE
- (void)l2capChannelQueueSpaceAvailable:(IOBluetoothL2CAPChannel*)l2capChannel
{
- Q_UNUSED(l2capChannel)
+ Q_UNUSED(l2capChannel);
}
// Aux. methods.
diff --git a/src/bluetooth/darwin/btl2capchannel_p.h b/src/bluetooth/darwin/btl2capchannel_p.h
index 32122fe8..68d24aba 100644
--- a/src/bluetooth/darwin/btl2capchannel_p.h
+++ b/src/bluetooth/darwin/btl2capchannel_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef BTL2CAPCHANNEL_P_H
#define BTL2CAPCHANNEL_P_H
@@ -51,7 +15,8 @@
// We mean it.
//
-#include <QtCore/qglobal.h>
+#include <QtCore/private/qcore_mac_p.h>
+#include <QtCore/private/qglobal_p.h>
#include <Foundation/Foundation.h>
@@ -115,4 +80,6 @@ QT_END_NAMESPACE
@end
+QT_NAMESPACE_ALIAS_OBJC_CLASS(DarwinBTL2CAPChannel);
+
#endif
diff --git a/src/bluetooth/darwin/btledeviceinquiry.mm b/src/bluetooth/darwin/btledeviceinquiry.mm
index 107ffc5b..2611aae0 100644
--- a/src/bluetooth/darwin/btledeviceinquiry.mm
+++ b/src/bluetooth/darwin/btledeviceinquiry.mm
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qbluetoothdeviceinfo.h"
#include "btledeviceinquiry_p.h"
@@ -46,6 +10,7 @@
#include <QtCore/qloggingcategory.h>
#include <QtCore/qdebug.h>
#include <QtCore/qendian.h>
+#include <QtCore/qlist.h>
#include <algorithm>
@@ -60,7 +25,7 @@ QBluetoothUuid qt_uuid(NSUUID *nsUuid)
uuid_t uuidData = {};
[nsUuid getUUIDBytes:uuidData];
- quint128 qtUuidData = {};
+ QUuid::Id128Bytes qtUuidData = {};
std::copy(uuidData, uuidData + 16, qtUuidData.data);
return QBluetoothUuid(qtUuidData);
}
@@ -81,8 +46,9 @@ struct AdvertisementData {
// For now, we "parse":
QString localName;
- QVector<QBluetoothUuid> serviceUuids;
+ QList<QBluetoothUuid> serviceUuids;
QHash<quint16, QByteArray> manufacturerData;
+ QHash<QBluetoothUuid, QByteArray> serviceData;
// TODO: other keys probably?
AdvertisementData(NSDictionary *AdvertisementData);
};
@@ -108,6 +74,13 @@ AdvertisementData::AdvertisementData(NSDictionary *advertisementData)
serviceUuids << qt_uuid(cbUuid);
}
+ NSDictionary *advdict = [advertisementData objectForKey:CBAdvertisementDataServiceDataKey];
+ if (advdict) {
+ [advdict enumerateKeysAndObjectsUsingBlock:^(CBUUID *key, NSData *val, BOOL *) {
+ serviceData.insert(qt_uuid(key), QByteArray::fromNSData(static_cast<NSData *>(val)));
+ }];
+ }
+
value = [advertisementData objectForKey:CBAdvertisementDataManufacturerDataKey];
if (value && [value isKindOfClass:[NSData class]]) {
QByteArray data = QByteArray::fromNSData(static_cast<NSData *>(value));
@@ -121,12 +94,12 @@ QT_END_NAMESPACE
QT_USE_NAMESPACE
-@interface QT_MANGLE_NAMESPACE(DarwinBTLEDeviceInquiry)(PrivateAPI)
+@interface DarwinBTLEDeviceInquiry (PrivateAPI)
- (void)stopScanSafe;
- (void)stopNotifier;
@end
-@implementation QT_MANGLE_NAMESPACE(DarwinBTLEDeviceInquiry)
+@implementation DarwinBTLEDeviceInquiry
{
LECBManagerNotifier *notifier;
ObjCScopedPointer<CBCentralManager> manager;
@@ -161,7 +134,7 @@ QT_USE_NAMESPACE
- (void)timeout:(id)sender
{
- Q_UNUSED(sender)
+ Q_UNUSED(sender);
if (internalState == InquiryActive) {
[self stopScanSafe];
@@ -211,13 +184,21 @@ QT_USE_NAMESPACE
if (inquiryTimeoutMS > 0) {
[elapsedTimer cancelTimer];
- elapsedTimer.reset([[GCDTimerObjC alloc] initWithDelegate:self], RetainPolicy::noInitialRetain);
+ elapsedTimer.reset([[DarwinBTGCDTimer alloc] initWithDelegate:self], RetainPolicy::noInitialRetain);
[elapsedTimer startWithTimeout:inquiryTimeoutMS step:timeStepMS];
}
- [manager scanForPeripheralsWithServices:nil options:nil];
+ // ### Qt 6.x: remove the use of env. variable, as soon as a proper public API is in place.
+ bool envOk = false;
+ const int env = qEnvironmentVariableIntValue("QT_BLUETOOTH_SCAN_ENABLE_DUPLICATES", &envOk);
+ if (envOk && env) {
+ [manager scanForPeripheralsWithServices:nil
+ options:@{CBCentralManagerScanOptionAllowDuplicatesKey : @YES}];
+ } else {
+ [manager scanForPeripheralsWithServices:nil options:nil];
+ }
} // Else we ignore.
- } else if (state == CBManagerStateUnsupported || state == CBManagerStateUnauthorized) {
+ } else if (state == CBManagerStateUnsupported) {
if (internalState == InquiryActive) {
[self stopScanSafe];
// Not sure how this is possible at all,
@@ -228,7 +209,12 @@ QT_USE_NAMESPACE
internalState = ErrorLENotSupported;
emit notifier->LEnotSupported();
}
-
+ [manager setDelegate:nil];
+ } else if (state == CBManagerStateUnauthorized) {
+ if (internalState == InquiryActive)
+ [self stopScanSafe];
+ internalState = ErrorNotAuthorized;
+ emit notifier->CBManagerError(QBluetoothDeviceDiscoveryAgent::MissingPermissionsError);
[manager setDelegate:nil];
} else if (state == CBManagerStatePoweredOff) {
@@ -239,12 +225,12 @@ QT_USE_NAMESPACE
// we'll receive 'PoweredOn' state update later.
// No change in internalState. Wait for 30 seconds.
[elapsedTimer cancelTimer];
- elapsedTimer.reset([[GCDTimerObjC alloc] initWithDelegate:self], RetainPolicy::noInitialRetain);
+ elapsedTimer.reset([[DarwinBTGCDTimer alloc] initWithDelegate:self], RetainPolicy::noInitialRetain);
[elapsedTimer startWithTimeout:powerOffTimeoutMS step:300];
return;
}
#else
- Q_UNUSED(powerOffTimeoutMS)
+ Q_UNUSED(powerOffTimeoutMS);
#endif // Q_OS_MACOS
[elapsedTimer cancelTimer];
[self stopScanSafe];
@@ -351,10 +337,14 @@ QT_USE_NAMESPACE
if (qtAdvData.serviceUuids.size())
newDeviceInfo.setServiceUuids(qtAdvData.serviceUuids);
- const QList<quint16> keys = qtAdvData.manufacturerData.keys();
- for (quint16 key : keys)
+ const QList<quint16> keysManufacturer = qtAdvData.manufacturerData.keys();
+ for (quint16 key : keysManufacturer)
newDeviceInfo.setManufacturerData(key, qtAdvData.manufacturerData.value(key));
+ const QList<QBluetoothUuid> keysService = qtAdvData.serviceData.keys();
+ for (QBluetoothUuid key : keysService)
+ newDeviceInfo.setServiceData(key, qtAdvData.serviceData.value(key));
+
// CoreBluetooth scans only for LE devices.
newDeviceInfo.setCoreConfigurations(QBluetoothDeviceInfo::LowEnergyCoreConfiguration);
emit notifier->deviceDiscovered(newDeviceInfo);
diff --git a/src/bluetooth/darwin/btledeviceinquiry_p.h b/src/bluetooth/darwin/btledeviceinquiry_p.h
index 58c66e56..edc393d8 100644
--- a/src/bluetooth/darwin/btledeviceinquiry_p.h
+++ b/src/bluetooth/darwin/btledeviceinquiry_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef BTLEDEVICEINQUIRY_P_H
#define BTLEDEVICEINQUIRY_P_H
@@ -56,8 +20,9 @@
#include "btgcdtimer_p.h"
#include "btutility_p.h"
+#include <QtCore/private/qcore_mac_p.h>
+
#include <QtCore/qglobal.h>
-#include <QtCore/qlist.h>
#include <Foundation/Foundation.h>
@@ -86,7 +51,8 @@ enum LEInquiryState
InquiryFinished,
InquiryCancelled,
ErrorPoweredOff,
- ErrorLENotSupported
+ ErrorLENotSupported,
+ ErrorNotAuthorized
};
@interface QT_MANGLE_NAMESPACE(DarwinBTLEDeviceInquiry) : NSObject<CBCentralManagerDelegate, QT_MANGLE_NAMESPACE(GCDTimerDelegate)>
@@ -100,4 +66,6 @@ enum LEInquiryState
@end
+QT_NAMESPACE_ALIAS_OBJC_CLASS(DarwinBTLEDeviceInquiry);
+
#endif
diff --git a/src/bluetooth/darwin/btnotifier.cpp b/src/bluetooth/darwin/btnotifier.cpp
index 24f54a09..6ab7e473 100644
--- a/src/bluetooth/darwin/btnotifier.cpp
+++ b/src/bluetooth/darwin/btnotifier.cpp
@@ -1 +1,4 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
#include "btnotifier_p.h"
diff --git a/src/bluetooth/darwin/btnotifier_p.h b/src/bluetooth/darwin/btnotifier_p.h
index e074a225..64a285e2 100644
--- a/src/bluetooth/darwin/btnotifier_p.h
+++ b/src/bluetooth/darwin/btnotifier_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef BTNOTIFIER_P_H
#define BTNOTIFIER_P_H
@@ -51,7 +15,6 @@
// We mean it.
//
-
#include "qbluetoothdevicediscoveryagent.h"
#include "qlowenergycontroller.h"
#include "qbluetoothdeviceinfo.h"
@@ -60,7 +23,7 @@
#include <QtCore/qsharedpointer.h>
#include <QtCore/qbytearray.h>
-#include <QtCore/qglobal.h>
+#include <QtCore/private/qglobal_p.h>
#include <QtCore/qobject.h>
QT_BEGIN_NAMESPACE
@@ -81,6 +44,8 @@ Q_SIGNALS:
void connected();
void disconnected();
+ void mtuChanged(int newValue);
+
void serviceDiscoveryFinished();
void serviceDetailsDiscoveryFinished(QSharedPointer<QLowEnergyServicePrivate> service);
void characteristicRead(QLowEnergyHandle charHandle, const QByteArray &value);
@@ -90,6 +55,7 @@ Q_SIGNALS:
void descriptorWritten(QLowEnergyHandle descHandle, const QByteArray &value);
void notificationEnabled(QLowEnergyHandle charHandle, bool enabled);
void servicesWereModified();
+ void rssiUpdated(qint16 newValue);
void LEnotSupported();
void CBManagerError(QBluetoothDeviceDiscoveryAgent::Error error);
diff --git a/src/bluetooth/darwin/btobexsession.mm b/src/bluetooth/darwin/btobexsession.mm
deleted file mode 100644
index ecf010ba..00000000
--- a/src/bluetooth/darwin/btobexsession.mm
+++ /dev/null
@@ -1,843 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qbluetoothaddress.h"
-#include "btobexsession_p.h"
-#include "btutility_p.h"
-
-#include <QtCore/qloggingcategory.h>
-#include <QtCore/qvector.h>
-#include <QtCore/qdebug.h>
-#include <QtCore/qlist.h>
-
-#include <algorithm>
-#include <cstddef>
-#include <limits>
-
-QT_BEGIN_NAMESPACE
-
-namespace DarwinBluetooth
-{
-
-OBEXSessionDelegate::~OBEXSessionDelegate()
-{
-}
-
-namespace {
-
-using NSDataPtr = NSMutableData *;
-
-struct OBEXHeader
-{
- OBEXHeader() : headerID(0)
- {
- }
-
- quint8 headerID;
- QVariant value;
-};
-
-enum {
- // Bits 7 and 8 == header's format.
- OBEXHeaderFormatMask = 0xc0,
- //
- OBEXHeaderFormatUnicode = 0, // 87
- OBEXHeaderFormatByteSequence = 0x40, // 0100 0000
- OBEXHeaderFormat1Byte = 0x80, // 1000 0000
- OBEXHeaderFormat4Byte = 0xc0, // 1100 0000
-
-};
-
-quint32 extract_uint32(const uint8_t *bytes)
-{
- // Four byte value, high byte first.
- Q_ASSERT_X(bytes, Q_FUNC_INFO, "invalid input data (null)");
-
- uint32_t value = uint32_t();
- std::copy(bytes, bytes + sizeof value, reinterpret_cast<uint8_t *>(&value));
-
- return NSSwapBigIntToHost(value);
-}
-
-quint16 extract_uint16(const uint8_t *bytes)
-{
- // Two byte value, high byte first.
- Q_ASSERT_X(bytes, Q_FUNC_INFO, "invalid input data (null)");
-
- uint16_t value = uint16_t();
- std::copy(bytes, bytes + sizeof value, reinterpret_cast<uint8_t *>(&value));
-
- return NSSwapBigShortToHost(value);
-}
-
-QString extract_qstring(const uint8_t *bytes, quint16 stringLength)
-{
- if (bytes && stringLength) {
- NSString * const nsString = [[NSString alloc] initWithBytes:bytes
- length:stringLength
- encoding:NSUnicodeStringEncoding];
- if (nsString)
- return QString::fromNSString(nsString);
- }
-
- // Empty string is an error, "valid" empty strings are
- // handled separately.
- return QString();
-}
-
-QList<OBEXHeader> qt_bluetooth_headers(const uint8_t *data, std::size_t length)
-{
- // Convert a data from IOBluetooth into something, Qt understands.
- // Possible formats (bits 7 and 8):
- // 1. 00 Two bytes of length folowed by a null-terminated
- // Unicode text string (length is unsigned integer;
- // it covers the header ID and the whole of the header
- // value, including the length bytes and the two bytes
- // of null terminator.
- // 2. 01 Two bytes of length followed by a byte sequence (length
- // is an unsigned integer sent high byte first; it covers
- // the header ID and the whole of the header value).
- // 3. 10 A single byte value.
- // 4. 11 A four byte value, sent high byte first.
-
- Q_ASSERT_X(data, Q_FUNC_INFO, "invalid data (null)");
- Q_ASSERT_X(length >= 2, Q_FUNC_INFO, "invalid data length");
-
- Q_UNUSED(data)
- Q_UNUSED(length)
-
- QList<OBEXHeader> empty;
- QList<OBEXHeader> qtHeaders;
-
- for (std::size_t i = 0; i < length;) {
- std::size_t headerLength = 0;
- OBEXHeader header;
- header.headerID = data[i];
-
- switch (data[i] & OBEXHeaderFormatMask) {
- case OBEXHeaderFormatUnicode:
- {
- if (i + 3 > length)
- return empty;
- headerLength = extract_uint16(data + i + 1);
- // Invalid length or input data:
- if (headerLength < 3 || i + headerLength > length)
- return empty;
- if (headerLength == 3 || headerLength == 5) { // Can 5 ever happen?
- header.value.fromValue<QString>(QString());
- } else if (headerLength > 5) {// TODO: We do not check now, that the string actually valid.
- const QString value(extract_qstring(data + i + 3, headerLength - 5));
- if (!value.length()) // Some error?
- return empty;
- header.value.setValue<QString>(value);
- } else // Still something weird.
- return empty;
- break;
- }
- case OBEXHeaderFormatByteSequence:
- {
- if (i + 3 > length)
- return empty;
- headerLength = extract_uint16(data + i + 1);
- // Something is wrong:
- if (headerLength < 3 || i + headerLength > length)
- return empty;
- QVector<unsigned char> value;
- if (headerLength > 3) {
- value.resize(headerLength - 3);
- std::copy(data, data + headerLength, value.begin());
- }
- header.value.setValue<QVector<unsigned char> >(value);
- break;
- }
- case OBEXHeaderFormat1Byte:
- {
- // 1 byte integer + 1 byte headerID == 2
- if (i + 2 > length)
- return empty;
- headerLength = 2;
- header.value.setValue<quint8>(data[i + 1]);
- break;
- }
- case OBEXHeaderFormat4Byte:
- {
- // 4 byte integer + 1 byte headerID == 5
- if (i + 5 > length)
- return empty;
- headerLength = 5;
- header.value.setValue<quint32>(extract_uint32(data + i + 1));
- break;
- }
- default:
- qCWarning(QT_BT_DARWIN) << "invalid header format";
- return empty;
- }
-
- i += headerLength;
- qtHeaders.push_back(header);
- }
-
- return qtHeaders;
-}
-
-bool append_uint16(ObjCStrongReference<NSMutableData> headers, uint16_t value)
-{
- if (!headers)
- return false;
-
- const NSUInteger length = [headers length];
- const uint16_t valueSwapped = NSSwapHostShortToBig(value);
- [headers appendBytes:&valueSwapped length:sizeof valueSwapped];
-
- return [headers length] - length == 2;
-}
-
-
-bool append_four_byte_header(ObjCStrongReference<NSMutableData> headers, uint8_t headerID,
- uint32_t headerValue)
-{
- if (!headers)
- return false;
-
- const NSUInteger length = [headers length];
- // Header ID (1 byte)
- [headers appendBytes:&headerID length:1];
- // Header value (4 bytes)
- const uint32_t valueSwapped(NSSwapHostIntToBig(headerValue));
- [headers appendBytes:&valueSwapped length:sizeof valueSwapped];
-
- return [headers length] - length == 5;
-}
-
-bool append_unicode_header(ObjCStrongReference<NSMutableData> headers, uint8_t headerID,
- const QString &string)
-{
- // Two bytes of length followed by a null-terminated
- // Unicode text string. Length is unsigned integer,
- // it covers the header ID and the whole of the header
- // value, including the length bytes and the two bytes
- // of null terminator.
- // All Obj-C objects are autoreleased.
-
- if (!headers)
- return false;
-
- QT_BT_MAC_AUTORELEASEPOOL;
-
- const NSUInteger initialLength = [headers length];
- [headers appendBytes:&headerID length:1];
-
- if (!string.length()) {
- // Empty string. The length is 3
- // (header ID + length value itself).
- return append_uint16(headers, 3);
- }
-
- NSString *const nsString = string.toNSString();
- if (!nsString)
- return false;
-
- // TODO: check if the encodings is right. It was NSUnicodeStringEncoding but
- // byte order was wrong. Also, I do not need BOM check anymore?
- NSData *const data = [nsString dataUsingEncoding:NSUTF16BigEndianStringEncoding];
- if (!data)
- return false;
-
- // This data can include byte-order marker (BOM) and does not include
- // a null terminator. Anyway, the length must be >= 2.
- NSUInteger length = [data length];
- if (length < 2)
- return false;
-
- const uint8_t *dataPtr = static_cast<const uint8_t *>([data bytes]);
- if ((dataPtr[0] == 0xff && dataPtr[1] == 0xfe)
- || (dataPtr[0] == 0xfe && dataPtr[1] == 0xff)) {
- if (length == 2) //Something weird?
- return false;
- // Skip a BOM.
- dataPtr += 2;
- length -= 2;
- }
-
- // headerID + length == 3, string's length + 2
- // bytes for a null terminator.
- if (!append_uint16(headers, length + 3 + 2))
- return false;
-
- [headers appendBytes:dataPtr length:length];
- const uint8_t nullTerminator[2] = {};
- [headers appendBytes:nullTerminator length:2];
-
- return [headers length] - initialLength == length + 3 + 2;
-}
-
-ObjCStrongReference<NSMutableData> next_data_chunk(QIODevice &inputStream, IOBluetoothOBEXSession *session,
- NSUInteger headersLength, bool &isLast)
-{
- // Work only for OBEX put (we request a specific payload length).
- Q_ASSERT_X(session, Q_FUNC_INFO, "invalid OBEX session (nil)");
-
- const OBEXMaxPacketLength packetSize = [session getAvailableCommandPayloadLength:kOBEXOpCodePut];
- if (!packetSize || headersLength >= packetSize)
- return ObjCStrongReference<NSMutableData>();
-
- const OBEXMaxPacketLength maxBodySize = packetSize - headersLength;
-
- QVector<char> block(maxBodySize);
- const int realSize = inputStream.read(block.data(), block.size());
- if (realSize <= 0) {
- // Well, either the last or an error.
- isLast = true;
- return ObjCStrongReference<NSMutableData>();
- }
-
- ObjCStrongReference<NSMutableData> chunk([NSMutableData dataWithBytes:block.data()
- length:realSize], RetainPolicy::doInitialRetain);
- if (chunk && [chunk length]) {
- // If it actually was the last chunk
- // of a length == maxBodySize, we'll
- // send one more packet (empty though)?
- isLast = [chunk length] < maxBodySize;
- }
-
- return chunk;
-}
-
-bool check_connect_event(const OBEXSessionEvent *e, OBEXError &error, OBEXOpCode &response)
-{
- Q_ASSERT_X(e, Q_FUNC_INFO, "invalid event (null)");
-
- // This function tries to extract either an error code or a
- // server response code. "Good" event has type connect command respond
- // and reponse code 0XA0. Everything else is a "bad" event and
- // means connect failed.
-
- // If it's an error event - return the error.
- // If it's connect response - extract the response code.
- // If it's something else (is it possible?) - set general error.
-
- if (e->type == kOBEXSessionEventTypeError) {
- error = e->u.errorData.error;
- return false;
- } if (e->type == kOBEXSessionEventTypeConnectCommandResponseReceived) {
- // We can read response code only for such an event.
- response = e->u.connectCommandResponseData.serverResponseOpCode;
- return response == kOBEXResponseCodeSuccessWithFinalBit;
- } else {
- qCWarning(QT_BT_DARWIN) << "unexpected event type";
- error = kOBEXGeneralError;
- return false;
- }
-}
-
-bool check_put_event(const OBEXSessionEvent *e, OBEXError &error, OBEXOpCode &response)
-{
- Q_ASSERT_X(e, Q_FUNC_INFO, "invalid event (null)");
-
- // See the comments above.
-
- if (e->type == kOBEXSessionEventTypeError) {
- error = e->u.errorData.error;
- return false;
- } else if (e->type == kOBEXSessionEventTypePutCommandResponseReceived) {
- response = e->u.putCommandResponseData.serverResponseOpCode;
- return response == kOBEXResponseCodeContinueWithFinalBit ||
- response == kOBEXResponseCodeSuccessWithFinalBit;
- } else {
- qCWarning(QT_BT_DARWIN) << "unexpected event type";
- error = kOBEXGeneralError;
- return false;
- }
-}
-
-bool check_abort_event(const OBEXSessionEvent *e, OBEXError &error, OBEXOpCode &response)
-{
- Q_ASSERT_X(e, Q_FUNC_INFO, "invalid event (null)");
-
- if (e->type == kOBEXSessionEventTypeError) {
- error = e->u.errorData.error;
- return false;
- } else if (e->type == kOBEXSessionEventTypeAbortCommandResponseReceived) {
- response = e->u.abortCommandResponseData.serverResponseOpCode;
- return response == kOBEXResponseCodeSuccessWithFinalBit;
- } else {
- qCWarning(QT_BT_DARWIN) << "unexpected event type";
- return false;
- }
-}
-
-} // Unnamed namespace.
-} // namespace DarwinBluetooth.
-
-QT_END_NAMESPACE
-
-QT_USE_NAMESPACE
-
-@interface QT_MANGLE_NAMESPACE(DarwinBTOBEXSession) (PrivateAPI)
-
-// OBEXDisconnect returns void - it's considered to be always
-// successful. These methods are "private API" - no need to expose them,
-// for internal use only.
-- (void)OBEXDisconnect;
-- (void)OBEXDisconnectHandler:(const OBEXSessionEvent*)event;
-
-@end
-
-@implementation QT_MANGLE_NAMESPACE(DarwinBTOBEXSession)
-{
- QT_PREPEND_NAMESPACE(DarwinBluetooth)::OBEXSessionDelegate *delegate;
- IOBluetoothDevice *device;
- quint16 channelID;
- IOBluetoothOBEXSession *session;
-
- QT_PREPEND_NAMESPACE(DarwinBluetooth)::OBEXRequest currentRequest;
-
- bool connected;
- bool connectionIDFound;
- quint32 connectionID;
-
- QT_PREPEND_NAMESPACE(QIODevice) *inputStream;
-
- // TODO: switch to scoped pointers or strong reference objects instead.
- NSMutableData *headersData;
- NSMutableData *bodyData;
-
- quint32 bytesSent;
- bool pendingAbort;
-}
-
-+ (OBEXMaxPacketLength) maxPacketLength
-{
- // Some arbitrary number, we'll adjust it as soon as
- // we connected, asking a session about packet size for
- // a particular command.
- return 0x1000;
-}
-
-- (id)initWithDelegate:(QT_PREPEND_NAMESPACE(DarwinBluetooth::OBEXSessionDelegate) *)aDelegate
- remoteDevice:(const QBluetoothAddress &)deviceAddress channelID:(quint16)port
-{
- Q_ASSERT_X(aDelegate, Q_FUNC_INFO, "invalid delegate (null)");
- Q_ASSERT_X(!deviceAddress.isNull(), Q_FUNC_INFO, "invalid remote device address");
- Q_ASSERT_X(port, Q_FUNC_INFO, "invalid port (0)");
-
- if (self = [super init]) {
- connected = false;
- currentRequest = DarwinBluetooth::OBEXNoop;
- connectionID = 0;
- connectionIDFound = false;
-
- const BluetoothDeviceAddress addr(DarwinBluetooth::iobluetooth_address(deviceAddress));
- device = [[IOBluetoothDevice deviceWithAddress:&addr] retain];
- if (!device) {
- qCWarning(QT_BT_DARWIN) << "failed to create an IOBluetoothDevice";
- return self;
- }
-
- session = [[IOBluetoothOBEXSession alloc] initWithDevice:device channelID:port];
- if (!session) {
- qCWarning(QT_BT_DARWIN) << "failed to create an OBEX session";
- return self;
- }
-
- delegate = aDelegate;
- channelID = port;
- }
-
- return self;
-}
-
-- (void)dealloc
-{
- [device release];
- [session release];
-
- [headersData release];
- [bodyData release];
-
- [super dealloc];
-}
-
-- (OBEXError)OBEXConnect
-{
- if (!session) {
- qCWarning(QT_BT_DARWIN) << "invalid session (nil)";
- return kOBEXGeneralError;
- }
-
- // That's a "single-shot" operation:
- Q_ASSERT_X(currentRequest == DarwinBluetooth::OBEXNoop, Q_FUNC_INFO,
- "can not connect in this state (another request is active)");
-
- connected = false;
- connectionIDFound = false;
- connectionID = 0;
- currentRequest = DarwinBluetooth::OBEXConnect;
-
- const OBEXError status = [session OBEXConnect:kOBEXConnectFlagNone
- maxPacketLength:[QT_MANGLE_NAMESPACE(DarwinBTOBEXSession) maxPacketLength]
- optionalHeaders:nullptr
- optionalHeadersLength:0
- eventSelector:@selector(OBEXConnectHandler:)
- selectorTarget:self
- refCon:nullptr];
-
- if (status != kOBEXSuccess) {
- currentRequest = DarwinBluetooth::OBEXNoop;
- // Already connected is still ok for us?
- connected = status == kOBEXSessionAlreadyConnectedError;
- }
-
- return status;
-}
-
-- (void)OBEXConnectHandler:(const OBEXSessionEvent*)event
-{
- using namespace DarwinBluetooth;
-
- Q_ASSERT_X(session, Q_FUNC_INFO, "invalid session (nil)");
-
- if (pendingAbort) {
- currentRequest = OBEXNoop;
- [self OBEXAbort];
- return;
- }
-
- if (currentRequest != OBEXConnect) {
- qCWarning(QT_BT_DARWIN) << "called while there is no "
- "active connect request";
- return;
- }
-
- currentRequest = OBEXNoop;
-
- OBEXError errorCode = kOBEXSuccess;
- OBEXOpCode responseCode = kOBEXResponseCodeSuccessWithFinalBit;
-
- if (!check_connect_event(event, errorCode, responseCode)) {
- // OBEX connect failed.
- if (delegate)
- delegate->OBEXConnectError(errorCode, responseCode);
- return;
- }
-
- const OBEXConnectCommandResponseData *const response = &event->u.connectCommandResponseData;
- if (response->headerDataPtr && response->headerDataLength >= 2) {
- // 2 == 1 byte headerID + at least 1 byte headerValue ...
- const QList<OBEXHeader> headers(qt_bluetooth_headers(static_cast<const uint8_t *>(response->headerDataPtr),
- response->headerDataLength));
- // ConnectionID is used when multiplexing OBEX connections
- // to identify which particular connection this object is
- // being sent on. When used, this _must_ be the first
- // header sent.
-
- for (const OBEXHeader &header : headers) {
- if (header.headerID == kOBEXHeaderIDConnectionID) {
- connectionID = header.value.value<quint32>();
- connectionIDFound = true;
- break;
- }
- }
- }
-
- connected = true;
-
- if (delegate)
- delegate->OBEXConnectSuccess();
-}
-
-- (OBEXError)OBEXAbort
-{
- using namespace DarwinBluetooth;
-
- Q_ASSERT_X(session, Q_FUNC_INFO, "invalid OBEX session (nil)");
-
- if (currentRequest == OBEXNoop) {
- pendingAbort = false;
-
- if (![self isConnected])
- return kOBEXSessionNotConnectedError;
-
- currentRequest = OBEXAbort;
- const OBEXError status = [session OBEXAbort:nullptr
- optionalHeadersLength:0
- eventSelector:@selector(OBEXAbortHandler:)
- selectorTarget:self
- refCon:nullptr];
- if (status != kOBEXSuccess)
- currentRequest = OBEXNoop;
-
- return status;
- } else {
- // We're in the middle of some request, wait
- // for any handler to be called first.
- pendingAbort = true;
- return kOBEXSuccess;
- }
-}
-
-- (void)OBEXAbortHandler:(const OBEXSessionEvent*)event
-{
- using namespace DarwinBluetooth;
-
- Q_ASSERT_X(session, Q_FUNC_INFO, "invalid OBEX session (nil)");
-
- if (currentRequest != OBEXAbort) {
- qCWarning(QT_BT_DARWIN) << "called while there "
- "is no ABORT request";
- return;
- }
-
- pendingAbort = false;
- currentRequest = OBEXNoop;
-
- if (delegate) {
- OBEXError error = kOBEXSuccess;
- OBEXOpCode response = kOBEXResponseCodeSuccessWithFinalBit;
- if (check_abort_event(event, error, response))
- delegate->OBEXAbortSuccess();
- }
-}
-
-- (OBEXError)OBEXPutFile:(QT_PREPEND_NAMESPACE(QIODevice) *)input withName:(const QString &)name
-{
- using namespace DarwinBluetooth;
-
- if (!session || ![self isConnected])
- return kOBEXSessionNotConnectedError;
-
- Q_ASSERT_X(currentRequest == OBEXNoop, Q_FUNC_INFO,
- "the current session has an active request already");
- Q_ASSERT_X(input, Q_FUNC_INFO, "invalid input stream (null)");
- Q_ASSERT_X(input->isReadable(), Q_FUNC_INFO, "invalid input stream (not readable)");
-
- // We send a put request with a couple of headers (size/file name/may be connection ID) +
- // a payload.
- const qint64 fileSize = input->size();
- if (fileSize <= 0 || fileSize >= std::numeric_limits<uint32_t>::max()) {
- qCWarning(QT_BT_DARWIN) << "invalid input file size";
- return kOBEXBadArgumentError;
- }
-
- ObjCStrongReference<NSMutableData> headers([[NSMutableData alloc] init], RetainPolicy::noInitialRetain);
- if (!headers) {
- qCWarning(QT_BT_DARWIN) << "failed to allocate headers";
- return kOBEXNoResourcesError;
- }
-
- // Now we append headers with: Connection ID (if any),
- // file name, file size, the first (and probably the only) chunk of data
- // from the input stream and send a put request.
-
- if (connectionIDFound) {
- if (!append_four_byte_header(headers, kOBEXHeaderIDConnectionID, connectionID)) {
- qCWarning(QT_BT_DARWIN) << "failed to append connection ID header";
- return kOBEXNoResourcesError;
- }
- }
-
- if (name.length()) {
- if (!append_unicode_header(headers, kOBEXHeaderIDName, name)) {
- qCWarning(QT_BT_DARWIN) << "failed to append a unicode string";
- return kOBEXNoResourcesError;
- }
- }
-
- if (fileSize && !input->isSequential())
- append_four_byte_header(headers, kOBEXHeaderIDLength, uint32_t(fileSize));
-
- bool lastChunk = false;
- ObjCStrongReference<NSMutableData> chunk(next_data_chunk(*input, session, [headers length], lastChunk));
- if (!chunk || ![chunk length]) {
- // We do not support PUT-DELETE (?)
- // At least the first chunk is expected to be non-empty.
- qCWarning(QT_BT_DARWIN) << "invalid input stream";
- return kOBEXBadArgumentError;
- }
-
- currentRequest = OBEXPut;
-
- const OBEXError status = [session OBEXPut:lastChunk
- headersData:[headers mutableBytes]
- headersDataLength:[headers length]
- bodyData:[chunk mutableBytes]
- bodyDataLength:[chunk length]
- eventSelector:@selector(OBEXPutHandler:)
- selectorTarget:self
- refCon:nullptr];
-
- if (status == kOBEXSuccess) {
- if (delegate && fileSize && !input->isSequential())
- delegate->OBEXPutDataSent([chunk length], fileSize);
-
- bytesSent = [chunk length];
- headersData = NSDataPtr(headers.release());
- bodyData = NSDataPtr(chunk.release());
- inputStream = input;
- } else {
- // PUT request failed and we now
- // want to close a connection/session.
- currentRequest = OBEXNoop;
- // Try to cleanup (disconnect).
- [self OBEXDisconnect];
- }
-
- return status;
-}
-
-- (void)OBEXPutHandler:(const OBEXSessionEvent*)event
-{
- using namespace DarwinBluetooth;
-
- Q_ASSERT_X(session, Q_FUNC_INFO, "invalid OBEX session (nil)");
-
- if (pendingAbort) {
- currentRequest = OBEXNoop;
- [self OBEXAbort];
- return;
- }
-
- if (currentRequest != OBEXPut) {
- qCWarning(QT_BT_DARWIN) << "called while the current "
- "request is not a put request";
- return;
- }
-
- OBEXError error = kOBEXSuccess;
- OBEXOpCode responseCode = kOBEXResponseCodeSuccessWithFinalBit;
- if (!check_put_event(event, error, responseCode)) {
- currentRequest = OBEXNoop;
- if (delegate)
- delegate->OBEXPutError(error, responseCode);
- [self OBEXDisconnect];
- return;
- }
-
- // Now try to send more data if we have any.
- if (responseCode == kOBEXResponseCodeContinueWithFinalBit) {
- // Send more data.
- bool lastChunk = false;
- // 0 for the headers length, no more headers.
- ObjCStrongReference<NSMutableData> chunk(next_data_chunk(*inputStream, session, 0, lastChunk));
- if (!chunk && !lastChunk) {
- qCWarning(QT_BT_DARWIN) << "failed to allocate the next memory chunk";
- return;
- }
-
- void *dataPtr = chunk ? [chunk mutableBytes] : nullptr;
- const NSUInteger dataSize = chunk ? [chunk length] : 0;
- const OBEXError status = [session OBEXPut:lastChunk
- headersData:nullptr
- headersDataLength:0
- bodyData:dataPtr
- bodyDataLength:dataSize
- eventSelector:@selector(OBEXPutHandler:)
- selectorTarget:self
- refCon:nullptr];
-
- if (status != kOBEXSuccess) {
- qCWarning(QT_BT_DARWIN) << "failed to send the next memory chunk";
- currentRequest = OBEXNoop;
- if (delegate) // Response code is not important here.
- delegate->OBEXPutError(kOBEXNoResourcesError, 0);
-
- [self OBEXDisconnect];
- } else {
- [bodyData release];
- bytesSent += [chunk length];
- bodyData = NSDataPtr(chunk.release());
-
- if (delegate && !inputStream->isSequential())
- delegate->OBEXPutDataSent(bytesSent, inputStream->size());
- }
- } else if (responseCode == kOBEXResponseCodeSuccessWithFinalBit) {
- currentRequest = OBEXNoop;
- if (delegate)
- delegate->OBEXPutSuccess();
-
- [self OBEXDisconnect];
- }
-}
-
-- (void)OBEXDisconnect
-{
- Q_ASSERT_X(session, Q_FUNC_INFO, "invalid session (nil)");
-
- currentRequest = DarwinBluetooth::OBEXDisconnect;
-
- [session OBEXDisconnect:nullptr
- optionalHeadersLength:0
- eventSelector:@selector(OBEXDisconnectHandler:)
- selectorTarget:self
- refCon:nullptr];
-}
-
-- (void)OBEXDisconnectHandler:(const OBEXSessionEvent*)event
-{
- Q_UNUSED(event)
-
- Q_ASSERT_X(session, Q_FUNC_INFO, "invalid session (nil)");
-
- // Event can have an error type, but there's nothing
- // we can do - even "cleanup" failed.
- connected = false;
-}
-
-- (bool)isConnected
-{
- return device && session && connected;
-}
-
-- (void)closeSession
-{
- // Clear the delegate and reset the request,
- // do not try any of OBEX commands - the session will be deleted
- // immediately.
- delegate = nullptr;
- // This will stop any handler (callback) preventing
- // any read/write to potentially deleted objects.
- currentRequest = DarwinBluetooth::OBEXNoop;
-}
-
-- (bool)hasActiveRequest
-{
- return currentRequest != DarwinBluetooth::OBEXNoop && !pendingAbort;
-}
-
-@end
diff --git a/src/bluetooth/darwin/btobexsession_p.h b/src/bluetooth/darwin/btobexsession_p.h
deleted file mode 100644
index 11c6d226..00000000
--- a/src/bluetooth/darwin/btobexsession_p.h
+++ /dev/null
@@ -1,138 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef BTOBEXSESSION_P_H
-#define BTOBEXSESSION_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <QtCore/qvariant.h>
-#include <QtCore/qglobal.h>
-
-#include <Foundation/Foundation.h>
-
-#include <IOBluetooth/IOBluetooth.h>
-
-// TODO: all this code must be removed in Qt 6?
-
-@class QT_MANGLE_NAMESPACE(DarwinBTOBEXSession);
-
-QT_BEGIN_NAMESPACE
-
-class QBluetoothAddress;
-class QIODevice;
-class QString;
-
-namespace DarwinBluetooth
-{
-
-class OBEXSessionDelegate
-{
-public:
- typedef QT_MANGLE_NAMESPACE(DarwinBTOBEXSession) ObjCOBEXSession;
-
- virtual ~OBEXSessionDelegate();
-
- virtual void OBEXConnectError(OBEXError error, OBEXOpCode responseCode) = 0;
- virtual void OBEXConnectSuccess() = 0;
-
- virtual void OBEXAbortSuccess() = 0;
-
- virtual void OBEXPutDataSent(quint32 current, quint32 total) = 0;
- virtual void OBEXPutSuccess() = 0;
- virtual void OBEXPutError(OBEXError error, OBEXOpCode responseCode) = 0;
-};
-
-enum OBEXRequest {
- OBEXNoop,
- OBEXConnect,
- OBEXDisconnect,
- OBEXPut,
- OBEXGet,
- OBEXSetPath,
- OBEXAbort
-};
-
-} // namespace DarwinBluetooth
-
-QT_END_NAMESPACE
-
-// OBEX Session, it's a "single-shot" operation as our QBluetoothTransferReply is
-// (it does not have an interface to re-send data or re-use the same transfer reply).
-// It either succeeds or fails and tries to cleanup in any case.
-@interface QT_MANGLE_NAMESPACE(DarwinBTOBEXSession) : NSObject
-
-- (id)initWithDelegate:(QT_PREPEND_NAMESPACE(DarwinBluetooth::OBEXSessionDelegate) *)aDelegate
- remoteDevice:(const QBluetoothAddress &)deviceAddress channelID:(quint16)port;
-
-- (void)dealloc;
-
-// Below I have pairs: OBEX operation and its callback method.
-- (OBEXError)OBEXConnect;
-- (void)OBEXConnectHandler:(const OBEXSessionEvent*)event;
-
-- (OBEXError)OBEXAbort;
-- (void)OBEXAbortHandler:(const OBEXSessionEvent*)event;
-
-- (OBEXError)OBEXPutFile:(QT_PREPEND_NAMESPACE(QIODevice) *)inputStream withName:(const QString &)name;
-- (void)OBEXPutHandler:(const OBEXSessionEvent*)event;
-
-// Aux. methods.
-- (bool)isConnected;
-
-// To be called from C++ destructors. OBEXSession is not
-// valid anymore after this call (no more OBEX operations
-// can be executed). It's an ABORT/DISCONNECT sequence.
-// It also resets a delegate to null.
-- (void)closeSession;
-//
-- (bool)hasActiveRequest;
-
-@end
-
-#endif
diff --git a/src/bluetooth/darwin/btperipheralmanager.mm b/src/bluetooth/darwin/btperipheralmanager.mm
index 3336d8c5..78a328cc 100644
--- a/src/bluetooth/darwin/btperipheralmanager.mm
+++ b/src/bluetooth/darwin/btperipheralmanager.mm
@@ -1,44 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+#include "qlowenergyadvertisingparameters.h"
#include "qlowenergycharacteristicdata.h"
#include "qlowenergydescriptordata.h"
#include "btperipheralmanager_p.h"
@@ -46,11 +9,15 @@
#include "btnotifier_p.h"
#include "qbluetooth.h"
+#include <QtCore/qstring.h>
#include <QtCore/qdebug.h>
#include <QtCore/qlist.h>
#include <algorithm>
+#include <vector>
#include <limits>
+#include <deque>
+#include <map>
namespace
{
@@ -76,10 +43,10 @@ CBAttributePermissions cb_permissions(const QLowEnergyCharacteristicData &data)
if (props & QLEC::Read)
cbFlags = CBAttributePermissions(cbFlags | CBAttributePermissionsReadable);
- if (data.writeConstraints() & QBluetooth::AttEncryptionRequired)
+ if (data.writeConstraints() & QBluetooth::AttAccessConstraint::AttEncryptionRequired)
cbFlags = CBAttributePermissions(cbFlags | CBAttributePermissionsWriteEncryptionRequired);
- if (data.readConstraints() & QBluetooth::AttEncryptionRequired)
+ if (data.readConstraints() & QBluetooth::AttAccessConstraint::AttEncryptionRequired)
cbFlags = CBAttributePermissions(cbFlags | CBAttributePermissionsReadEncryptionRequired);
return cbFlags;
@@ -105,8 +72,8 @@ ObjCStrongReference<CBMutableDescriptor> create_descriptor(const QLowEnergyDescr
CBUUIDCharacteristicUserDescriptionString and CBUUIDCharacteristicFormatString"
*/
- if (data.uuid() != QBluetoothUuid::CharacteristicUserDescription &&
- data.uuid() != QBluetoothUuid::CharacteristicPresentationFormat) {
+ if (data.uuid() != QBluetoothUuid::DescriptorType::CharacteristicUserDescription &&
+ data.uuid() != QBluetoothUuid::DescriptorType::CharacteristicPresentationFormat) {
qCWarning(QT_BT_DARWIN) << "unsupported descriptor" << data.uuid();
return {};
}
@@ -116,7 +83,7 @@ ObjCStrongReference<CBMutableDescriptor> create_descriptor(const QLowEnergyDescr
// Descriptors are immutable with CoreBluetooth, that's why we
// have to provide a value here and not able to change it later.
ObjCStrongReference<NSObject> value;
- if (data.uuid() == QBluetoothUuid::CharacteristicUserDescription) {
+ if (data.uuid() == QBluetoothUuid::DescriptorType::CharacteristicUserDescription) {
const QString asQString(QString::fromUtf8(data.value()));
value.reset(asQString.toNSString(), RetainPolicy::doInitialRetain); // toNSString is auto-released, we have to retain.
} else {
@@ -134,14 +101,14 @@ quint32 qt_countGATTEntries(const QLowEnergyServiceData &data)
{
const auto maxu32 = std::numeric_limits<quint32>::max();
// + 1 for a service itself.
- quint32 nEntries = 1 + quint32(data.includedServices().count());
+ quint32 nEntries = 1 + quint32(data.includedServices().size());
for (const auto &ch : data.characteristics()) {
if (maxu32 - 2 < nEntries)
return {};
nEntries += 2;
- if (maxu32 - ch.descriptors().count() < nEntries)
+ if (maxu32 - ch.descriptors().size() < nEntries)
return {};
- nEntries += ch.descriptors().count();
+ nEntries += ch.descriptors().size();
}
return nEntries;
@@ -159,10 +126,9 @@ bool qt_validate_value_range(const QLowEnergyCharacteristicData &data)
}
-@interface QT_MANGLE_NAMESPACE(DarwinBTPeripheralManager) (PrivateAPI)
+@interface DarwinBTPeripheralManager (PrivateAPI)
- (void)addConnectedCentral:(CBCentral *)central;
-- (void)removeConnectedCentral:(CBCentral *)central;
- (CBService *)findIncludedService:(const QBluetoothUuid &)qtUUID;
- (void)addIncludedServices:(const QLowEnergyServiceData &)data
@@ -177,7 +143,7 @@ bool qt_validate_value_range(const QLowEnergyCharacteristicData &data)
@end
-@implementation QT_MANGLE_NAMESPACE(DarwinBTPeripheralManager)
+@implementation DarwinBTPeripheralManager
{
ObjCScopedPointer<CBPeripheralManager> manager;
LECBManagerNotifier *notifier;
@@ -200,10 +166,9 @@ bool qt_validate_value_range(const QLowEnergyCharacteristicData &data)
std::deque<UpdateRequest> updateQueue;
- ObjCScopedPointer<NSMutableSet> connectedCentrals;
-
PeripheralState state;
NSUInteger maxNotificationValueLength;
+ decltype(services.size()) nOfFailedAds;
}
- (id)initWith:(LECBManagerNotifier *)aNotifier
@@ -213,8 +178,6 @@ bool qt_validate_value_range(const QLowEnergyCharacteristicData &data)
notifier = aNotifier;
state = PeripheralState::idle;
nextServiceToAdd = {};
- connectedCentrals.reset([[NSMutableSet alloc] init],
- DarwinBluetooth::RetainPolicy::noInitialRetain);
maxNotificationValueLength = std::numeric_limits<NSUInteger>::max();
}
@@ -274,7 +237,7 @@ bool qt_validate_value_range(const QLowEnergyCharacteristicData &data)
data:(const QLowEnergyAdvertisingData &)data
scanResponse:(const QLowEnergyAdvertisingData &)scanResponse
{
- Q_UNUSED(parameters)
+ Q_UNUSED(parameters);
// This is the last method we call on the controller's thread
// before starting advertising on the Qt's LE queue.
@@ -311,7 +274,7 @@ bool qt_validate_value_range(const QLowEnergyCharacteristicData &data)
forKey:CBAdvertisementDataLocalNameKey];
}
- if (!data.services().count() && !scanResponse.services().count())
+ if (data.services().isEmpty() && scanResponse.services().isEmpty())
return;
const ObjCScopedPointer<NSMutableArray> uuids([[NSMutableArray alloc] init],
@@ -388,7 +351,7 @@ bool qt_validate_value_range(const QLowEnergyCharacteristicData &data)
}
const auto & range = valueRanges[charHandle];
- if (value.size() < int(range.first) || value.size() > int(range.second)
+ if (value.size() < qsizetype(range.first) || value.size() > qsizetype(range.second)
#ifdef Q_OS_IOS
|| value.size() > DarwinBluetooth::maxValueLength) {
#else
@@ -434,6 +397,7 @@ bool qt_validate_value_range(const QLowEnergyCharacteristicData &data)
[manager removeAllServices];
nextServiceToAdd = {};
state = PeripheralState::advertising;
+ nOfFailedAds = 0;
[self addServicesToPeripheral];
}
return;
@@ -444,7 +408,7 @@ bool qt_validate_value_range(const QLowEnergyCharacteristicData &data)
advertising has stopped and that any connected centrals have been disconnected."
*/
- [connectedCentrals removeAllObjects];
+ maxNotificationValueLength = std::numeric_limits<NSUInteger>::max();
if (state == PeripheralState::advertising) {
state = PeripheralState::waitingForPowerOn;
@@ -459,22 +423,17 @@ bool qt_validate_value_range(const QLowEnergyCharacteristicData &data)
explicitly added again."
*/
- if (peripheral.state == CBManagerStateUnauthorized || peripheral.state == CBManagerStateUnsupported) {
+ if (peripheral.state == CBManagerStateUnsupported) {
+ state = PeripheralState::idle;
emit notifier->LEnotSupported();
+ } else if (peripheral.state == CBManagerStateUnauthorized) {
state = PeripheralState::idle;
+ emit notifier->CBManagerError(QLowEnergyController::MissingPermissionsError);
}
#pragma clang diagnostic pop
}
-- (void)peripheralManager:(CBPeripheralManager *)peripheral
- willRestoreState:(NSDictionary *)dict
-{
- Q_UNUSED(peripheral)
- Q_UNUSED(dict)
- // NOOP atm.
-}
-
- (void)peripheralManagerDidStartAdvertising:(CBPeripheralManager *)peripheral
error:(NSError *)error
{
@@ -491,28 +450,32 @@ bool qt_validate_value_range(const QLowEnergyCharacteristicData &data)
- (void)peripheralManager:(CBPeripheralManager *)peripheral
didAddService:(CBService *)service error:(NSError *)error
{
- Q_UNUSED(service)
+ Q_UNUSED(service);
if (peripheral != manager || !notifier)
return;
if (error) {
NSLog(@"failed to add a service, error: %@", error);
- emit notifier->CBManagerError(QLowEnergyController::AdvertisingError);
- state = PeripheralState::idle;
- return;
+ if (++nOfFailedAds == services.size()) {
+ emit notifier->CBManagerError(QLowEnergyController::AdvertisingError);
+ state = PeripheralState::idle;
+ return;
+ }
}
- if (nextServiceToAdd == services.size())
+ if (nextServiceToAdd == services.size()) {
+ nOfFailedAds = 0; // Discard any failed, some services made it into advertising.
[manager startAdvertising:[advertisementData count] ? advertisementData.get() : nil];
- else
+ } else {
[self addServicesToPeripheral];
+ }
}
- (void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central
didSubscribeToCharacteristic:(CBCharacteristic *)characteristic
{
- Q_UNUSED(characteristic)
+ Q_UNUSED(characteristic);
if (peripheral != manager || !notifier)
return;
@@ -526,17 +489,15 @@ bool qt_validate_value_range(const QLowEnergyCharacteristicData &data)
- (void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central
didUnsubscribeFromCharacteristic:(CBCharacteristic *)characteristic
{
- Q_UNUSED(characteristic)
+ Q_UNUSED(characteristic);
if (peripheral != manager || !notifier)
return;
- [self removeConnectedCentral:central];
-
- if (![connectedCentrals count]) {
- if (const auto handle = charMap.key(characteristic))
+ const auto handle = charMap.key(characteristic);
+ if (![static_cast<CBMutableCharacteristic*>(characteristic).subscribedCentrals count]
+ && handle)
emit notifier->notificationEnabled(handle, false);
- }
}
- (void)peripheralManager:(CBPeripheralManager *)peripheral
@@ -632,7 +593,7 @@ bool qt_validate_value_range(const QLowEnergyCharacteristicData &data)
[self writeValueForCharacteristic:charHandle withWriteRequest:request];
}
- for (const auto pair : updated) {
+ for (const auto &pair : updated) {
const auto handle = pair.first;
NSMutableData *value = charValues[handle];
value.length = pair.second;
@@ -667,8 +628,7 @@ bool qt_validate_value_range(const QLowEnergyCharacteristicData &data)
while (updateQueue.size()) {
const auto &request = updateQueue.front();
if (charMap.contains(request.charHandle)) {
- if ([connectedCentrals count]
- && maxNotificationValueLength < [request.value length]) {
+ if (maxNotificationValueLength < [request.value length]) {
qCWarning(QT_BT_DARWIN) << "value of length" << [request.value length]
<< "will possibly be truncated to"
<< maxNotificationValueLength;
@@ -705,33 +665,8 @@ bool qt_validate_value_range(const QLowEnergyCharacteristicData &data)
if (state == PeripheralState::advertising) {
state = PeripheralState::connected;
- [manager stopAdvertising];
emit notifier->connected();
}
-
- if (![connectedCentrals containsObject:central.identifier])
- [connectedCentrals addObject:central.identifier];
-}
-
-- (void)removeConnectedCentral:(CBCentral *)central
-{
- if (!notifier) {
- // Detached.
- return;
- }
-
- QT_BT_MAC_AUTORELEASEPOOL
-
- if ([connectedCentrals containsObject:central.identifier])
- [connectedCentrals removeObject:central.identifier];
-
- if (state == PeripheralState::connected && ![connectedCentrals count]) {
- state = PeripheralState::idle;
- emit notifier->disconnected();
- }
-
- if (![connectedCentrals count])
- maxNotificationValueLength = std::numeric_limits<NSUInteger>::max();
}
- (CBService *)findIncludedService:(const QBluetoothUuid &)qtUUID
@@ -801,7 +736,7 @@ bool qt_validate_value_range(const QLowEnergyCharacteristicData &data)
}
#ifdef Q_OS_IOS
- if (ch.value().length() > DarwinBluetooth::maxValueLength) {
+ if (ch.value().size() > DarwinBluetooth::maxValueLength) {
qCWarning(QT_BT_DARWIN) << "addCharacteristicsAndDescritptors: "
"value exceeds the maximal permitted "
"value length ("
diff --git a/src/bluetooth/darwin/btperipheralmanager_p.h b/src/bluetooth/darwin/btperipheralmanager_p.h
index e09165ac..3bd7ceb7 100644
--- a/src/bluetooth/darwin/btperipheralmanager_p.h
+++ b/src/bluetooth/darwin/btperipheralmanager_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef BTPERIPHERALMANAGER_P_H
#define BTPERIPHERALMANAGER_P_H
@@ -53,18 +17,17 @@
#include "btutility_p.h"
-#include "qlowenergyadvertisingparameters.h"
#include "qlowenergyserviceprivate_p.h"
-#include "qbluetoothuuid.h"
#include "qbluetooth.h"
#include <QtCore/qsharedpointer.h>
#include <QtCore/qbytearray.h>
-#include <QtCore/qsysinfo.h>
#include <QtCore/qglobal.h>
#include <QtCore/qpair.h>
#include <QtCore/qmap.h>
+#include <QtCore/private/qcore_mac_p.h>
+
#include <vector>
#include <deque>
#include <map>
@@ -75,6 +38,8 @@
QT_BEGIN_NAMESPACE
+class QLowEnergyAdvertisingParameters;
+class QLowEnergyAdvertisingData;
class QLowEnergyServiceData;
namespace DarwinBluetooth
@@ -142,8 +107,6 @@ using ValueRange = QPair<NSUInteger, NSUInteger>;
// CBPeripheralManagerDelegate's callbacks (BTLE queue).
- (void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral;
-- (void)peripheralManager:(CBPeripheralManager *)peripheral
- willRestoreState:(NSDictionary *)dict;
- (void)peripheralManagerDidStartAdvertising:(CBPeripheralManager *)peripheral
error:(NSError *)error;
- (void)peripheralManager:(CBPeripheralManager *)peripheral
@@ -160,4 +123,6 @@ using ValueRange = QPair<NSUInteger, NSUInteger>;
@end
+QT_NAMESPACE_ALIAS_OBJC_CLASS(DarwinBTPeripheralManager);
+
#endif
diff --git a/src/bluetooth/darwin/btraii.mm b/src/bluetooth/darwin/btraii.mm
index 486c3c14..acf95ae2 100644
--- a/src/bluetooth/darwin/btraii.mm
+++ b/src/bluetooth/darwin/btraii.mm
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "btraii_p.h"
diff --git a/src/bluetooth/darwin/btraii_p.h b/src/bluetooth/darwin/btraii_p.h
index c7a159cb..1ba5d35e 100644
--- a/src/bluetooth/darwin/btraii_p.h
+++ b/src/bluetooth/darwin/btraii_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef BTRAII_P_H
#define BTRAII_P_H
@@ -51,7 +15,7 @@
// We mean it.
//
-#include <QtCore/qglobal.h>
+#include <QtCore/private/qglobal_p.h>
#include <utility>
@@ -76,10 +40,6 @@ enum class RetainPolicy
// Objective-C compiler to work. Member-function template 'getAs' is
// a convenience shortcut giving the desired pointer type in
// Objective-C++ files (*.mm).
-
-// TODO: on top of these classes I can build ObjCStrongReference (it's
-// now inside osxbtutils_p.h, a template class that does have type
-// information needed but works only in Objective-C++ environment.
class StrongReference
{
public:
diff --git a/src/bluetooth/darwin/btrfcommchannel.mm b/src/bluetooth/darwin/btrfcommchannel.mm
index 0cac3c6d..821944ec 100644
--- a/src/bluetooth/darwin/btrfcommchannel.mm
+++ b/src/bluetooth/darwin/btrfcommchannel.mm
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "btrfcommchannel_p.h"
#include "qbluetoothaddress.h"
@@ -44,7 +8,7 @@
QT_USE_NAMESPACE
-@implementation QT_MANGLE_NAMESPACE(DarwinBTRFCOMMChannel)
+@implementation DarwinBTRFCOMMChannel
{
QT_PREPEND_NAMESPACE(DarwinBluetooth)::ChannelDelegate *delegate;
IOBluetoothDevice *device;
@@ -140,7 +104,7 @@ QT_USE_NAMESPACE
- (void)rfcommChannelData:(IOBluetoothRFCOMMChannel*)rfcommChannel
data:(void *)dataPointer length:(size_t)dataLength
{
- Q_UNUSED(rfcommChannel)
+ Q_UNUSED(rfcommChannel);
Q_ASSERT_X(delegate, Q_FUNC_INFO, "invalid delegate (null)");
@@ -155,7 +119,7 @@ QT_USE_NAMESPACE
- (void)rfcommChannelOpenComplete:(IOBluetoothRFCOMMChannel*)rfcommChannel
status:(IOReturn)error
{
- Q_UNUSED(rfcommChannel)
+ Q_UNUSED(rfcommChannel);
Q_ASSERT_X(delegate, Q_FUNC_INFO, "invalid delegate (null)");
@@ -169,7 +133,7 @@ QT_USE_NAMESPACE
- (void)rfcommChannelClosed:(IOBluetoothRFCOMMChannel*)rfcommChannel
{
- Q_UNUSED(rfcommChannel)
+ Q_UNUSED(rfcommChannel);
Q_ASSERT_X(delegate, Q_FUNC_INFO, "invalid delegate (null)");
delegate->channelClosed();
@@ -178,19 +142,19 @@ QT_USE_NAMESPACE
- (void)rfcommChannelControlSignalsChanged:(IOBluetoothRFCOMMChannel*)rfcommChannel
{
- Q_UNUSED(rfcommChannel)
+ Q_UNUSED(rfcommChannel);
}
- (void)rfcommChannelFlowControlChanged:(IOBluetoothRFCOMMChannel*)rfcommChannel
{
- Q_UNUSED(rfcommChannel)
+ Q_UNUSED(rfcommChannel);
}
- (void)rfcommChannelWriteComplete:(IOBluetoothRFCOMMChannel*)rfcommChannel
refcon:(void*)refcon status:(IOReturn)error
{
- Q_UNUSED(rfcommChannel)
- Q_UNUSED(refcon)
+ Q_UNUSED(rfcommChannel);
+ Q_UNUSED(refcon);
Q_ASSERT_X(delegate, Q_FUNC_INFO, "invalid delegate (null)");
@@ -202,7 +166,7 @@ QT_USE_NAMESPACE
- (void)rfcommChannelQueueSpaceAvailable:(IOBluetoothRFCOMMChannel*)rfcommChannel
{
- Q_UNUSED(rfcommChannel)
+ Q_UNUSED(rfcommChannel);
}
- (BluetoothRFCOMMChannelID)getChannelID
diff --git a/src/bluetooth/darwin/btrfcommchannel_p.h b/src/bluetooth/darwin/btrfcommchannel_p.h
index 25299092..dd32c49a 100644
--- a/src/bluetooth/darwin/btrfcommchannel_p.h
+++ b/src/bluetooth/darwin/btrfcommchannel_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef BTRFCOMMCHANNEL_P_H
#define BTRFCOMMCHANNEL_P_H
@@ -51,7 +15,8 @@
// We mean it.
//
-#include <QtCore/qglobal.h>
+#include <QtCore/private/qglobal_p.h>
+#include <QtCore/private/qcore_mac_p.h>
#include <Foundation/Foundation.h>
@@ -102,7 +67,8 @@ QT_END_NAMESPACE
- (IOReturn) writeSync:(void*)data length:(UInt16)length;
- (IOReturn) writeAsync:(void*)data length:(UInt16)length;
-
@end
+QT_NAMESPACE_ALIAS_OBJC_CLASS(DarwinBTRFCOMMChannel);
+
#endif
diff --git a/src/bluetooth/darwin/btsdpinquiry.mm b/src/bluetooth/darwin/btsdpinquiry.mm
index 468d5445..f3a235a6 100644
--- a/src/bluetooth/darwin/btsdpinquiry.mm
+++ b/src/bluetooth/darwin/btsdpinquiry.mm
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qbluetoothserviceinfo.h"
#include "btsdpinquiry_p.h"
@@ -43,8 +7,12 @@
#include "btdelegates_p.h"
#include "btutility_p.h"
+#include <QtCore/qoperatingsystemversion.h>
#include <QtCore/qvariant.h>
#include <QtCore/qstring.h>
+#include <QtCore/qtimer.h>
+
+#include <memory>
QT_BEGIN_NAMESPACE
@@ -52,6 +20,8 @@ namespace DarwinBluetooth {
namespace {
+const int basebandConnectTimeoutMS = 20000;
+
QBluetoothUuid sdp_element_to_uuid(IOBluetoothSDPDataElement *element)
{
QT_BT_MAC_AUTORELEASEPOOL;
@@ -71,18 +41,27 @@ QBluetoothUuid extract_service_ID(IOBluetoothSDPServiceRecord *record)
return sdp_element_to_uuid([record getAttributeDataElement:kBluetoothSDPAttributeIdentifierServiceID]);
}
-QVector<QBluetoothUuid> extract_service_class_ID_list(IOBluetoothSDPServiceRecord *record)
+QList<QBluetoothUuid> extract_service_class_ID_list(IOBluetoothSDPServiceRecord *record)
{
Q_ASSERT(record);
QT_BT_MAC_AUTORELEASEPOOL;
IOBluetoothSDPDataElement *const idList = [record getAttributeDataElement:kBluetoothSDPAttributeIdentifierServiceClassIDList];
- if (!idList || [idList getTypeDescriptor] != kBluetoothSDPDataElementTypeDataElementSequence)
- return {};
- QVector<QBluetoothUuid> uuids;
- NSArray *const arr = [idList getArrayValue];
+ QList<QBluetoothUuid> uuids;
+ if (!idList)
+ return uuids;
+
+ NSArray *arr = nil;
+ if ([idList getTypeDescriptor] == kBluetoothSDPDataElementTypeDataElementSequence)
+ arr = [idList getArrayValue];
+ else if ([idList getTypeDescriptor] == kBluetoothSDPDataElementTypeUUID)
+ arr = @[idList];
+
+ if (!arr)
+ return uuids;
+
for (IOBluetoothSDPDataElement *dataElement in arr) {
const auto qtUuid = sdp_element_to_uuid(dataElement);
if (!qtUuid.isNull())
@@ -92,7 +71,7 @@ QVector<QBluetoothUuid> extract_service_class_ID_list(IOBluetoothSDPServiceRecor
return uuids;
}
-QBluetoothServiceInfo::Sequence service_class_ID_list_to_sequence(const QVector<QBluetoothUuid> &uuids)
+QBluetoothServiceInfo::Sequence service_class_ID_list_to_sequence(const QList<QBluetoothUuid> &uuids)
{
if (uuids.isEmpty())
return {};
@@ -170,15 +149,15 @@ void extract_service_record(IOBluetoothSDPServiceRecord *record, QBluetoothServi
if (!serviceUuid.isNull())
serviceInfo.setServiceUuid(serviceUuid);
- const QVector<QBluetoothUuid> uuids(extract_service_class_ID_list(record));
+ const QList<QBluetoothUuid> uuids(extract_service_class_ID_list(record));
const auto sequence = service_class_ID_list_to_sequence(uuids);
if (!sequence.isEmpty())
serviceInfo.setAttribute(QBluetoothServiceInfo::ServiceClassIds, sequence);
}
-QVector<QBluetoothUuid> extract_services_uuids(IOBluetoothDevice *device)
+QList<QBluetoothUuid> extract_services_uuids(IOBluetoothDevice *device)
{
- QVector<QBluetoothUuid> uuids;
+ QList<QBluetoothUuid> uuids;
// All "temporary" obj-c objects are autoreleased.
QT_BT_MAC_AUTORELEASEPOOL;
@@ -192,7 +171,7 @@ QVector<QBluetoothUuid> extract_services_uuids(IOBluetoothDevice *device)
if (!serviceID.isNull())
uuids.push_back(serviceID);
- const QVector<QBluetoothUuid> idList(extract_service_class_ID_list(record));
+ const QList<QBluetoothUuid> idList(extract_service_class_ID_list(record));
if (idList.size())
uuids.append(idList);
}
@@ -208,11 +187,14 @@ QT_USE_NAMESPACE
using namespace DarwinBluetooth;
-@implementation QT_MANGLE_NAMESPACE(DarwinBTSDPInquiry)
+@implementation DarwinBTSDPInquiry
{
QT_PREPEND_NAMESPACE(DarwinBluetooth::SDPInquiryDelegate) *delegate;
ObjCScopedPointer<IOBluetoothDevice> device;
bool isActive;
+
+ // Needed to workaround a broken SDP on Monterey:
+ std::unique_ptr<QTimer> connectionWatchdog;
}
- (id)initWithDelegate:(DarwinBluetooth::SDPInquiryDelegate *)aDelegate
@@ -241,17 +223,40 @@ using namespace DarwinBluetooth;
return [self performSDPQueryWithDevice:address filters:emptyFilter];
}
+- (void)interruptSDPQuery
+{
+ // To be only executed on timer.
+ Q_ASSERT(connectionWatchdog.get());
+ // If device was reset, so the timer should be, we can never be here then.
+ Q_ASSERT(device.get());
+
+ Q_ASSERT_X(delegate, Q_FUNC_INFO, "invalid delegate (null)");
+ qCDebug(QT_BT_DARWIN) << "couldn't connect to device" << [device nameOrAddress]
+ << ", ending SDP inquiry.";
+
+ // Stop the watchdog and close the connection as otherwise there could be
+ // later "connectionComplete" callbacks
+ connectionWatchdog->stop();
+ [device closeConnection];
+
+ delegate->SDPInquiryError(device, kIOReturnTimeout);
+ device.reset();
+ isActive = false;
+}
+
- (IOReturn)performSDPQueryWithDevice:(const QBluetoothAddress &)address
filters:(const QList<QBluetoothUuid> &)qtFilters
{
Q_ASSERT_X(!isActive, Q_FUNC_INFO, "SDP query in progress");
Q_ASSERT_X(!address.isNull(), Q_FUNC_INFO, "invalid target device address");
+ qCDebug(QT_BT_DARWIN) << "Starting and SDP inquiry for address:" << address;
QT_BT_MAC_AUTORELEASEPOOL;
// We first try to allocate "filters":
ObjCScopedPointer<NSMutableArray> array;
- if (qtFilters.size()) {
+ if (QOperatingSystemVersion::current() <= QOperatingSystemVersion::MacOSBigSur
+ && qtFilters.size()) { // See the comment about filters on Monterey below.
array.reset([[NSMutableArray alloc] init], RetainPolicy::noInitialRetain);
if (!array) {
qCCritical(QT_BT_DARWIN) << "failed to allocate an uuid filter";
@@ -264,7 +269,7 @@ using namespace DarwinBluetooth;
[array addObject:uuid];
}
- if (int([array count]) != qtFilters.size()) {
+ if (qsizetype([array count]) != qtFilters.size()) {
qCCritical(QT_BT_DARWIN) << "failed to create an uuid filter";
return kIOReturnError;
}
@@ -276,8 +281,65 @@ using namespace DarwinBluetooth;
qCCritical(QT_BT_DARWIN) << "failed to create an IOBluetoothDevice object";
return kIOReturnError;
}
+ qCDebug(QT_BT_DARWIN) << "Device" << [device nameOrAddress] << "connected:"
+ << bool([device isConnected]) << "paired:" << bool([device isPaired]);
IOReturn result = kIOReturnSuccess;
+
+ if (QOperatingSystemVersion::current() > QOperatingSystemVersion::MacOSBigSur) {
+ // SDP query on Monterey does not follow its own documented/expected behavior:
+ // - a simple performSDPQuery was previously ensuring baseband connection
+ // to be opened, now it does not do so, instead logs a warning and returns
+ // immediately.
+ // - a version with UUID filters simply does nothing except it immediately
+ // returns kIOReturnSuccess.
+
+ // If the device was not yet connected, connect it first
+ if (![device isConnected]) {
+ qCDebug(QT_BT_DARWIN) << "Device" << [device nameOrAddress]
+ << "is not connected, connecting it first";
+ result = [device openConnection:self];
+ // The connection may succeed immediately. But if it didn't, start a connection timer
+ // which has two guardian roles:
+ // 1. Guard against connect attempt taking too long time
+ // 2. Sometimes on Monterey the callback indicating "connection completion" is
+ // not received even though the connection has in fact succeeded
+ if (![device isConnected]) {
+ qCDebug(QT_BT_DARWIN) << "Starting connection monitor for device"
+ << [device nameOrAddress] << "with timeout limit of"
+ << basebandConnectTimeoutMS/1000 << "seconds.";
+ connectionWatchdog.reset(new QTimer);
+ connectionWatchdog->setSingleShot(false);
+ QObject::connect(connectionWatchdog.get(), &QTimer::timeout,
+ connectionWatchdog.get(),
+ [self] () {
+ qCDebug(QT_BT_DARWIN) << "Connection monitor timeout for device:"
+ << [device nameOrAddress]
+ << ", connected:" << bool([device isConnected]);
+ // Device can sometimes get properly connected without IOBluetooth
+ // calling the connectionComplete callback, so we check the status here
+ if ([device isConnected])
+ [self connectionComplete:device status:kIOReturnSuccess];
+ else
+ [self interruptSDPQuery];
+ });
+ connectionWatchdog->start(basebandConnectTimeoutMS);
+ }
+ }
+
+ if ([device isConnected])
+ result = [device performSDPQuery:self];
+
+ if (result != kIOReturnSuccess) {
+ qCCritical(QT_BT_DARWIN, "failed to start an SDP query");
+ device.reset();
+ } else {
+ isActive = true;
+ }
+
+ return result;
+ } // Monterey's code path.
+
if (qtFilters.size())
result = [device performSDPQuery:self uuids:array];
else
@@ -293,16 +355,45 @@ using namespace DarwinBluetooth;
return result;
}
+- (void)connectionComplete:(IOBluetoothDevice *)aDevice status:(IOReturn)status
+{
+ qCDebug(QT_BT_DARWIN) << "connectionComplete for device" << [aDevice nameOrAddress]
+ << "with status:" << status;
+ if (aDevice != device) {
+ // Connection was previously cancelled, probably, due to the timeout.
+ return;
+ }
+
+ // The connectionComplete may be invoked by either the IOBluetooth callback or our
+ // connection watchdog. In either case stop the watchdog if it exists
+ if (connectionWatchdog)
+ connectionWatchdog->stop();
+
+ if (status == kIOReturnSuccess)
+ status = [aDevice performSDPQuery:self];
+
+ if (status != kIOReturnSuccess) {
+ isActive = false;
+ qCWarning(QT_BT_DARWIN, "failed to open connection or start an SDP query");
+ Q_ASSERT_X(delegate, Q_FUNC_INFO, "invalid delegate (null)");
+ delegate->SDPInquiryError(aDevice, status);
+ }
+}
+
- (void)stopSDPQuery
{
- // There is no API to stop it,
- // but there is a 'stop' member-function in Qt and
- // after it's called sdpQueryComplete must be somehow ignored.
+ // There is no API to stop it SDP on device, but there is a 'stop'
+ // member-function in Qt and after it's called sdpQueryComplete
+ // must be somehow ignored (device != aDevice in a callback).
device.reset();
+ isActive = false;
+ connectionWatchdog.reset();
}
- (void)sdpQueryComplete:(IOBluetoothDevice *)aDevice status:(IOReturn)status
{
+ qCDebug(QT_BT_DARWIN) << "sdpQueryComplete for device:" << [aDevice nameOrAddress]
+ << "with status:" << status;
// Can happen - there is no legal way to cancel an SDP query,
// after the 'reset' device can never be
// the same as the cancelled one.
@@ -313,6 +404,15 @@ using namespace DarwinBluetooth;
isActive = false;
+ // If we used the manual connection establishment, close the
+ // connection here. Otherwise the IOBluetooth may call stray
+ // connectionComplete or sdpQueryCompletes
+ if (connectionWatchdog) {
+ qCDebug(QT_BT_DARWIN) << "Closing the connection established for SDP inquiry.";
+ connectionWatchdog.reset();
+ [device closeConnection];
+ }
+
if (status != kIOReturnSuccess)
delegate->SDPInquiryError(aDevice, status);
else
diff --git a/src/bluetooth/darwin/btsdpinquiry_p.h b/src/bluetooth/darwin/btsdpinquiry_p.h
index 6cce5703..74d7c850 100644
--- a/src/bluetooth/darwin/btsdpinquiry_p.h
+++ b/src/bluetooth/darwin/btsdpinquiry_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef BTSDPINQUIRY_H
#define BTSDPINQUIRY_H
@@ -54,9 +18,9 @@
#include "qbluetoothaddress.h"
#include "qbluetoothuuid.h"
-#include <QtCore/qglobal.h>
+#include <QtCore/private/qglobal_p.h>
+#include <QtCore/private/qcore_mac_p.h>
#include <QtCore/qlist.h>
-#include <QtCore/qvector.h>
#include <Foundation/Foundation.h>
@@ -75,7 +39,7 @@ class SDPInquiryDelegate;
void extract_service_record(IOBluetoothSDPServiceRecord *record, QBluetoothServiceInfo &serviceInfo);
QVariant extract_attribute_value(IOBluetoothSDPDataElement *dataElement);
-QVector<QBluetoothUuid> extract_services_uuids(IOBluetoothDevice *device);
+QList<QBluetoothUuid> extract_services_uuids(IOBluetoothDevice *device);
} // namespace DarwinBluetooth
@@ -96,4 +60,6 @@ QT_END_NAMESPACE
@end
+QT_NAMESPACE_ALIAS_OBJC_CLASS(DarwinBTSDPInquiry);
+
#endif
diff --git a/src/bluetooth/darwin/btservicerecord.mm b/src/bluetooth/darwin/btservicerecord.mm
index dd711504..5c2e5184 100644
--- a/src/bluetooth/darwin/btservicerecord.mm
+++ b/src/bluetooth/darwin/btservicerecord.mm
@@ -1,48 +1,11 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qbluetoothserviceinfo.h"
#include "btservicerecord_p.h"
#include <QtCore/qvariant.h>
#include <QtCore/qdebug.h>
-#include <QtCore/qmap.h>
#include <QtCore/qurl.h>
#include <IOBluetooth/IOBluetooth.h>
@@ -79,7 +42,7 @@ QBluetoothUuid profile_uuid(const QBluetoothServiceInfo &serviceInfo)
if (var.isValid()) {
const Sequence seq(var.value<Sequence>());
- for (int i = 0; i < seq.count(); ++i) {
+ for (qsizetype i = 0; i < seq.size(); ++i) {
QBluetoothUuid uuid(seq.at(i).value<QBluetoothUuid>());
if (uuid.isNull())
continue;
@@ -147,7 +110,7 @@ void add_attribute(const QVariant &var, AttributeId key, Dictionary dict)
return;
const Number num(variant_to_nsnumber<ValueType>(var));
- [dict setObject:num forKey:[NSString stringWithFormat:@"%d", int(key)]];
+ [dict setObject:num forKey:[NSString stringWithFormat:@"%x", int(key)]];
}
template<>
@@ -159,9 +122,9 @@ void add_attribute<QString>(const QVariant &var, AttributeId key, Dictionary dic
return;
const QString string(var.value<QString>());
- if (string.length()) {
+ if (!string.isEmpty()) {
if (NSString *const nsString = string.toNSString())
- [dict setObject:nsString forKey:[NSString stringWithFormat:@"%d", int(key)]];
+ [dict setObject:nsString forKey:[NSString stringWithFormat:@"%x", int(key)]];
}
}
@@ -174,7 +137,7 @@ void add_attribute<QBluetoothUuid>(const QVariant &var, AttributeId key, Diction
return;
SDPUUid ioUUID(iobluetooth_uuid(var.value<QBluetoothUuid>()));
- [dict setObject:ioUUID forKey:[NSString stringWithFormat:@"%d", int(key)]];
+ [dict setObject:ioUUID forKey:[NSString stringWithFormat:@"%x", int(key)]];
}
template<>
@@ -185,9 +148,9 @@ void add_attribute<QUrl>(const QVariant &var, AttributeId key, Dictionary dict)
if (!var.canConvert<QUrl>())
return;
- Q_UNUSED(var)
- Q_UNUSED(key)
- Q_UNUSED(dict)
+ Q_UNUSED(var);
+ Q_UNUSED(key);
+ Q_UNUSED(dict);
// TODO: not clear how should I pass an url in a dictionary, NSURL does not work.
}
@@ -208,6 +171,25 @@ void add_attribute(const QVariant &var, NSMutableArray *list)
}
template<>
+void add_attribute<unsigned short>(const QVariant &var, NSMutableArray *list)
+{
+ Q_ASSERT_X(list, Q_FUNC_INFO, "invalid list (nil)");
+
+ if (!var.canConvert<unsigned short>())
+ return;
+
+ const Number num(variant_to_nsnumber<unsigned short>(var));
+
+ NSDictionary* dict = @{
+ @"DataElementType" : [NSNumber numberWithInt:1],
+ @"DataElementSize" : [NSNumber numberWithInt:2],
+ @"DataElementValue" : num
+ };
+
+ [list addObject: dict];
+}
+
+template<>
void add_attribute<QString>(const QVariant &var, NSMutableArray *list)
{
Q_ASSERT_X(list, Q_FUNC_INFO, "invalid list (nil)");
@@ -216,7 +198,7 @@ void add_attribute<QString>(const QVariant &var, NSMutableArray *list)
return;
const QString string(var.value<QString>());
- if (string.length()) {
+ if (!string.isEmpty()) {
if (NSString *const nsString = string.toNSString())
[list addObject:nsString];
}
@@ -242,8 +224,8 @@ void add_attribute<QUrl>(const QVariant &var, NSMutableArray *list)
if (!var.canConvert<QUrl>())
return;
- Q_UNUSED(var)
- Q_UNUSED(list)
+ Q_UNUSED(var);
+ Q_UNUSED(list);
// TODO: not clear how should I pass an url in a dictionary, NSURL does not work.
}
@@ -274,7 +256,7 @@ void add_rfcomm_protocol_descriptor_list(uint16 channelID, Dictionary dict)
[rfcommList addObject:rfcommDict];
[descriptorList addObject:rfcommList];
- [dict setObject:descriptorList forKey:[NSString stringWithFormat:@"%d",
+ [dict setObject:descriptorList forKey:[NSString stringWithFormat:@"%x",
kBluetoothSDPAttributeIdentifierProtocolDescriptorList]];
}
@@ -300,7 +282,7 @@ void add_l2cap_protocol_descriptor_list(uint16 psm, Dictionary dict)
[l2capList addObject:l2capDict];
[descriptorList addObject:l2capList];
- [dict setObject:descriptorList forKey:[NSString stringWithFormat:@"%d",
+ [dict setObject:descriptorList forKey:[NSString stringWithFormat:@"%x",
kBluetoothSDPAttributeIdentifierProtocolDescriptorList]];
}
@@ -311,10 +293,10 @@ bool add_attribute(const QVariant &var, AttributeId key, NSMutableArray *list)
if (var.canConvert<Sequence>())
return false;
- if (var.canConvert<QString>()) {
+ if (var.typeId() == QMetaType::QString) {
//ServiceName, ServiceDescription, ServiceProvider.
add_attribute<QString>(var, list);
- } else if (var.canConvert<QBluetoothUuid>()) {
+ } else if (var.userType() == qMetaTypeId<QBluetoothUuid>()) {
add_attribute<QBluetoothUuid>(var, list);
} else {
// Here we need 'key' to understand the type.
@@ -326,6 +308,9 @@ bool add_attribute(const QVariant &var, AttributeId key, NSMutableArray *list)
case QSInfo::ServiceInfoTimeToLive:
add_attribute<unsigned>(var, list);
break;
+ case QSInfo::BluetoothProfileDescriptorList:
+ add_attribute<unsigned short>(var, list);
+ break;
case QSInfo::ServiceAvailability:
add_attribute<unsigned char>(var, list);
break;
@@ -349,10 +334,10 @@ bool add_attribute(const QBluetoothServiceInfo &serviceInfo, AttributeId key, Di
if (var.canConvert<Sequence>())
return false;
- if (var.canConvert<QString>()) {
+ if (var.typeId() == QMetaType::QString) {
//ServiceName, ServiceDescription, ServiceProvider.
add_attribute<QString>(var, key, dict);
- } else if (var.canConvert<QBluetoothUuid>()) {
+ } else if (var.userType() == qMetaTypeId<QBluetoothUuid>()) {
add_attribute<QBluetoothUuid>(serviceInfo.attribute(key), key, dict);
} else {
// We can have different integer types actually, so I have to check
@@ -386,14 +371,15 @@ bool add_sequence_attribute(const QVariant &var, AttributeId key, NSMutableArray
if (var.isNull() || !var.canConvert<Sequence>())
return false;
+ NSMutableArray *const nested = [NSMutableArray array];
+ [list addObject:nested];
+
const Sequence sequence(var.value<Sequence>());
for (const QVariant &var : sequence) {
if (var.canConvert<Sequence>()) {
- NSMutableArray *const nested = [NSMutableArray array];
add_sequence_attribute(var, key, nested);
- [list addObject:nested];
} else {
- add_attribute(var, key, list);
+ add_attribute(var, key, nested);
}
}
@@ -416,8 +402,7 @@ bool add_sequence_attribute(const QBluetoothServiceInfo &serviceInfo, AttributeI
if (!add_sequence_attribute(element, key, list))
add_attribute(element, key, list);
}
- [dict setObject:list forKey:[NSString stringWithFormat:@"%d", int(key)]];
-
+ [dict setObject:list forKey:[NSString stringWithFormat:@"%x", int(key)]];
return true;
}
diff --git a/src/bluetooth/darwin/btservicerecord_p.h b/src/bluetooth/darwin/btservicerecord_p.h
index 6b5b0374..fc882d91 100644
--- a/src/bluetooth/darwin/btservicerecord_p.h
+++ b/src/bluetooth/darwin/btservicerecord_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef BTSERVICERECORD_P_H
#define BTSERVICERECORD_P_H
diff --git a/src/bluetooth/darwin/btsocketlistener.mm b/src/bluetooth/darwin/btsocketlistener.mm
index 505fec14..073e8944 100644
--- a/src/bluetooth/darwin/btsocketlistener.mm
+++ b/src/bluetooth/darwin/btsocketlistener.mm
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "btsocketlistener_p.h"
#include "btdelegates_p.h"
@@ -45,7 +9,7 @@
QT_USE_NAMESPACE
-@implementation QT_MANGLE_NAMESPACE(DarwinBTSocketListener)
+@implementation DarwinBTSocketListener
{
IOBluetoothUserNotification *connectionNotification;
QT_PREPEND_NAMESPACE(DarwinBluetooth::SocketListener) *delegate;
@@ -105,7 +69,7 @@ QT_USE_NAMESPACE
- (void)rfcommOpenNotification:(IOBluetoothUserNotification *)notification
channel:(IOBluetoothRFCOMMChannel *)newChannel
{
- Q_UNUSED(notification)
+ Q_UNUSED(notification);
Q_ASSERT_X(delegate, Q_FUNC_INFO, "invalid delegate (null)");
delegate->openNotifyRFCOMM(newChannel);
@@ -114,7 +78,7 @@ QT_USE_NAMESPACE
- (void)l2capOpenNotification:(IOBluetoothUserNotification *)notification
channel:(IOBluetoothL2CAPChannel *)newChannel
{
- Q_UNUSED(notification)
+ Q_UNUSED(notification);
Q_ASSERT_X(delegate, Q_FUNC_INFO, "invalid delegate (null)");
delegate->openNotifyL2CAP(newChannel);
diff --git a/src/bluetooth/darwin/btsocketlistener_p.h b/src/bluetooth/darwin/btsocketlistener_p.h
index 4b9b267a..82950ec2 100644
--- a/src/bluetooth/darwin/btsocketlistener_p.h
+++ b/src/bluetooth/darwin/btsocketlistener_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef BTSOCKETLISTENER_P_H
#define BTSOCKETLISTENER_P_H
@@ -51,7 +15,8 @@
// We mean it.
//
-#include <QtCore/qglobal.h>
+#include <QtCore/private/qglobal_p.h>
+#include <QtCore/private/qcore_mac_p.h>
#include <Foundation/Foundation.h>
@@ -88,4 +53,6 @@ QT_END_NAMESPACE
@end
+QT_NAMESPACE_ALIAS_OBJC_CLASS(DarwinBTSocketListener);
+
#endif
diff --git a/src/bluetooth/darwin/btutility.mm b/src/bluetooth/darwin/btutility.mm
index 07c22c1c..e9f2156f 100644
--- a/src/bluetooth/darwin/btutility.mm
+++ b/src/bluetooth/darwin/btutility.mm
@@ -1,47 +1,12 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qlowenergycharacteristicdata.h"
#include "qbluetoothaddress.h"
-#include "btutility_p.h"
#include "qbluetoothuuid.h"
+#include "btutility_p.h"
+#include <QtCore/qoperatingsystemversion.h>
#include <QtCore/qendian.h>
#include <QtCore/qstring.h>
@@ -62,10 +27,12 @@ Q_LOGGING_CATEGORY(QT_BT_DARWIN, "qt.bluetooth.darwin")
namespace DarwinBluetooth {
-const int defaultLEScanTimeoutMS = 25000;
+const int defaultLEScanTimeoutMS = 40000;
// We use it only on iOS for now:
const int maxValueLength = 512;
+const int defaultMtu = 23;
+
QString qt_address(NSString *address)
{
if (address && address.length) {
@@ -114,7 +81,7 @@ BluetoothDeviceAddress iobluetooth_address(const QBluetoothAddress &qAddress)
ObjCStrongReference<IOBluetoothSDPUUID> iobluetooth_uuid(const QBluetoothUuid &uuid)
{
const unsigned nBytes = 128 / std::numeric_limits<unsigned char>::digits;
- const quint128 intVal(uuid.toUInt128());
+ const QUuid::Id128Bytes intVal(uuid.toBytes());
const ObjCStrongReference<IOBluetoothSDPUUID> iobtUUID([IOBluetoothSDPUUID uuidWithBytes:intVal.data
length:nBytes], RetainPolicy::doInitialRetain);
@@ -128,7 +95,7 @@ QBluetoothUuid qt_uuid(IOBluetoothSDPUUID *uuid)
return qtUuid;
// TODO: ensure the correct byte-order!!!
- quint128 uuidVal = {};
+ QUuid::Id128Bytes uuidVal = {};
const quint8 *const source = static_cast<const quint8 *>([uuid bytes]);
std::copy(source, source + 16, uuidVal.data);
return QBluetoothUuid(uuidVal);
@@ -169,7 +136,6 @@ void qt_test_iobluetooth_runloop()
#endif // !QT_IOS_BLUETOOTH
-
// Apple has: CBUUID, NSUUID, CFUUID, IOBluetoothSDPUUID
// and it's handy to have several converters:
@@ -177,8 +143,7 @@ QBluetoothUuid qt_uuid(CBUUID *uuid)
{
// Apples' docs say "128 bit" and "16-bit UUIDs are implicitly
// pre-filled with the Bluetooth Base UUID."
- // But Core Bluetooth can return CBUUID objects of length 2
- // (16-bit, so they are not pre-filled?).
+ // But Core Bluetooth can return CBUUID objects of length 2, 4, and 16.
if (!uuid)
return QBluetoothUuid();
@@ -190,40 +155,35 @@ QBluetoothUuid qt_uuid(CBUUID *uuid)
// Seems to be in big-endian.
const uchar *const src = static_cast<const uchar *>(uuid.data.bytes);
return QBluetoothUuid(qFromBigEndian<quint16>(src));
+ } else if (uuid.data.length == 4) {
+ const uchar *const src = static_cast<const uchar *>(uuid.data.bytes);
+ return QBluetoothUuid(qFromBigEndian<quint32>(src));
} else if (uuid.data.length == 16) {
- quint128 qtUuidData = {};
+ QUuid::Id128Bytes qtUuidData = {};
const quint8 *const source = static_cast<const quint8 *>(uuid.data.bytes);
std::copy(source, source + 16, qtUuidData.data);
return QBluetoothUuid(qtUuidData);
}
- qCDebug(QT_BT_DARWIN) << "qt_uuid, invalid CBUUID, 2 or 16 bytes expected, but got "
+ qCDebug(QT_BT_DARWIN) << "qt_uuid, invalid CBUUID, 2, 4, or 16 bytes expected, but got "
<< uuid.data.length << " bytes length";
return QBluetoothUuid();
}
-QCFType<CFUUIDRef> cf_uuid(const QBluetoothUuid &qtUuid)
-{
- const quint128 qtUuidData = qtUuid.toUInt128();
- const quint8 *const data = qtUuidData.data;
-
- CFUUIDBytes bytes = {data[0], data[1], data[2], data[3],
- data[4], data[5], data[6], data[7],
- data[8], data[9], data[10], data[11],
- data[12], data[13], data[14], data[15]};
-
- CFUUIDRef cfUuid = CFUUIDCreateFromUUIDBytes(kCFAllocatorDefault, bytes);
- return cfUuid;
-}
-
ObjCStrongReference<CBUUID> cb_uuid(const QBluetoothUuid &qtUuid)
{
- QCFType<CFUUIDRef> cfUuid(cf_uuid(qtUuid));
- if (!cfUuid)
- return ObjCStrongReference<CBUUID>();
+ bool ok = false;
+ const auto asUInt16 = qToBigEndian(qtUuid.toUInt16(&ok));
+ const auto asUInt128 = qtUuid.toBytes();
+
+ const NSUInteger length = ok ? sizeof asUInt16 : sizeof asUInt128;
+ const void *bytes = &asUInt128;
+ if (ok)
+ bytes = &asUInt16;
- ObjCStrongReference<CBUUID> cbUuid([CBUUID UUIDWithCFUUID:cfUuid], RetainPolicy::doInitialRetain);
+ NSData *uuidData = [NSData dataWithBytes:bytes length:length];
+ ObjCStrongReference<CBUUID> cbUuid([CBUUID UUIDWithData:uuidData], RetainPolicy::doInitialRetain);
return cbUuid;
}
diff --git a/src/bluetooth/darwin/btutility_p.h b/src/bluetooth/darwin/btutility_p.h
index b65544e2..87f4a719 100644
--- a/src/bluetooth/darwin/btutility_p.h
+++ b/src/bluetooth/darwin/btutility_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef BTUTILITY_P_H
#define BTUTILITY_P_H
@@ -71,6 +35,7 @@ QT_BEGIN_NAMESPACE
class QLowEnergyCharacteristicData;
class QBluetoothAddress;
class QBluetoothUuid;
+class QString;
namespace DarwinBluetooth {
@@ -156,6 +121,7 @@ dispatch_queue_t qt_LE_queue();
extern const int defaultLEScanTimeoutMS;
extern const int maxValueLength;
+extern const int defaultMtu;
} // namespace DarwinBluetooth
@@ -163,23 +129,4 @@ Q_DECLARE_LOGGING_CATEGORY(QT_BT_DARWIN)
QT_END_NAMESPACE
-#if QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(101300) && QT_MACOS_DEPLOYMENT_TARGET_BELOW(101300)
-
- // In the macOS 10.13 SDK, the identifier property was moved from the CBPeripheral
- // and CBCentral classes to a new CBPeer base class. Because CBPeer is only available
- // on macOS 10.13 and above, the same is true for -[CBPeer identifier]. However,
- // since we know that the derived classes have always had this property,
- // we'll explicitly mark its availability here. This will not adversely affect
- // using the identifier through the CBPeer base class, which will still require macOS 10.13.
-
-@interface CBPeripheral (UnguardedWorkaround)
-@property (readonly, nonatomic) NSUUID *identifier NS_AVAILABLE(10_7, 5_0);
-@end
-
-@interface CBCentral (UnguardedWorkaround)
-@property (readonly, nonatomic) NSUUID *identifier NS_AVAILABLE(10_7, 5_0);
-@end
-
-#endif // QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE
-
#endif // BTUTILITY_P_H
diff --git a/src/bluetooth/darwin/darwinbt.pri b/src/bluetooth/darwin/darwinbt.pri
deleted file mode 100644
index b419007a..00000000
--- a/src/bluetooth/darwin/darwinbt.pri
+++ /dev/null
@@ -1,48 +0,0 @@
-SOURCES += darwin/uistrings.cpp \
- darwin/btnotifier.cpp \
- darwin/btdelegates.cpp \
- darwin/btledeviceinquiry.mm \
- darwin/btcentralmanager.mm
-
-HEADERS += darwin/uistrings_p.h \
- darwin/btgcdtimer_p.h \
- darwin/btraii_p.h \
- darwin/btdelegates_p.h \
- darwin/btutility_p.h \
- darwin/btledeviceinquiry_p.h \
- darwin/btcentralmanager_p.h \
- darwin/btnotifier_p.h
-
-OBJECTIVE_SOURCES += darwin/btgcdtimer.mm \
- darwin/btraii.mm \
- darwin/btutility.mm
-
-#QMAKE_CXXFLAGS_WARN_ON += -Wno-nullability-completeness
-
-macos {
- HEADERS += darwin/btdevicepair_p.h \
- darwin/btdeviceinquiry_p.h \
- darwin/btconnectionmonitor_p.h \
- darwin/btsdpinquiry_p.h \
- darwin/btrfcommchannel_p.h \
- darwin/btl2capchannel_p.h \
- darwin/btservicerecord_p.h \
- darwin/btsocketlistener_p.h \
- darwin/btobexsession_p.h
-
- OBJECTIVE_SOURCES += darwin/btdevicepair.mm \
- darwin/btdeviceinquiry.mm \
- darwin/btconnectionmonitor.mm \
- darwin/btsdpinquiry.mm \
- darwin/btrfcommchannel.mm \
- darwin/btl2capchannel.mm \
- darwin/btservicerecord.mm \
- darwin/btsocketlistener.mm \
- darwin/btobexsession.mm
-}
-
-macos | ios {
- HEADERS += darwin/btperipheralmanager_p.h
-
- OBJECTIVE_SOURCES += darwin/btperipheralmanager.mm
-}
diff --git a/src/bluetooth/darwin/uistrings.cpp b/src/bluetooth/darwin/uistrings.cpp
index 7260417f..9f93b23c 100644
--- a/src/bluetooth/darwin/uistrings.cpp
+++ b/src/bluetooth/darwin/uistrings.cpp
@@ -1,44 +1,10 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "uistrings_p.h"
+#include <qttranslation.h>
+
// Translatable messages should go into this .cpp file for them to
// be picked up by lupdate.
@@ -50,6 +16,7 @@ const char DD_INVALID_ADAPTER[] = QT_TRANSLATE_NOOP("QBluetoothDeviceDiscoveryAg
const char DD_IO[] = QT_TRANSLATE_NOOP("QBluetoothDeviceDiscoveryAgent", "Input Output Error");
const char DD_NOTSUPPORTED[] = QT_TRANSLATE_NOOP("QBluetoothDeviceDiscoveryAgent", "Bluetooth LE is not supported");
const char DD_UNKNOWN_ERROR[] = QT_TRANSLATE_NOOP("QBluetoothDeviceDiscoveryAgent", "Unknown error");
+const char DD_MISSING_PERMISSION[] = QT_TRANSLATE_NOOP("QBluetoothDeviceDiscoveryAgent", "Missing permission");
const char DD_NOT_STARTED[] = QT_TRANSLATE_NOOP("QBluetoothDeviceDiscoveryAgent", "Cannot start device inquiry");
const char DD_NOT_STARTED_LE[] = QT_TRANSLATE_NOOP("QBluetoothDeviceDiscoveryAgent", "Cannot start low energy device inquiry");
const char DD_NOT_STOPPED[] = QT_TRANSLATE_NOOP("QBluetoothDeviceDiscoveryAgent", "Discovery cannot be stopped");
@@ -84,5 +51,6 @@ const char LEC_RDEV_NO_FOUND[] = QT_TRANSLATE_NOOP("QLowEnergyController", "Remo
const char LEC_NO_LOCAL_DEV[] = QT_TRANSLATE_NOOP("QLowEnergyController", "Cannot find local adapter");
const char LEC_IO_ERROR[] = QT_TRANSLATE_NOOP("QLowEnergyController", "Error occurred during connection I/O");
const char LEC_UNKNOWN_ERROR[] = QT_TRANSLATE_NOOP("QLowEnergyController", "Unknown Error");
+const char LEC_MISSING_PERMISSION[] = QT_TRANSLATE_NOOP("QLowEnergyController", "Missing permission");
QT_END_NAMESPACE
diff --git a/src/bluetooth/darwin/uistrings_p.h b/src/bluetooth/darwin/uistrings_p.h
index 999a8c6d..11cfb24f 100644
--- a/src/bluetooth/darwin/uistrings_p.h
+++ b/src/bluetooth/darwin/uistrings_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef TRANSLATIONS_H
#define TRANSLATIONS_H
@@ -51,8 +15,9 @@
// We mean it.
//
-#include <QtCore/QCoreApplication>
-#include <QtCore/QString>
+#include <QtCore/qglobal.h>
+
+#include <QtCore/private/qglobal_p.h>
QT_BEGIN_NAMESPACE
@@ -63,6 +28,7 @@ extern const char DD_INVALID_ADAPTER[];
extern const char DD_IO[];
extern const char DD_NOTSUPPORTED[];
extern const char DD_UNKNOWN_ERROR[];
+extern const char DD_MISSING_PERMISSION[];
extern const char DD_NOT_STARTED[];
extern const char DD_NOT_STARTED_LE[];
extern const char DD_NOT_STOPPED[];
@@ -101,6 +67,7 @@ extern const char LEC_RDEV_NO_FOUND[];
extern const char LEC_NO_LOCAL_DEV[];
extern const char LEC_IO_ERROR[];
extern const char LEC_UNKNOWN_ERROR[];
+extern const char LEC_MISSING_PERMISSION[];
QT_END_NAMESPACE
diff --git a/src/bluetooth/doc/qt6-changes.qdoc b/src/bluetooth/doc/qt6-changes.qdoc
new file mode 100644
index 00000000..c22105e8
--- /dev/null
+++ b/src/bluetooth/doc/qt6-changes.qdoc
@@ -0,0 +1,141 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+ \page qtbluetooth-changes-qt6.html
+ \title Changes to Qt Bluetooth
+ \ingroup changes-qt-5-to-6
+ \brief Migrate QtBluetooth to Qt 6.
+
+ Qt 6 is a result of the conscious effort to make the framework more
+ efficient and easy to use.
+
+ We try to maintain binary and source compatibility for all the public
+ APIs in each release. But some changes were inevitable in an effort to
+ make Qt a better framework.
+
+ In this topic we summarize those changes in QtBluetooth, and provide guidance
+ to handle them.
+
+ \section1 General
+
+ \list
+ \li qbluetoothglobal.h was removed. qtbluetoothglobal.h is the official header with the same purpose.
+
+ \li Every usage of QVector has been replaced by QList.
+
+ \li Win32 backend has been removed. There will not be a working Bluetooth backend when Qt is built with mingw.
+
+ \li Since there is now only one Windows backend, the logging category qt.bluetooth.winrt was removed.
+ The corresponding log messages are now in qt.bluetooth.windows.
+ \endlist
+
+ \section1 QBluetooth namespace
+
+ The enums QBluetooth::Security and QBluetooth::AttAccessConstraint have been changed
+ to a scoped enums for improved type safety.
+
+ \section1 QBluetoothDeviceDiscoveryAgent
+
+ QBluetoothDeviceDiscoveryAgent::inquiryType property and related setter/getter & enum were removed.
+ The API element was never implemented and/or supported.
+
+ \section1 QBluetoothDeviceInfo
+
+ \list
+ \li manufacturerData() returns a QMultiHash rather than QHash. Since Qt 6
+ QMultiHash is no longer derived from QHash.
+
+ \li DataCompleteness was removed without replacement as the related API elements
+ no longer served a purpose
+
+ \li setServiceUuids(const QList<QBluetoothUuid>, DataCompleteness) was replaced by
+ setServiceUuids(const QList<QBluetoothUuid> &uuids)
+
+ \li DataCompleteness serviceUuidsCompleteness() const was removed without replacement.
+
+ \li QList<QBluetoothUuid> serviceUuids(DataCompleteness *completeness = nullptr) const was replaced by
+ QList<QBluetoothUuid> serviceUuids() const.
+ \endlist
+
+ \section1 QBluetoothLocalDevice
+
+ The pairing agent related API was removed without replacement. This includes pairingConfirmation(bool),
+ pairingDisplayPinCode(..) & pairingDisplayConfirmation(..). Except for Android and BlueZ 4 there was
+ never an implementation for it. Bluez 4 support was removed in Qt 6 and Android's implementation
+ required unobtainable BLUETOOTH_PRIVILEGED for at least parts of the code.
+
+ \section1 QLowEnergyService
+
+ Renamed ServiceState enum values:
+ \list
+ \li \l{QLowEnergyService::DiscoveryRequired}{DiscoveryRequired} becomes \l{QLowEnergyService::RemoteService}{RemoteService}
+ \li \l{QLowEnergyService::DiscoveringService}{DiscoveringService} becomes \l{QLowEnergyService::RemoteServiceDiscovering}{RemoteServiceDiscovering}
+ \li \l{QLowEnergyService::ServiceDiscovered}{ServiceDiscovered} becomes \l{QLowEnergyService::RemoteServiceDiscovered}{RemoteServiceDiscovered}
+ \endlist
+ This change happens in anticipation that service discovery might become an optional
+ step in the future.
+
+ \section1 QBluetoothUuid
+
+ enums \l{QBluetoothUuid::ProtocolUuid}{ProtocolUuid},
+ \l{QBluetoothUuid::ServiceClassUuid}{ServiceClassUuid},
+ \l{QBluetoothUuid::CharacteristicType}{CharacteristicType}, and
+ \l{QBluetoothUuid::DescriptorType}{DescriptorType} are now scoped enums.
+ The usage of enum items has to be adapted in user code.
+
+ \section1 QLowEnergyController
+
+ \list
+ \li Existing ctors and create*() functions with remote QBluetoothAddress parameters have been removed. QBluetoothAddress
+ is not sufficient to indicate remote devices on Apple systems. It requires UUIDs to "name" devices. This can only
+ be satisfied by QBluetoothDeviceInfo.
+
+ \li Remaining QLowEnergyController ctors have been made private. The createPeripheral() and createCentral() functions
+ should be used to obtain QLowEnergyController instances.
+ \endlist
+
+ \section1 QLowEnergyCharacteristic
+
+ \list
+ \li The new method clientCharacteristicConfiguration() has been introduced to conveniently obtain the
+ Client Characteristic Configuration Descriptor.
+ \li The constants
+ \l{QLowEnergyCharacteristic::CCCDDisable}{CCCDDisable},
+ \l{QLowEnergyCharacteristic::CCCDEnableNotification}{CCCDEnableNotification}, and
+ \l{QLowEnergyCharacteristic::CCCDEnableIndication}{CCCDEnableIndication} have been introduced
+ which hold the possible values for the Client Characteristic Configuration Descriptor.
+ \li The handle() method is no longer part of the public Bluetooth LE interfaces. It's purpose as identifier
+ for characteristics was replaced. The QLowEnergyCharacteristic instances itself serve as identifier.
+ \endlist
+
+ \section1 QLowEnergyDescriptor
+
+ The handle() method is no longer part of the public Bluetooth LE interfaces. It's purpose as identifier
+ for descriptors was replaced. The QLowEnergyDescriptor instances itself serve as identifier.
+
+ \section1 QBluetoothTransferManager
+
+ QBluetoothTransferManager, QBluetoothTransferRequest, and QBluetoothTransferReply have been removed
+ without replacement.
+
+ \section1 QBluetoothSocket
+
+ QBluetoothSocket::SocketState and QBluetoothSocket::SocketError are now scoped enums. The usage of enum
+ items has to be adapted in user code.
+
+ \section1 QML Interface
+
+ The QML interface has been removed because socket programming via QML is not advisable.
+ QDeclarativeBluetoothService, QDeclarativeBluetoothSocket, and QDeclarativeBluetoothDiscoveryModel
+ (in QML: BluetoothService, BluetoothSocket, and BluetoothDiscoveryModel)
+ have been removed without replacement.
+
+ \section1 "error" signals
+
+ The "error" signals in QBluetoothDeviceDiscoveryAgent, QBluetoothLocalDevice, QBluetoothServer,
+ QBluetoothServiceDiscoveryAgent, QBluetoothSocket, QLowEnergyController, and QLowEnergyService
+ have been renamed to "errorOccurred" to remove ambiguities between the "error" signal and the
+ "error" getter.
+
+*/
diff --git a/src/bluetooth/doc/qtbluetooth.qdocconf b/src/bluetooth/doc/qtbluetooth.qdocconf
index 9ee5a567..325897ce 100644
--- a/src/bluetooth/doc/qtbluetooth.qdocconf
+++ b/src/bluetooth/doc/qtbluetooth.qdocconf
@@ -15,18 +15,11 @@ qhp.QtBluetooth.virtualFolder = qtbluetooth
qhp.QtBluetooth.indexTitle = Qt Bluetooth
qhp.QtBluetooth.indexRoot =
-qhp.QtBluetooth.filterAttributes = qtbluetooth $QT_VERSION qtrefdoc
-qhp.QtBluetooth.customFilters.Qt.name = QtBluetooth $QT_VERSION
-qhp.QtBluetooth.customFilters.Qt.filterAttributes = qtbluetooth $QT_VERSION
-qhp.QtBluetooth.subprojects = overviews classes qml examples
+qhp.QtBluetooth.subprojects = overviews classes examples
qhp.QtBluetooth.subprojects.classes.title = C++ Classes
qhp.QtBluetooth.subprojects.classes.indexTitle = Qt Bluetooth C++ Classes
qhp.QtBluetooth.subprojects.classes.selectors = class fake:headerfile
qhp.QtBluetooth.subprojects.classes.sortPages = true
-qhp.QtBluetooth.subprojects.qml.title = QML Types
-qhp.QtBluetooth.subprojects.qml.indexTitle = Qt Bluetooth QML Types
-qhp.QtBluetooth.subprojects.qml.selectors = fake:headerfile
-qhp.QtBluetooth.subprojects.qml.sortPages = true
qhp.QtBluetooth.subprojects.overviews.title = Overviews
qhp.QtBluetooth.subprojects.overviews.indexTitle = Qt Bluetooth Overview
qhp.QtBluetooth.subprojects.overviews.selectors = fake:page,group,module
@@ -36,23 +29,26 @@ qhp.QtBluetooth.subprojects.examples.selectors = fake:example
tagfile = ../../../doc/qtbluetooth/qtbluetooth.tags
-depends += qtcore qtdoc qtquick
+depends += qtcore qtgui qtwidgets qtdoc qtquick qtcmake qmake
-headerdirs += .. \
- ../../imports/bluetooth
+headerdirs += ..
-sourcedirs += .. \
- ../../imports/bluetooth \
+sourcedirs += ..
exampledirs += ../../../examples/bluetooth \
snippets/ \
../
-manifestmeta.thumbnail.names = "QtBluetooth/Bluetooth Low Energy Heart Rate Server Example"
-manifestmeta.highlighted.names += "QtBluetooth/Bluetooth Low Energy Heart Rate Game"
+manifestmeta.thumbnail.names = "QtBluetooth/Bluetooth Low Energy Heart Rate Server"
+
+manifestmeta.highlighted.names = \
+ "QtBluetooth/Bluetooth Low Energy Heart Rate Game" \
+ "QtBluetooth/Bluetooth Low Energy Scanner"
imagedirs += images
navigation.landingpage = "Qt Bluetooth"
navigation.cppclassespage = "Qt Bluetooth C++ Classes"
-navigation.qmltypespage = "Qt Bluetooth QML Types"
+
+# Enforce zero documentation warnings
+warninglimit = 0
diff --git a/src/bluetooth/doc/snippets/CMakeLists.txt b/src/bluetooth/doc/snippets/CMakeLists.txt
new file mode 100644
index 00000000..50fd10c5
--- /dev/null
+++ b/src/bluetooth/doc/snippets/CMakeLists.txt
@@ -0,0 +1,7 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+# ![0]
+find_package(Qt6 REQUIRED COMPONENTS Bluetooth)
+target_link_libraries(mytarget PRIVATE Qt6::Bluetooth)
+# ![0]
diff --git a/src/bluetooth/doc/snippets/doc_src_qtbluetooth.cpp b/src/bluetooth/doc/snippets/doc_src_qtbluetooth.cpp
index a2c4d8b1..fa57b0cb 100644
--- a/src/bluetooth/doc/snippets/doc_src_qtbluetooth.cpp
+++ b/src/bluetooth/doc/snippets/doc_src_qtbluetooth.cpp
@@ -1,52 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//! [include]
#include <QtBluetooth/QBluetoothLocalDevice>
@@ -57,9 +10,6 @@
#include <QtCore/QObject>
#include <QtBluetooth/QBluetoothDeviceDiscoveryAgent>
#include <QtBluetooth/QBluetoothServiceDiscoveryAgent>
-#include <QtBluetooth/QBluetoothTransferManager>
-#include <QtBluetooth/QBluetoothTransferRequest>
-#include <QtBluetooth/QBluetoothTransferReply>
#include <QtBluetooth/QLowEnergyController>
#include <QtBluetooth/QLowEnergyService>
@@ -84,8 +34,6 @@ public:
public slots:
void deviceDiscovered(const QBluetoothDeviceInfo &device);
void serviceDiscovered(const QBluetoothServiceInfo &service);
- void transferFinished(QBluetoothTransferReply* reply);
- void error(QBluetoothTransferReply::TransferError errorType);
void characteristicChanged(const QLowEnergyCharacteristic& ,const QByteArray&);
};
@@ -160,40 +108,6 @@ void MyClass::serviceDiscovered(const QBluetoothServiceInfo &service)
}
//! [service_discovery]
-void MyClass::objectPush()
-{
-//! [sendfile]
-// Create a transfer manager
-QBluetoothTransferManager *transferManager = new QBluetoothTransferManager(this);
-
-// Create the transfer request and file to be sent
-QBluetoothAddress remoteAddress("00:11:22:33:44:55:66");
-QBluetoothTransferRequest request(remoteAddress);
-QFile *file = new QFile("testfile.txt");
-
-// Ask the transfer manager to send it
-QBluetoothTransferReply *reply = transferManager->put(request, file);
-if (reply->error() == QBluetoothTransferReply::NoError) {
-
- // Connect to the reply's signals to be informed about the status and do cleanups when done
- QObject::connect(reply, SIGNAL(finished(QBluetoothTransferReply*)),
- this, SLOT(transferFinished(QBluetoothTransferReply*)));
- QObject::connect(reply, SIGNAL(error(QBluetoothTransferReply::TransferError)),
- this, SLOT(error(QBluetoothTransferReply::TransferError)));
-} else {
- qWarning() << "Cannot push testfile.txt:" << reply->errorString();
-}
-//! [sendfile]
-}
-
-void MyClass::transferFinished(QBluetoothTransferReply* /*reply*/)
-{
-}
-
-void MyClass::error(QBluetoothTransferReply::TransferError /*errorType*/)
-{
-}
-
void MyClass::characteristicChanged(const QLowEnergyCharacteristic &, const QByteArray &)
{
}
@@ -209,14 +123,14 @@ void MyClass::btleSharedData()
// waiting for connection
- first = control.createServiceObject(QBluetoothUuid::BatteryService);
- second = control.createServiceObject(QBluetoothUuid::BatteryService);
- Q_ASSERT(first->state() == QLowEnergyService::DiscoveryRequired);
+ first = control.createServiceObject(QBluetoothUuid::ServiceClassUuid::BatteryService);
+ second = control.createServiceObject(QBluetoothUuid::ServiceClassUuid::BatteryService);
+ Q_ASSERT(first->state() == QLowEnergyService::RemoteService);
Q_ASSERT(first->state() == second->state());
first->discoverDetails();
- Q_ASSERT(first->state() == QLowEnergyService::DiscoveringServices);
+ Q_ASSERT(first->state() == QLowEnergyService::RemoteServiceDiscovering);
Q_ASSERT(first->state() == second->state());
//! [data_share_qlowenergyservice]
}
@@ -229,7 +143,7 @@ void MyClass::enableCharNotifications()
control->connectToDevice();
- service = control->createServiceObject(QBluetoothUuid::BatteryService, this);
+ service = control->createServiceObject(QBluetoothUuid::ServiceClassUuid::BatteryService, this);
if (!service)
return;
@@ -240,12 +154,12 @@ void MyClass::enableCharNotifications()
//! [enable_btle_notifications]
//PreCondition: service details already discovered
QLowEnergyCharacteristic batteryLevel = service->characteristic(
- QBluetoothUuid::BatteryLevel);
+ QBluetoothUuid::CharacteristicType::BatteryLevel);
if (!batteryLevel.isValid())
return;
QLowEnergyDescriptor notification = batteryLevel.descriptor(
- QBluetoothUuid::ClientCharacteristicConfiguration);
+ QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration);
if (!notification.isValid())
return;
diff --git a/src/bluetooth/doc/snippets/doc_src_qtbluetooth.qml b/src/bluetooth/doc/snippets/doc_src_qtbluetooth.qml
deleted file mode 100644
index 8508a9e4..00000000
--- a/src/bluetooth/doc/snippets/doc_src_qtbluetooth.qml
+++ /dev/null
@@ -1,78 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-//! [import]
-import QtBluetooth 5.12
-//! [import]
-
-//! [service]
- // The socket via which communication to remote host happens
- BluetoothSocket {
- id: bluetoothSocket
-
- onConnectedChanged: {
- console.log("bluetoothSocket status: " + connected)
- if (connected) {
- titleRow.title = "Connected";
-
- // Send some data to the remote device
- stringData = "Hello there!";
-
- } else {
- titleRow.title = "Disconnected";
- }
- }
-
- // read incoming data from the remote device
- onDataAvailable: {
- print("received data:", stringData);
- }
- }
-//! [service]
diff --git a/src/bluetooth/doc/snippets/snippets.pro b/src/bluetooth/doc/snippets/snippets.pro
index f59983ee..7ad0c443 100644
--- a/src/bluetooth/doc/snippets/snippets.pro
+++ b/src/bluetooth/doc/snippets/snippets.pro
@@ -1,8 +1,3 @@
-TEMPLATE = app
-TARGET = bluetooth_cppsnippet
-QT = core
#! [contacts project modification]
QT += bluetooth
#! [contacts project modification]
-
-SOURCES += doc_src_qtbluetooth.cpp
diff --git a/src/bluetooth/doc/src/bluetooth-cpp.qdoc b/src/bluetooth/doc/src/bluetooth-cpp.qdoc
index 26cd060b..958609bf 100644
--- a/src/bluetooth/doc/src/bluetooth-cpp.qdoc
+++ b/src/bluetooth/doc/src/bluetooth-cpp.qdoc
@@ -1,29 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt local connectivty modules.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\module QtBluetooth
@@ -36,8 +12,7 @@
The \l{Qt Bluetooth} C++ API enables an application to scan for devices and
- connect and interact with them in a more flexible way than the \l {Qt
- Bluetooth QML Types}.
+ connect and interact with them in a more flexible way.
To use the C++ library in your application, add the following configuration
option to your \c .pro file:
diff --git a/src/bluetooth/doc/src/bluetooth-index.qdoc b/src/bluetooth/doc/src/bluetooth-index.qdoc
index 0f5b96d6..ff6bf037 100644
--- a/src/bluetooth/doc/src/bluetooth-index.qdoc
+++ b/src/bluetooth/doc/src/bluetooth-index.qdoc
@@ -1,29 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\page qtbluetooth-index.html
@@ -40,10 +16,9 @@ Currently, the API is supported on the following platforms:
\li API Feature
\li \l {Qt for Android}{Android}
\li \l {Qt for iOS}{iOS}
- \li \l {Qt for Linux/X11}{Linux (BlueZ 4.x/5.x)}
+ \li \l {Qt for Linux/X11}{Linux (BlueZ 5.x)}
\li \l \macos
- \li \l {Qt for UWP}{UWP (Universal Windows Platform)}
- \li \l {Qt for Windows}{Win32}
+ \li \l {Qt for Windows}{Windows}
\row
\li Classic Bluetooth
\li x
@@ -51,7 +26,6 @@ Currently, the API is supported on the following platforms:
\li x
\li x
\li x
- \li x
\row
\li Bluetooth LE Central
\li x
@@ -59,7 +33,6 @@ Currently, the API is supported on the following platforms:
\li x
\li x
\li x
- \li x
\row
\li Bluetooth LE Peripheral
\li x
@@ -67,67 +40,86 @@ Currently, the API is supported on the following platforms:
\li x
\li x
\li
- \li
-\row
- \li Bluetooth LE Advertisement & Scanning
- \li
- \li
- \li
- \li
- \li
- \li
\endtable
-Qt 5.14 adds a native Win32 port supporting Classic Bluetooth on Windows 7 or newer,
-and Bluetooth LE on Windows 8 or newer. It must be enabled at build time by configuration
-option -native-win32-bluetooth. The UWP backend is used by default if this option is not
-set and the Win32 target platform supports the required UWP APIs (minimal requirement is
-Windows 10 version 1507, with slightly improved service discovery since Windows 10 version
-1607).
-
\section1 Overview
Bluetooth is a short-range (less than 100 meters) wireless technology. It
-has a reasonably high data transfer rate of 2.1 Mbit/s, which makes it ideal
+has a data transfer rate of 2.1 Mbps, which makes it ideal
for transferring data between devices. Bluetooth connectivity is based on
basic device management, such as scanning for devices, gathering information
about them, and exchanging data between them.
-Qt Bluetooth supports Bluetooth Low Energy development for client/central role use cases.
-Further details can be found in the
+Qt Bluetooth supports Bluetooth Low Energy development for client/central role
+use cases. Further details can be found in the
\l {Bluetooth Low Energy Overview}{Bluetooth Low Energy Overview} section.
-A new addition since the Qt Bluetooth 5.7 release covers support for Bluetooth Low Energy
-applications performing the peripheral/server role. This new API remains in Technology Preview.
+\section1 Using the Module
+
+\include {module-use.qdocinc} {using the c++ api}
+
+\section2 Building with CMake
-\section1 Getting Started
+\include {module-use.qdocinc} {building with cmake} {Bluetooth}
-To use the C++ library in your application, add the following configuration
-option to your \c .pro file:
+\section2 Building with qmake
-\snippet snippets.pro contacts project modification
+\include {module-use.qdocinc} {building_with_qmake} {bluetooth}
-To use the classes of the module in your application you need the following
-import statement in your \c .qml file:
+\section1 Permissions
-\snippet doc_src_qtbluetooth.qml import
+Starting from Qt 6.6, the Qt Bluetooth module uses new \l QPermission API
+to handle \l {QBluetoothPermission}{Bluetooth} permissions. This means that Qt
+itself no longer queries for these permissions, so this needs to be done
+directly from the client application.
+
+Please refer to the \l {Application Permissions} page for an example of how
+to integrate the new \l QPermission API into the application.
\section1 Related Information
\section2 Building Qt Bluetooth
-Despite the fact that the module can be built for all Qt platforms,
-the module is not ported to all of them. Not supported platforms
-employ a fake or dummy backend which is automatically selected when the
-platform is not supported. The dummy backend reports appropriate error messages
-and values which allow the Qt Bluetooth developer to detect at runtime that the
-current platform is not supported. The dummy backend is also selected on Linux if
-BlueZ development headers are not found during build time or Qt was built without
-Qt D-Bus support.
+Even though the module can be built for all Qt platforms, the module is not
+ported to all of them. Non-supported platforms employ a dummy backend that is
+automatically selected when the platform is not supported. The dummy backend
+reports appropriate error messages and values, which enables you to detect at
+runtime that the current platform is not supported. The dummy backend is also
+selected on Linux if BlueZ development headers are not found during build time
+or Qt was built without Qt D-Bus support.
The usage of the dummy backend is highlighted via an appropriate warning while building and running.
-\section2 Guides
+\section3 Linux Specific
+
+Since Qt 6.5 the Linux peripheral support has two backend alternatives:
+BlueZ DBus and Bluetooth Kernel API. The DBus backend is the default
+backend since Qt 6.7.
+
+BlueZ DBus is the newer BlueZ stack and possibly the eventual successor of the
+older Kernel API. It is a bit more limited in terms of features, but in a
+typical usage this should not matter. One notable benefit of using the DBus
+backend is that the user process no longer needs to have the
+\e CAP_NET_ADMIN capability (for example by running as \c root user).
+
+The DBus backend requires BlueZ version 5.56 or higher, and that it provides
+the needed DBus APIs. If these requirements are not met, Qt automatically
+falls back to the Bluetooth Kernel API backend.
+
+The older kernel backend can also be selected manually by setting the
+\e QT_BLUETOOTH_USE_KERNEL_PERIPHERAL environment variable.
+
+\section3 \macos Specific
+The Bluetooth API on \macos requires a certain type of event dispatcher
+that in Qt causes a dependency to \l QGuiApplication. However, you can set the
+environment variable \c {QT_EVENT_DISPATCHER_CORE_FOUNDATION=1} to circumvent
+this issue.
+
+Applications that don't use Classic Bluetooth will find a subset of QtBluetooth
+is available, as CoreBluetooth (Bluetooth LE) don't require \l QApplication or
+\l QGuiApplication.
+
+\section2 Articles and Guides
\list
\li \l {Qt Bluetooth Overview}{Classic Bluetooth Overview}
\li \l {Bluetooth Low Energy Overview}
@@ -135,7 +127,6 @@ The usage of the dummy backend is highlighted via an appropriate warning while b
\section2 Reference
\list
- \li \l {Qt Bluetooth QML Types}{QML Types}
\li \l {Qt Bluetooth C++ Classes}{C++ Classes}
\endlist
@@ -164,20 +155,14 @@ The \l QtBluetooth module exports the following
\li qt.bluetooth.osx
\li Enables logging of the \l {Qt for macOS} {macOS} implementation
\row
- \li qt.bluetooth.qml
- \li Enables logging of the QtBluetooth QML implementation
-\row
- \li qt.bluetooth.winrt
- \li Enables logging of the \l {Qt for UWP}{UWP (Universal Windows Platform)}
- implementation
-\row
\li qt.bluetooth.windows
- \li Enables logging of the \l {Qt for Windows} {Win32} implementation
+ \li Enables logging of the \l {Qt for Windows} {Windows} implementation
\endtable
-Logging categories can be used to enable additional warning and debug output
-for QtBluetooth. More detailed information about logging can be found in \l QLoggingCategory.
-A quick way to enable all QtBluetooth logging is to add the following line to the \c main() function:
+Logging categories enable additional warning and debug output for QtBluetooth.
+More detailed information about logging is found in \l QLoggingCategory. A
+quick way to enable all QtBluetooth logging is to add the following line to the
+\c main() function:
\code
QLoggingCategory::setFilterRules(QStringLiteral("qt.bluetooth* = true"));
@@ -187,10 +172,6 @@ A quick way to enable all QtBluetooth logging is to add the following line to th
\list
\li QML
\list
- \li \l {scanner}{QML Bluetooth Scanner}
- \li \l {picturetransfer}{QML Bluetooth Picture Push}
- \li \l {pingpong}{QML Bluetooth PingPong}
- \li \l {chat}{QML Bluetooth Chat}
\li \l {heartrate-game}{Bluetooth Low Energy Heart Rate Game}
\li \l {heartrate-server}{Bluetooth Low Energy Heart Rate Server}
\li \l {lowenergyscanner}{Bluetooth Low Energy Scanner}
@@ -198,11 +179,14 @@ A quick way to enable all QtBluetooth logging is to add the following line to th
\li C++
\list
\li \l {btchat}{Bluetooth Chat}
- \li \l {btscanner}{Bluetooth Scanner}
- \li \l {btfiletransfer}{Bluetooth File Transfer}
\endlist
\endlist
+\section1 Module Evolution
+
+\l{Changes to Qt Bluetooth} lists important changes in the module
+API and functionality that were done for the Qt 6 series of Qt.
+
\section1 Licenses and Attributions
Qt Bluetooth is available under commercial licenses from \l{The Qt Company}.
diff --git a/src/bluetooth/doc/src/bluetooth-le-overview.qdoc b/src/bluetooth/doc/src/bluetooth-le-overview.qdoc
index 60181240..cc943088 100644
--- a/src/bluetooth/doc/src/bluetooth-le-overview.qdoc
+++ b/src/bluetooth/doc/src/bluetooth-le-overview.qdoc
@@ -1,29 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt local connectivty modules.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\ingroup technology-apis
@@ -34,11 +10,9 @@ Low Energy devices.
\tableofcontents
- The Qt Bluetooth Low Energy API for the central role was introduced by Qt 5.4.
- Since Qt 5.5 that part of the API is final and a compatibility guarantee is given for
- future releases.
- Since Qt 5.7, additional API supporting the peripheral role was added as a Technology Preview,
- with the backend implemented for Linux/BlueZ, iOS and macOS.
+ The Qt Bluetooth Low Energy API supports the peripheral/server and central/client roles.
+ It is supported on all major Qt platforms. The only exception is the missing peripheral role
+ support on Windows.
\section1 What Is Bluetooth Low Energy
@@ -120,7 +94,7 @@ Low Energy devices.
\row
\li 0x0004
\li 0x2803
- \li UUID 0x2A08, Value handle: 0x0006
+ \li UUID 0x2A08, Value handle: 0x0005
\li Characteristic of type Date Time
\row
\li 0x0005
@@ -146,7 +120,7 @@ Low Energy devices.
The example above uses the UUIDs \c 0x2A08 (Date Time) and \c 0x2A37 (Heart Rate Measurement).
Each of the above UUIDs is defined by the \l {https://bluetooth.org}{Bluetooth Special Interest Group}.
and can be found in the
- \l{https://developer.bluetooth.org/gatt/Pages/default.aspx}{GATT specification}. While it
+ \l{https://www.bluetooth.com/specifications/assigned-numbers}{GATT specifications}. While it
is advisable to use pre-defined UUIDs where available it is entirely possible to use new and not
yet used UUIDs for characteristic and service types.
@@ -181,7 +155,10 @@ Low Energy devices.
Since we are only interested in Low Energy devices we filter the device type within the
receiving slot. The device type can be ascertained using the \l QBluetoothDeviceInfo::coreConfigurations()
- flag:
+ flag. The \l {QBluetoothDeviceDiscoveryAgent::}{deviceDiscovered()} signal
+ may be emitted multiple times for the same device as more details are
+ discovered. Here we match these device discoveries so that the user only
+ sees the individual devices:
\snippet heartrate-game/devicefinder.cpp devicediscovery-3
\snippet heartrate-game/devicefinder.cpp devicediscovery-4
@@ -197,13 +174,13 @@ Low Energy devices.
\section2 Service Search
- The above code snippet how the application initiates the service discovery once the connection has
- been established.
+ The above code snippet shows how the application initiates the service discovery once the
+ connection has been established.
The \c serviceDiscovered() slot below is triggered as a result of the
\l {QLowEnergyController::serviceDiscovered()} signal and provides an intermittent progress report.
Since we are talking about the heart listener app which monitors HeartRate devices in the vicinity
- we ignore any service that is not of type \l QBluetoothUuid::HeartRate.
+ we ignore any service that is not of type \l QBluetoothUuid::ServiceClassUuid::HeartRate.
\snippet heartrate-game/devicehandler.cpp Filter HeartRate service 1
@@ -216,21 +193,21 @@ Low Energy devices.
\snippet heartrate-game/devicehandler.cpp Filter HeartRate service 2
During the detail search the service's \l {QLowEnergyService::state()}{state()} transitions
- from \l {QLowEnergyService::DiscoveryRequired}{DiscoveryRequired} to
- \l {QLowEnergyService::DiscoveringServices}{DiscoveringServices} and eventually ends with
- \l {QLowEnergyService::ServiceDiscovered}{ServiceDiscovered}:
+ from \l {QLowEnergyService::RemoteService}{RemoteService} to
+ \l {QLowEnergyService::RemoteServiceDiscovering}{RemoteServiceDiscovering} and eventually ends with
+ \l {QLowEnergyService::RemoteServiceDiscovered}{RemoteServiceDiscovered}:
\snippet heartrate-game/devicehandler.cpp Find HRM characteristic
\section2 Interaction with the Peripheral Device
In the code example above, the desired characteristic is of type
- \l {QBluetoothUuid::HeartRateMeasurement}{HeartRateMeasurement}. Since the application measures
+ \l {QBluetoothUuid::CharacteristicType::HeartRateMeasurement}{HeartRateMeasurement}. Since the application measures
the heart rate changes, it must enable change notifications for the characteristic.
Note that not all characteristics provide change notifications. Since the HeartRate characteristic
has been standardized it is possible to assume that notifications can be received. Ultimately
\l QLowEnergyCharacteristic::properties() must have the \l {QLowEnergyCharacteristic::Notify} flag
- set and a descriptor of type \l {QBluetoothUuid::ClientCharacteristicConfiguration} must exist to confirm
+ set and a descriptor of type \l {QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration} must exist to confirm
the availability of an appropriate notification.
Finally, we process the value of the HeartRate characteristic, as per Bluetooth Low Energy standard:
@@ -286,4 +263,11 @@ Low Energy devices.
In general characteristic and descriptor value updates on the peripheral device use the same
methods as connecting Bluetooth Low Energy devices.
+
+ \note To use \l{Qt Bluetooth} (in both central and peripheral roles) on iOS, you have to provide
+ an Info.plist file containing the usage description. According to the CoreBluetooth's
+ documentation: \e {Your app will crash if its Info.plist doesn’t include usage description
+ keys for the types of data it needs to access. To access Core Bluetooth APIs on apps linked
+ on or after iOS 13, include the NSBluetoothAlwaysUsageDescription key. In iOS 12 and earlier,
+ include NSBluetoothPeripheralUsageDescription to access Bluetooth peripheral data.}
*/
diff --git a/src/bluetooth/doc/src/bluetooth-overview.qdoc b/src/bluetooth/doc/src/bluetooth-overview.qdoc
index 33ccaa33..54a429dc 100644
--- a/src/bluetooth/doc/src/bluetooth-overview.qdoc
+++ b/src/bluetooth/doc/src/bluetooth-overview.qdoc
@@ -1,29 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt local connectivty modules.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\ingroup technology-apis
@@ -49,12 +25,13 @@
Note that the Object Push Profile is not supported on Android and Windows.
- Note that parts of RFCOMM functionality cannot be configured by Qt on Windows.
- A service's \l {ServiceClassIds} and \l {ProtocolDescriptorList} are filled automatically by
- Windows. Therefore registering a service with custom values for these fields might not yield the
- expected result on Windows.
+ \note Parts of RFCOMM functionality cannot be configured by Qt on
+ Windows. A service's \l {QBluetoothServiceInfo::}{ServiceClassIds} and
+ \l {QBluetoothServiceInfo::}{ProtocolDescriptorList} are filled
+ automatically. Therefore, registering a service with custom values for
+ these fields might not yield the expected result on Windows.
- Note that the Received Signal Strength Indicator (RSSI), as well as
+ \note The Received Signal Strength Indicator (RSSI), as well as
the Manufacturer Specific Data advertised by Bluetooth LE devices are
not supported by the Win32 backend. Also, it is only possible to find
devices that have been previously paired through Windows Settings.
@@ -81,18 +58,6 @@
\snippet doc_src_qtbluetooth.cpp device_discovery
- \section1 Pushing Files to Remote Devices
-
- Once the desired device was found, there are two main use cases provided by Qt Bluetooth. The
- simpler one is to send files via the Obex Object Push Profile (OPP). As the name describes, this
- profile can push files from one device to another. Currently it is not possible to pull files
- or browse the remote file system. The profile does not require the two devices to be
- paired before exchanging data. To push files to remote devices, create a
- QBluetoothTransferRequest and ask the QBluetoothTransferManager to push the file contained in
- the request by calling its \l {QBluetoothTransferManager::put()}{put()} function.
-
- \snippet doc_src_qtbluetooth.cpp sendfile
-
\section1 Exchanging Data Between Devices
The more flexible approach for communication between two Bluetooth enabled devices, is to
diff --git a/src/bluetooth/doc/src/bluetooth-qml.qdoc b/src/bluetooth/doc/src/bluetooth-qml.qdoc
deleted file mode 100644
index a6870864..00000000
--- a/src/bluetooth/doc/src/bluetooth-qml.qdoc
+++ /dev/null
@@ -1,48 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt local connectivty modules.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-
-/*!
-
-\qmlmodule QtBluetooth \QtVer
-\title Qt Bluetooth QML Types
-\ingroup qmlmodules
-\brief Provides QML types for basic Bluetooth operations on devices.
-
-The Qt Bluetooth QML Types enable an application to scan for devices and connect
-and interact with them in an easier way than the C++ Classes. However, it is a bit
-more limited than the C++ API. You can always use the C++ API to create QML
-plugins with the flexibility you need.
-
-To use the classes of the module in your application you need the following
-import statement in your \c .qml file:
-
-\qml \QtVer
-import QtBluetooth \1
-\endqml
-*/
-
diff --git a/src/bluetooth/doc/src/examples.qdoc b/src/bluetooth/doc/src/examples.qdoc
index e33ae4d8..46425cf6 100644
--- a/src/bluetooth/doc/src/examples.qdoc
+++ b/src/bluetooth/doc/src/examples.qdoc
@@ -1,32 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
- \ingroup all-examples
\page bluetooth-examples.html
\title Qt Bluetooth Examples
\brief Examples for the Qt Bluetooth module.
@@ -47,12 +22,6 @@
\row
\li \l{btchat}{Bluetooth Chat}
\li Simple chat server and client via Bluetooth.
- \row
- \li \l{btfiletransfer}{Bluetooth File Transfer}
- \li Transfer files between Bluetooth devices.
- \row
- \li \l{btscanner}{Bluetooth Scanner}
- \li Scan for Bluetooth devices.
\endtable
\section2 QML Examples
@@ -61,18 +30,6 @@
\li Example
\li Description
\row
- \li \l{chat}{QML Bluetooth Chat Example}
- \li Simple chat client via Bluetooth.
- \row
- \li \l{picturetransfer}{QML Bluetooth Picture Push Example}
- \li Transfer pictures between Bluetooth devices.
- \row
- \li \l{pingpong}{QML Bluetooth PingPong}
- \li Ping pong game demonstrating Bluetooth socket communication between two devices.
- \row
- \li \l{scanner}{QML Bluetooth Scanner}
- \li Scan for Bluetooth devices and services.
- \row
\li \l{heartrate-game}{QML Bluetooth Low Energy Heart Rate Game}
\li Connect to Bluetooth Low Energy heart rate belts and receive
measurements such as the current pulse.
diff --git a/src/bluetooth/dummy/dummy.pri b/src/bluetooth/dummy/dummy.pri
deleted file mode 100644
index 49aa076c..00000000
--- a/src/bluetooth/dummy/dummy.pri
+++ /dev/null
@@ -1,2 +0,0 @@
-HEADERS += dummy/dummy_helper_p.h
-SOURCES += dummy/dummy_helper.cpp
diff --git a/src/bluetooth/dummy/dummy_helper.cpp b/src/bluetooth/dummy/dummy_helper.cpp
index 144ec7d6..a9257030 100644
--- a/src/bluetooth/dummy/dummy_helper.cpp
+++ b/src/bluetooth/dummy/dummy_helper.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtCore/QGlobalStatic>
#include <QtCore/QLoggingCategory>
diff --git a/src/bluetooth/dummy/dummy_helper_p.h b/src/bluetooth/dummy/dummy_helper_p.h
index 0c51770b..c51fa916 100644
--- a/src/bluetooth/dummy/dummy_helper_p.h
+++ b/src/bluetooth/dummy/dummy_helper_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef DUMMY_HELPER_H
#define DUMMY_HELPER_H
@@ -51,7 +15,7 @@
// We mean it.
//
-#include "QtCore/qglobal.h"
+#include "QtCore/private/qglobal_p.h"
QT_BEGIN_NAMESPACE
diff --git a/src/bluetooth/lecmaccalculator.cpp b/src/bluetooth/lecmaccalculator.cpp
index 475e46a8..92b9c35c 100644
--- a/src/bluetooth/lecmaccalculator.cpp
+++ b/src/bluetooth/lecmaccalculator.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "lecmaccalculator_p.h"
#include "bluez/bluez_data_p.h"
@@ -91,17 +55,17 @@ QByteArray LeCmacCalculator::createFullMessage(const QByteArray &message, quint3
{
// Spec v4.2, Vol 3, Part H, 2.4.5
QByteArray fullMessage = message;
- fullMessage.resize(fullMessage.count() + sizeof signCounter);
- putBtData(signCounter, fullMessage.data() + message.count());
+ fullMessage.resize(fullMessage.size() + sizeof signCounter);
+ putBtData(signCounter, fullMessage.data() + message.size());
return fullMessage;
}
-quint64 LeCmacCalculator::calculateMac(const QByteArray &message, const quint128 &csrk) const
+quint64 LeCmacCalculator::calculateMac(const QByteArray &message, QUuid::Id128Bytes csrk) const
{
#ifdef CONFIG_LINUX_CRYPTO_API
if (m_baseSocket == -1)
return false;
- quint128 csrkMsb;
+ QUuid::Id128Bytes csrkMsb;
std::reverse_copy(std::begin(csrk.data), std::end(csrk.data), std::begin(csrkMsb.data));
qCDebug(QT_BT_BLUEZ) << "CSRK (MSB):" << QByteArray(reinterpret_cast<char *>(csrkMsb.data),
sizeof csrkMsb).toHex();
@@ -129,19 +93,19 @@ quint64 LeCmacCalculator::calculateMac(const QByteArray &message, const quint128
return 0;
}
- QByteArray messageSwapped(message.count(), Qt::Uninitialized);
+ QByteArray messageSwapped(message.size(), Qt::Uninitialized);
std::reverse_copy(message.begin(), message.end(), messageSwapped.begin());
qint64 totalBytesWritten = 0;
do {
const qint64 bytesWritten = qt_safe_write(cryptoSocket.value(),
messageSwapped.constData() + totalBytesWritten,
- messageSwapped.count() - totalBytesWritten);
+ messageSwapped.size() - totalBytesWritten);
if (bytesWritten == -1) {
qCWarning(QT_BT_BLUEZ) << "writing to crypto socket failed:" << strerror(errno);
return 0;
}
totalBytesWritten += bytesWritten;
- } while (totalBytesWritten < messageSwapped.count());
+ } while (totalBytesWritten < messageSwapped.size());
quint64 mac;
quint8 * const macPtr = reinterpret_cast<quint8 *>(&mac);
qint64 totalBytesRead = 0;
@@ -163,7 +127,7 @@ quint64 LeCmacCalculator::calculateMac(const QByteArray &message, const quint128
#endif
}
-bool LeCmacCalculator::verify(const QByteArray &message, const quint128 &csrk,
+bool LeCmacCalculator::verify(const QByteArray &message, QUuid::Id128Bytes csrk,
quint64 expectedMac) const
{
#ifdef CONFIG_LINUX_CRYPTO_API
diff --git a/src/bluetooth/lecmaccalculator_p.h b/src/bluetooth/lecmaccalculator_p.h
index 1777f637..b79c5444 100644
--- a/src/bluetooth/lecmaccalculator_p.h
+++ b/src/bluetooth/lecmaccalculator_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef LECMACCALCULATOR_H
#define LECMACCALCULATOR_H
@@ -50,12 +14,11 @@
// We mean it.
//
-#include <QtCore/qglobal.h>
+#include <QtCore/private/qglobal_p.h>
+#include <QtCore/quuid.h>
QT_BEGIN_NAMESPACE
-struct quint128;
-
class Q_AUTOTEST_EXPORT LeCmacCalculator
{
public:
@@ -64,10 +27,10 @@ public:
static QByteArray createFullMessage(const QByteArray &message, quint32 signCounter);
- quint64 calculateMac(const QByteArray &message, const quint128 &csrk) const;
+ quint64 calculateMac(const QByteArray &message, QUuid::Id128Bytes csrk) const;
// Convenience function.
- bool verify(const QByteArray &message, const quint128 &csrk, quint64 expectedMac) const;
+ bool verify(const QByteArray &message, QUuid::Id128Bytes csrk, quint64 expectedMac) const;
private:
int m_baseSocket = -1;
diff --git a/src/bluetooth/osx/osxbt.pri b/src/bluetooth/osx/osxbt.pri
deleted file mode 100644
index edc1c751..00000000
--- a/src/bluetooth/osx/osxbt.pri
+++ /dev/null
@@ -1,61 +0,0 @@
-SOURCES += osx/uistrings.cpp \
- osx/osxbtnotifier.cpp \
- osx/btdelegates.cpp
-
-HEADERS += osx/uistrings_p.h \
- osx/osxbtgcdtimer_p.h \
- osx/btraii_p.h \
- osx/btdelegates_p.h
-
-
-OBJECTIVE_SOURCES += osx/osxbtgcdtimer.mm \
- osx/btraii.mm
-#QMAKE_CXXFLAGS_WARN_ON += -Wno-nullability-completeness
-
-CONFIG(osx) {
- HEADERS += osx/osxbtutility_p.h \
- osx/osxbtdevicepair_p.h \
- osx/osxbtdeviceinquiry_p.h \
- osx/osxbtconnectionmonitor_p.h \
- osx/osxbtsdpinquiry_p.h \
- osx/osxbtrfcommchannel_p.h \
- osx/osxbtl2capchannel_p.h \
- osx/osxbtservicerecord_p.h \
- osx/osxbtsocketlistener_p.h \
- osx/osxbtobexsession_p.h \
- osx/osxbtledeviceinquiry_p.h \
- osx/osxbluetooth_p.h \
- osx/osxbtcentralmanager_p.h \
- osx/osxbtnotifier_p.h \
- osx/osxbtperipheralmanager_p.h
-
- OBJECTIVE_SOURCES += osx/osxbtutility.mm \
- osx/osxbtdevicepair.mm \
- osx/osxbtdeviceinquiry.mm \
- osx/osxbtconnectionmonitor.mm \
- osx/osxbtsdpinquiry.mm \
- osx/osxbtrfcommchannel.mm \
- osx/osxbtl2capchannel.mm \
- osx/osxbtservicerecord.mm \
- osx/osxbtsocketlistener.mm \
- osx/osxbtobexsession.mm \
- osx/osxbtledeviceinquiry.mm \
- osx/osxbtcentralmanager.mm \
- osx/osxbtperipheralmanager.mm
-} else {
- HEADERS += osx/osxbtutility_p.h \
- osx/osxbtledeviceinquiry_p.h \
- osx/osxbluetooth_p.h \
- osx/osxbtcentralmanager_p.h \
- osx/osxbtnotifier_p.h
- ios {
- HEADERS += osx/osxbtperipheralmanager_p.h
- }
-
- OBJECTIVE_SOURCES += osx/osxbtutility.mm \
- osx/osxbtledeviceinquiry.mm \
- osx/osxbtcentralmanager.mm
- ios {
- OBJECTIVE_SOURCES += osx/osxbtperipheralmanager.mm
- }
-}
diff --git a/src/bluetooth/qbluetooth.cpp b/src/bluetooth/qbluetooth.cpp
index 1e8ce0b8..0a8efb44 100644
--- a/src/bluetooth/qbluetooth.cpp
+++ b/src/bluetooth/qbluetooth.cpp
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2014 Denis Shienkov <denis.shienkov@gmail.com>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2014 Denis Shienkov <denis.shienkov@gmail.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtCore/QLoggingCategory>
#include <QtBluetooth/qbluetooth.h>
@@ -103,7 +67,8 @@ Q_LOGGING_CATEGORY(QT_BT, "qt.bluetooth")
Q_LOGGING_CATEGORY(QT_BT_ANDROID, "qt.bluetooth.android")
Q_LOGGING_CATEGORY(QT_BT_BLUEZ, "qt.bluetooth.bluez")
Q_LOGGING_CATEGORY(QT_BT_WINDOWS, "qt.bluetooth.windows")
-Q_LOGGING_CATEGORY(QT_BT_WINRT, "qt.bluetooth.winrt")
-Q_LOGGING_CATEGORY(QT_BT_WINRT_SERVICE_THREAD, "qt.bluetooth.winrt.service.thread")
+Q_LOGGING_CATEGORY(QT_BT_WINDOWS_SERVICE_THREAD, "qt.bluetooth.winrt.service.thread")
QT_END_NAMESPACE
+
+#include "moc_qbluetooth.cpp"
diff --git a/src/bluetooth/qbluetooth.h b/src/bluetooth/qbluetooth.h
index df763147..5484b857 100644
--- a/src/bluetooth/qbluetooth.h
+++ b/src/bluetooth/qbluetooth.h
@@ -1,70 +1,38 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QBLUETOOTH_H
#define QBLUETOOTH_H
#include <QtBluetooth/qtbluetoothglobal.h>
+#include <QtCore/qglobal.h>
+#include <QtCore/qtmetamacros.h>
+#include <QtCore/qobject.h>
QT_BEGIN_NAMESPACE
namespace QBluetooth {
-
+Q_NAMESPACE_EXPORT(Q_BLUETOOTH_EXPORT)
// TODO Qt 6: Merge these two enums? But note that ATT Authorization has no equivalent
// on the socket security level.
-enum Security {
+enum class Security {
NoSecurity = 0x00,
Authorization = 0x01,
Authentication = 0x02,
Encryption = 0x04,
Secure = 0x08
};
-
+Q_ENUM_NS(Security)
Q_DECLARE_FLAGS(SecurityFlags, Security)
Q_DECLARE_OPERATORS_FOR_FLAGS(SecurityFlags)
-enum AttAccessConstraint {
+enum class AttAccessConstraint {
AttAuthorizationRequired = 0x1,
AttAuthenticationRequired = 0x2,
AttEncryptionRequired = 0x4,
};
+Q_ENUM_NS(AttAccessConstraint)
Q_DECLARE_FLAGS(AttAccessConstraints, AttAccessConstraint)
Q_DECLARE_OPERATORS_FOR_FLAGS(AttAccessConstraints)
diff --git a/src/bluetooth/qbluetoothaddress.cpp b/src/bluetooth/qbluetoothaddress.cpp
index 4485bc61..9919b890 100644
--- a/src/bluetooth/qbluetoothaddress.cpp
+++ b/src/bluetooth/qbluetoothaddress.cpp
@@ -1,44 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qbluetoothaddress.h"
-#include "qbluetoothaddress_p.h"
#ifndef QT_NO_DEBUG_STREAM
#include <QDebug>
@@ -46,6 +9,11 @@
QT_BEGIN_NAMESPACE
+static_assert(QT6_ONLY(!)std::is_trivially_copyable_v<QBluetoothAddress>,
+ "Must stay this way until Qt 7 because of BC reasons.");
+
+QT_IMPL_METATYPE_EXTERN(QBluetoothAddress)
+
/*!
\class QBluetoothAddress
\inmodule QtBluetooth
@@ -56,44 +24,23 @@ QT_BEGIN_NAMESPACE
This class holds a Bluetooth address in a platform- and protocol-independent manner.
*/
-/*!
- \fn inline bool QBluetoothAddress::operator!=(const QBluetoothAddress &other) const
-
-
- Compares this Bluetooth address with \a other.
-
- Returns true if the Bluetooth addresses are not equal, otherwise returns false.
-*/
-
-static void registerQBluetoothAddressMetaType()
+void registerQBluetoothAddress()
{
- static bool initDone = false;
- if (!initDone) {
- qRegisterMetaType<QBluetoothAddress>();
- initDone = true;
- }
+ qRegisterMetaType<QBluetoothAddress>();
}
+Q_CONSTRUCTOR_FUNCTION(registerQBluetoothAddress)
/*!
- Constructs an null Bluetooth address.
+ \fn QBluetoothAddress::QBluetoothAddress()
+
+ Constructs a null Bluetooth Address.
*/
-QBluetoothAddress::QBluetoothAddress() :
- d_ptr(new QBluetoothAddressPrivate)
-{
- registerQBluetoothAddressMetaType();
-}
/*!
+ \fn QBluetoothAddress::QBluetoothAddress(quint64 address)
+
Constructs a new Bluetooth address and assigns \a address to it.
*/
-QBluetoothAddress::QBluetoothAddress(quint64 address) :
- d_ptr(new QBluetoothAddressPrivate)
-{
- registerQBluetoothAddressMetaType();
-
- Q_D(QBluetoothAddress);
- d->m_address = address;
-}
/*!
Constructs a new Bluetooth address and assigns \a address to it.
@@ -101,104 +48,48 @@ QBluetoothAddress::QBluetoothAddress(quint64 address) :
The format of \a address can be either XX:XX:XX:XX:XX:XX or XXXXXXXXXXXX,
where X is a hexadecimal digit. Case is not important.
*/
-QBluetoothAddress::QBluetoothAddress(const QString &address) :
- d_ptr(new QBluetoothAddressPrivate)
+QBluetoothAddress::QBluetoothAddress(const QString &address)
{
- registerQBluetoothAddressMetaType();
-
- Q_D(QBluetoothAddress);
-
QString a = address;
- if (a.length() == 17)
+ if (a.size() == 17)
a.remove(QLatin1Char(':'));
- if (a.length() == 12) {
+ if (a.size() == 12) {
bool ok;
- d->m_address = a.toULongLong(&ok, 16);
+ m_address = a.toULongLong(&ok, 16);
if (!ok)
clear();
} else {
- d->m_address = 0;
+ m_address = 0;
}
}
/*!
- Constructs a new Bluetooth address which is a copy of \a other.
-*/
-QBluetoothAddress::QBluetoothAddress(const QBluetoothAddress &other) :
- d_ptr(new QBluetoothAddressPrivate)
-{
- *this = other;
-}
+ \fn QBluetoothAddress::qHash(const QBluetoothAddress &key, size_t seed)
+ \since 6.6
-/*!
- Destroys the QBluetoothAddress.
+ Returns the hash value for the \a key, using \a seed to seed the
+ calculation.
*/
-QBluetoothAddress::~QBluetoothAddress()
-{
- delete d_ptr;
-}
/*!
- Assigns \a other to this Bluetooth address.
-*/
-QBluetoothAddress &QBluetoothAddress::operator=(const QBluetoothAddress &other)
-{
- Q_D(QBluetoothAddress);
-
- d->m_address = other.d_func()->m_address;
+ \fn void QBluetoothAddress::clear()
- return *this;
-}
-
-/*!
Sets the Bluetooth address to 00:00:00:00:00:00.
*/
-void QBluetoothAddress::clear()
-{
- Q_D(QBluetoothAddress);
- d->m_address = 0;
-}
/*!
- Returns true if the Bluetooth address is null, otherwise returns false.
-*/
-bool QBluetoothAddress::isNull() const
-{
- Q_D(const QBluetoothAddress);
- return d->m_address == 0;
-}
+ \fn bool QBluetoothAddress::isNull() const
-/*!
- Returns true if the Bluetooth address is less than \a other, otherwise
- returns false.
+ Returns true if the Bluetooth address is null, otherwise returns false.
*/
-bool QBluetoothAddress::operator<(const QBluetoothAddress &other) const
-{
- Q_D(const QBluetoothAddress);
- return d->m_address < other.d_func()->m_address;
-}
/*!
- Compares this Bluetooth address to \a other.
-
- Returns true if the two Bluetooth addresses are equal, otherwise returns false.
-*/
-bool QBluetoothAddress::operator==(const QBluetoothAddress &other) const
-{
- Q_D(const QBluetoothAddress);
- return d->m_address == other.d_func()->m_address;
-}
+ \fn quint64 QBluetoothAddress::toUInt64() const
-/*!
Returns this Bluetooth address as a quint64.
*/
-quint64 QBluetoothAddress::toUInt64() const
-{
- Q_D(const QBluetoothAddress);
- return d->m_address;
-}
/*!
Returns the Bluetooth address as a string of the form, XX:XX:XX:XX:XX:XX.
@@ -206,23 +97,38 @@ quint64 QBluetoothAddress::toUInt64() const
QString QBluetoothAddress::toString() const
{
QString s(QStringLiteral("%1:%2:%3:%4:%5:%6"));
- Q_D(const QBluetoothAddress);
for (int i = 5; i >= 0; --i) {
- const quint8 a = (d->m_address >> (i*8)) & 0xff;
+ const quint8 a = (m_address >> (i*8)) & 0xff;
s = s.arg(a, 2, 16, QLatin1Char('0'));
}
return s.toUpper();
}
-QBluetoothAddressPrivate::QBluetoothAddressPrivate()
-{
- m_address = 0;
-}
+/*!
+ \fn bool QBluetoothAddress::operator<(const QBluetoothAddress &a,
+ const QBluetoothAddress &b)
+ \brief Returns true if the Bluetooth address \a a is less than \a b, otherwise
+ returns false.
+*/
+
+/*!
+ \fn bool QBluetoothAddress::operator==(const QBluetoothAddress &a,
+ const QBluetoothAddress &b)
+ \brief Returns \c true if the two Bluetooth addresses \a a and \a b are equal,
+ otherwise returns \c false.
+*/
+
+/*!
+ \fn bool QBluetoothAddress::operator!=(const QBluetoothAddress &a,
+ const QBluetoothAddress &b)
+ \brief Returns \c true if the two Bluetooth addresses \a a and \a b are not equal,
+ otherwise returns \c false.
+*/
#ifndef QT_NO_DEBUG_STREAM
-QDebug operator<<(QDebug debug, const QBluetoothAddress &address)
+QDebug QBluetoothAddress::streamingOperator(QDebug debug, const QBluetoothAddress &address)
{
debug << address.toString();
return debug;
diff --git a/src/bluetooth/qbluetoothaddress.h b/src/bluetooth/qbluetoothaddress.h
index e3750d21..a7a2daa0 100644
--- a/src/bluetooth/qbluetoothaddress.h
+++ b/src/bluetooth/qbluetoothaddress.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QBLUETOOTHADDRESS_H
#define QBLUETOOTHADDRESS_H
@@ -43,49 +7,95 @@
#include <QtBluetooth/qtbluetoothglobal.h>
#include <QtCore/QByteArray>
+#include <QtCore/qhashfunctions.h>
#include <QtCore/QString>
#include <QtCore/QMetaType>
+#include <QtCore/QDebug>
QT_BEGIN_NAMESPACE
-class QBluetoothAddressPrivate;
-
-class Q_BLUETOOTH_EXPORT QBluetoothAddress
+class QT6_ONLY(Q_BLUETOOTH_EXPORT) QBluetoothAddress
{
public:
- QBluetoothAddress();
- explicit QBluetoothAddress(quint64 address);
+ constexpr QBluetoothAddress() noexcept {};
+ constexpr explicit QBluetoothAddress(quint64 address) noexcept : m_address(address) {};
+ QT7_ONLY(Q_BLUETOOTH_EXPORT)
explicit QBluetoothAddress(const QString &address);
- QBluetoothAddress(const QBluetoothAddress &other);
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
+ QT_BLUETOOTH_INLINE_SINCE(6, 6)
+ QBluetoothAddress(const QBluetoothAddress &other) noexcept;
+ QT_BLUETOOTH_INLINE_SINCE(6, 6)
~QBluetoothAddress();
- QBluetoothAddress &operator=(const QBluetoothAddress &other);
+ QT_BLUETOOTH_INLINE_SINCE(6, 6)
+ QBluetoothAddress &operator=(const QBluetoothAddress &other) noexcept;
+ QBluetoothAddress(QBluetoothAddress &&) noexcept = default;
+ QBluetoothAddress &operator=(QBluetoothAddress &&) noexcept = default;
+#endif // Qt 6
- bool isNull() const;
+ QT_BLUETOOTH_INLINE_SINCE(6, 6)
+ bool isNull() const noexcept;
- void clear();
+ QT_BLUETOOTH_INLINE_SINCE(6, 6)
+ void clear() noexcept;
- bool operator<(const QBluetoothAddress &other) const;
- bool operator==(const QBluetoothAddress &other) const;
- inline bool operator!=(const QBluetoothAddress &other) const
+ friend bool operator<(const QBluetoothAddress &a, const QBluetoothAddress &b)
+ {
+ return a.m_address < b.m_address;
+ }
+ friend bool operator==(const QBluetoothAddress &a, const QBluetoothAddress &b)
+ {
+ return a.m_address == b.m_address;
+ }
+ inline friend bool operator!=(const QBluetoothAddress &a, const QBluetoothAddress &b)
{
- return !operator==(other);
+ return a.m_address != b.m_address;
}
- quint64 toUInt64() const;
+ QT_BLUETOOTH_INLINE_SINCE(6, 6)
+ quint64 toUInt64() const noexcept;
+ QT7_ONLY(Q_BLUETOOTH_EXPORT)
QString toString() const;
private:
- Q_DECLARE_PRIVATE(QBluetoothAddress)
- QBluetoothAddressPrivate *d_ptr;
+ quint64 m_address = { 0 };
+ friend QT7_ONLY(constexpr) size_t qHash(const QBluetoothAddress &key, size_t seed = 0) noexcept
+ { return qHash(key.m_address, seed); }
+#ifndef QT_NO_DEBUG_STREAM
+ friend QDebug operator<<(QDebug d, const QBluetoothAddress &a)
+ {
+ return streamingOperator(d, a);
+ }
+ QT7_ONLY(Q_BLUETOOTH_EXPORT)
+ static QDebug streamingOperator(QDebug, const QBluetoothAddress &address);
+#endif
};
-#ifndef QT_NO_DEBUG_STREAM
-Q_BLUETOOTH_EXPORT QDebug operator<<(QDebug, const QBluetoothAddress &address);
+#if QT_BLUETOOTH_INLINE_IMPL_SINCE(6, 6)
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
+QBluetoothAddress::QBluetoothAddress(const QBluetoothAddress &) noexcept = default;
+QBluetoothAddress &QBluetoothAddress::operator=(const QBluetoothAddress &) noexcept = default;
+QBluetoothAddress::~QBluetoothAddress() = default;
#endif
+void QBluetoothAddress::clear() noexcept
+{
+ m_address = 0;
+}
+
+bool QBluetoothAddress::isNull() const noexcept
+{
+ return m_address == 0;
+}
+
+quint64 QBluetoothAddress::toUInt64() const noexcept
+{
+ return m_address;
+}
+#endif // QT_BLUETOOTH_INLINE_IMPL_SINCE(6, 6)
+
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(QBluetoothAddress)
+QT_DECL_METATYPE_EXTERN(QBluetoothAddress, Q_BLUETOOTH_EXPORT)
#endif
diff --git a/src/bluetooth/qbluetoothaddress_p.h b/src/bluetooth/qbluetoothaddress_p.h
deleted file mode 100644
index c3d87b0e..00000000
--- a/src/bluetooth/qbluetoothaddress_p.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QBLUETOOTHADDRESS_P_H
-#define QBLUETOOTHADDRESS_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include "qbluetoothaddress.h"
-
-QT_BEGIN_NAMESPACE
-
-class QBluetoothAddressPrivate
-{
-public:
- QBluetoothAddressPrivate();
-
- quint64 m_address;
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/bluetooth/qbluetoothdevicediscoveryagent.cpp b/src/bluetooth/qbluetoothdevicediscoveryagent.cpp
index f38f8994..da88f4aa 100644
--- a/src/bluetooth/qbluetoothdevicediscoveryagent.cpp
+++ b/src/bluetooth/qbluetoothdevicediscoveryagent.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qbluetoothhostinfo.h"
#include "qbluetoothdevicediscoveryagent.h"
@@ -76,9 +40,6 @@ Q_DECLARE_LOGGING_CATEGORY(QT_BT)
\note Since Android 6.0 the ability to detect devices requires ACCESS_COARSE_LOCATION.
- \note Due to API limitations it is only possible to find devices that have been paired using
- Windows' settings on Windows.
-
\note The Win32 backend currently does not support the Received Signal Strength
Indicator (RSSI), as well as the Manufacturer Specific Data, or other data
updates advertised by Bluetooth LE devices after discovery.
@@ -94,34 +55,23 @@ Q_DECLARE_LOGGING_CATEGORY(QT_BT)
\value InputOutputError Writing or reading from the device resulted in an error.
\value InvalidBluetoothAdapterError The passed local adapter address does not match the physical
adapter address of any local Bluetooth device.
- \value UnsupportedPlatformError Device discovery is not possible or implemented on the current
- platform. The error is set in response to a call to \l start().
- An example for such cases are iOS versions below 5.0 which do not support
- Bluetooth device search at all. This value was introduced by Qt 5.5.
- \value UnsupportedDiscoveryMethod One of the requested discovery methods is not supported by
- the current platform. This value was introduced by Qt 5.8.
+ \value [since 5.5] UnsupportedPlatformError Device discovery is not possible or implemented
+ on the current platform. The error is set in
+ response to a call to \l start(). An example for
+ such cases are iOS versions below 5.0 which do
+ not support Bluetooth device search at all.
+ \value [since 5.8] UnsupportedDiscoveryMethod One of the requested discovery methods is not
+ supported by the current platform.
+ \value [since 6.2] LocationServiceTurnedOffError The location service is turned off.
+ Usage of Bluetooth APIs is not possible
+ when location service is turned off.
+ \value [since 6.4] MissingPermissionsError The operating system requests
+ permissions which were not
+ granted by the user.
\value UnknownError An unknown error has occurred.
*/
/*!
- \enum QBluetoothDeviceDiscoveryAgent::InquiryType
-
- This enum describes the inquiry type used while discovering Bluetooth devices.
-
- \value GeneralUnlimitedInquiry A general unlimited inquiry. Discovers all visible Bluetooth
- devices in the local vicinity.
- \value LimitedInquiry A limited inquiry discovers devices that are in limited
- inquiry mode.
-
- LimitedInquiry is not supported on all platforms. If it is requested on a platform that does not
- support it, GeneralUnlimitedInquiry will be used instead. Setting LimitedInquiry is useful
- for multi-player Bluetooth-based games that needs faster communication between the devices.
- The phone scans for devices in LimitedInquiry and Service Discovery is done on one or two devices
- to speed up the service scan. After the game has connected to the device it intended to,
- the device returns to GeneralUnlimitedInquiry.
-*/
-
-/*!
\enum QBluetoothDeviceDiscoveryAgent::DiscoveryMethod
This enum descibes the type of discovery method employed by the QBluetoothDeviceDiscoveryAgent.
@@ -186,12 +136,14 @@ Q_DECLARE_LOGGING_CATEGORY(QT_BT)
*/
/*!
- \fn void QBluetoothDeviceDiscoveryAgent::error(QBluetoothDeviceDiscoveryAgent::Error error)
+ \fn void QBluetoothDeviceDiscoveryAgent::errorOccurred(QBluetoothDeviceDiscoveryAgent::Error
+ error)
This signal is emitted when an \a error occurs during Bluetooth device discovery.
The \a error parameter describes the error that occurred.
\sa error(), errorString()
+ \since 6.2
*/
/*!
@@ -252,30 +204,6 @@ QBluetoothDeviceDiscoveryAgent::~QBluetoothDeviceDiscoveryAgent()
}
/*!
- \property QBluetoothDeviceDiscoveryAgent::inquiryType
- \brief type of inquiry scan to be used while discovering devices
-
- This property affects the type of inquiry scan which is performed while discovering devices.
-
- By default, this property is set to GeneralUnlimitedInquiry.
-
- Not all platforms support LimitedInquiry.
-
- \sa InquiryType
-*/
-QBluetoothDeviceDiscoveryAgent::InquiryType QBluetoothDeviceDiscoveryAgent::inquiryType() const
-{
- Q_D(const QBluetoothDeviceDiscoveryAgent);
- return d->inquiryType;
-}
-
-void QBluetoothDeviceDiscoveryAgent::setInquiryType(QBluetoothDeviceDiscoveryAgent::InquiryType type)
-{
- Q_D(QBluetoothDeviceDiscoveryAgent);
- d->inquiryType = type;
-}
-
-/*!
Returns a list of all discovered Bluetooth devices.
*/
QList<QBluetoothDeviceInfo> QBluetoothDeviceDiscoveryAgent::discoveredDevices() const
@@ -299,6 +227,8 @@ QList<QBluetoothDeviceInfo> QBluetoothDeviceDiscoveryAgent::discoveredDevices()
the platform the classic search may add more time to the total discovery process
beyond \a timeout.
+ For a reliable Bluetooth Low Energy discovery, use at least 40000 milliseconds.
+
\sa lowEnergyDiscoveryTimeout()
\since 5.8
*/
@@ -307,9 +237,14 @@ void QBluetoothDeviceDiscoveryAgent::setLowEnergyDiscoveryTimeout(int timeout)
Q_D(QBluetoothDeviceDiscoveryAgent);
// cannot deliberately turn it off
- if (d->lowEnergySearchTimeout < 0 || timeout < 0) {
- qCDebug(QT_BT) << "The Bluetooth Low Energy device discovery timeout cannot be negative "
- "or set on a backend which does not support this feature.";
+ if (timeout < 0) {
+ qCDebug(QT_BT) << "The Bluetooth Low Energy device discovery timeout cannot be negative.";
+ return;
+ }
+
+ if (d->lowEnergySearchTimeout < 0) {
+ qCDebug(QT_BT) << "The Bluetooth Low Energy device discovery timeout cannot be "
+ "set on a backend which does not support this feature.";
return;
}
@@ -352,7 +287,7 @@ int QBluetoothDeviceDiscoveryAgent::lowEnergyDiscoveryTimeout() const
void QBluetoothDeviceDiscoveryAgent::start()
{
Q_D(QBluetoothDeviceDiscoveryAgent);
- if (!isActive() && d->lastError != InvalidBluetoothAdapterError)
+ if (!isActive())
d->start(supportedDiscoveryMethods());
}
@@ -385,11 +320,11 @@ void QBluetoothDeviceDiscoveryAgent::start(DiscoveryMethods methods)
d->lastError = UnsupportedDiscoveryMethod;
d->errorString = QBluetoothDeviceDiscoveryAgent::tr("One or more device discovery methods "
"are not supported on this platform");
- emit error(d->lastError);
+ emit errorOccurred(d->lastError);
return;
}
- if (!isActive() && d->lastError != InvalidBluetoothAdapterError)
+ if (!isActive())
d->start(methods);
}
@@ -414,6 +349,8 @@ bool QBluetoothDeviceDiscoveryAgent::isActive() const
/*!
Returns the last error.
+
+ Any possible previous errors are cleared upon restarting the discovery.
*/
QBluetoothDeviceDiscoveryAgent::Error QBluetoothDeviceDiscoveryAgent::error() const
{
@@ -424,6 +361,8 @@ QBluetoothDeviceDiscoveryAgent::Error QBluetoothDeviceDiscoveryAgent::error() co
/*!
Returns a human-readable description of the last error.
+
+ \sa error(), errorOccurred()
*/
QString QBluetoothDeviceDiscoveryAgent::errorString() const
{
diff --git a/src/bluetooth/qbluetoothdevicediscoveryagent.h b/src/bluetooth/qbluetoothdevicediscoveryagent.h
index e566d895..923dbb93 100644
--- a/src/bluetooth/qbluetoothdevicediscoveryagent.h
+++ b/src/bluetooth/qbluetoothdevicediscoveryagent.h
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2014 Denis Shienkov <denis.shienkov@gmail.com>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2014 Denis Shienkov <denis.shienkov@gmail.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QBLUETOOTHDEVICEDISCOVERYAGENT_H
#define QBLUETOOTHDEVICEDISCOVERYAGENT_H
@@ -54,8 +18,6 @@ class QBluetoothDeviceDiscoveryAgentPrivate;
class Q_BLUETOOTH_EXPORT QBluetoothDeviceDiscoveryAgent : public QObject
{
Q_OBJECT
- Q_PROPERTY(QBluetoothDeviceDiscoveryAgent::InquiryType inquiryType
- READ inquiryType WRITE setInquiryType)
public:
// FIXME: add more errors
@@ -67,16 +29,12 @@ public:
InvalidBluetoothAdapterError,
UnsupportedPlatformError,
UnsupportedDiscoveryMethod,
+ LocationServiceTurnedOffError,
+ MissingPermissionsError,
UnknownError = 100 // New errors must be added before Unknown error
};
Q_ENUM(Error)
- enum InquiryType {
- GeneralUnlimitedInquiry,
- LimitedInquiry
- };
- Q_ENUM(InquiryType)
-
enum DiscoveryMethod
{
NoMethod = 0x0,
@@ -91,10 +49,6 @@ public:
QObject *parent = nullptr);
~QBluetoothDeviceDiscoveryAgent();
- // TODO Remove inquiry type in Qt 6 -> not really used anywhere
- QBluetoothDeviceDiscoveryAgent::InquiryType inquiryType() const;
- void setInquiryType(QBluetoothDeviceDiscoveryAgent::InquiryType type);
-
bool isActive() const;
Error error() const;
@@ -115,7 +69,7 @@ Q_SIGNALS:
void deviceDiscovered(const QBluetoothDeviceInfo &info);
void deviceUpdated(const QBluetoothDeviceInfo &info, QBluetoothDeviceInfo::Fields updatedFields);
void finished();
- void error(QBluetoothDeviceDiscoveryAgent::Error error);
+ void errorOccurred(QBluetoothDeviceDiscoveryAgent::Error error);
void canceled();
private:
diff --git a/src/bluetooth/qbluetoothdevicediscoveryagent_android.cpp b/src/bluetooth/qbluetoothdevicediscoveryagent_android.cpp
index d8cc5ace..109fcb36 100644
--- a/src/bluetooth/qbluetoothdevicediscoveryagent_android.cpp
+++ b/src/bluetooth/qbluetoothdevicediscoveryagent_android.cpp
@@ -1,51 +1,17 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Lauri Laanmets (Proekspert AS) <lauri.laanmets@eesti.ee>
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 Lauri Laanmets (Proekspert AS) <lauri.laanmets@eesti.ee>
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+#include "android/devicediscoverybroadcastreceiver_p.h"
+#include "android/androidutils_p.h"
+#include "android/jni_android_p.h"
#include "qbluetoothdevicediscoveryagent_p.h"
+#include <QCoreApplication>
#include <QtCore/QLoggingCategory>
#include <QtBluetooth/QBluetoothAddress>
#include <QtBluetooth/QBluetoothDeviceInfo>
-#include <QtCore/private/qjnihelpers_p.h>
-#include "android/devicediscoverybroadcastreceiver_p.h"
-#include <QtAndroidExtras/QAndroidJniEnvironment>
-#include <QtAndroid>
+#include <QtCore/QJniEnvironment>
+#include <QtCore/private/qandroidextras_p.h>
QT_BEGIN_NAMESPACE
@@ -57,30 +23,20 @@ enum {
BtleScanActive = 2
};
+static constexpr auto deviceDiscoveryStartTimeLimit = std::chrono::seconds{5};
+static constexpr short deviceDiscoveryStartMaxAttempts = 6;
+
QBluetoothDeviceDiscoveryAgentPrivate::QBluetoothDeviceDiscoveryAgentPrivate(
const QBluetoothAddress &deviceAdapter, QBluetoothDeviceDiscoveryAgent *parent) :
- inquiryType(QBluetoothDeviceDiscoveryAgent::GeneralUnlimitedInquiry),
- lastError(QBluetoothDeviceDiscoveryAgent::NoError),
- receiver(0),
- m_adapterAddress(deviceAdapter),
+ adapterAddress(deviceAdapter),
m_active(NoScanActive),
- leScanTimeout(0),
- pendingCancel(false),
- pendingStart(false),
- lowEnergySearchTimeout(25000),
+ deviceDiscoveryStartAttemptsLeft(deviceDiscoveryStartMaxAttempts),
q_ptr(parent)
{
- QAndroidJniEnvironment env;
- adapter = QAndroidJniObject::callStaticObjectMethod("android/bluetooth/BluetoothAdapter",
- "getDefaultAdapter",
- "()Landroid/bluetooth/BluetoothAdapter;");
- if (!adapter.isValid()) {
- if (env->ExceptionCheck()) {
- env->ExceptionDescribe();
- env->ExceptionClear();
- }
+ adapter = getDefaultBluetoothAdapter();
+
+ if (!adapter.isValid())
qCWarning(QT_BT_ANDROID) << "Device does not support Bluetooth";
- }
}
QBluetoothDeviceDiscoveryAgentPrivate::~QBluetoothDeviceDiscoveryAgentPrivate()
@@ -111,9 +67,42 @@ QBluetoothDeviceDiscoveryAgent::DiscoveryMethods QBluetoothDeviceDiscoveryAgent:
return (LowEnergyMethod | ClassicMethod);
}
+void QBluetoothDeviceDiscoveryAgentPrivate::classicDiscoveryStartFail()
+{
+ Q_Q(QBluetoothDeviceDiscoveryAgent);
+ lastError = QBluetoothDeviceDiscoveryAgent::InputOutputError;
+ errorString = QBluetoothDeviceDiscoveryAgent::tr("Classic Discovery cannot be started");
+ emit q->errorOccurred(lastError);
+}
+
+// Sets & emits an error and returns true if bluetooth is off
+bool QBluetoothDeviceDiscoveryAgentPrivate::setErrorIfPowerOff()
+{
+ Q_Q(QBluetoothDeviceDiscoveryAgent);
+
+ const int state = adapter.callMethod<jint>("getState");
+ if (state != 12) { // BluetoothAdapter.STATE_ON
+ lastError = QBluetoothDeviceDiscoveryAgent::PoweredOffError;
+ m_active = NoScanActive;
+ errorString = QBluetoothDeviceDiscoveryAgent::tr("Device is powered off");
+ emit q->errorOccurred(lastError);
+ return true;
+ }
+ return false;
+}
+
+/*
+The Classic/LE discovery method precedence is handled as follows:
+
+If only classic method is set => only classic method is used
+If only LE method is set => only LE method is used
+If both classic and LE methods are set, start classic scan first
+ If classic scan fails to start, start LE scan immediately in the start function
+ Otherwise start LE scan when classic scan completes
+*/
+
void QBluetoothDeviceDiscoveryAgentPrivate::start(QBluetoothDeviceDiscoveryAgent::DiscoveryMethods methods)
{
- //TODO Implement discovery method handling (see input parameter)
requestedMethods = methods;
if (pendingCancel) {
@@ -127,64 +116,70 @@ void QBluetoothDeviceDiscoveryAgentPrivate::start(QBluetoothDeviceDiscoveryAgent
qCWarning(QT_BT_ANDROID) << "Device does not support Bluetooth";
lastError = QBluetoothDeviceDiscoveryAgent::InputOutputError;
errorString = QBluetoothDeviceDiscoveryAgent::tr("Device does not support Bluetooth");
- emit q->error(lastError);
+ emit q->errorOccurred(lastError);
return;
}
- if (!m_adapterAddress.isNull()
- && adapter.callObjectMethod<jstring>("getAddress").toString()
- != m_adapterAddress.toString()) {
+ if (!adapterAddress.isNull()
+ && adapter.callMethod<jstring>("getAddress").toString()
+ != adapterAddress.toString()) {
qCWarning(QT_BT_ANDROID) << "Incorrect local adapter passed.";
lastError = QBluetoothDeviceDiscoveryAgent::InvalidBluetoothAdapterError;
errorString = QBluetoothDeviceDiscoveryAgent::tr("Passed address is not a local device.");
- emit q->error(lastError);
+ emit q->errorOccurred(lastError);
return;
}
- const int state = adapter.callMethod<jint>("getState");
- if (state != 12) { // BluetoothAdapter.STATE_ON
- lastError = QBluetoothDeviceDiscoveryAgent::PoweredOffError;
- errorString = QBluetoothDeviceDiscoveryAgent::tr("Device is powered off");
- emit q->error(lastError);
+ if (setErrorIfPowerOff())
+ return;
+
+ if (!ensureAndroidPermission(QBluetoothPermission::Access)) {
+ qCWarning(QT_BT_ANDROID)
+ << "Search not possible due to missing QBluetoothPermission::Access permission";
+ errorString = QBluetoothDeviceDiscoveryAgent::tr(
+ "Failed to start device discovery due to missing permissions.");
+ lastError = QBluetoothDeviceDiscoveryAgent::MissingPermissionsError;
+ emit q->errorOccurred(lastError);
return;
}
+ qCDebug(QT_BT_ANDROID) << "QBluetoothPermission::Access permission available";
- // check Android v23+ permissions
- // -> any device search requires android.permission.ACCESS_COARSE_LOCATION or android.permission.ACCESS_FINE_LOCATION
- if (QtAndroid::androidSdkVersion() >= 23) {
- const QString coarsePermission(QLatin1String("android.permission.ACCESS_COARSE_LOCATION"));
- const QString finePermission(QLatin1String("android.permission.ACCESS_FINE_LOCATION"));
-
- // do we have required permission already, if so nothing to do
- if (QtAndroidPrivate::checkPermission(coarsePermission) == QtAndroidPrivate::PermissionsResult::Denied
- && QtAndroidPrivate::checkPermission(finePermission) == QtAndroidPrivate::PermissionsResult::Denied) {
- qCWarning(QT_BT_ANDROID) << "Requesting ACCESS_*_LOCATION permission";
-
- QAndroidJniEnvironment env;
- const QHash<QString, QtAndroidPrivate::PermissionsResult> results =
- QtAndroidPrivate::requestPermissionsSync(env, QStringList() << coarsePermission << finePermission);
-
- bool permissionReceived = false;
- for (const QString &permission: results.keys()) {
- qCDebug(QT_BT_ANDROID) << permission << (results[permission] == QtAndroidPrivate::PermissionsResult::Denied);
- if ((permission == coarsePermission || permission == finePermission)
- && results[permission] == QtAndroidPrivate::PermissionsResult::Granted) {
- permissionReceived = true;
- break;
- }
- }
- if (!permissionReceived) {
- qCWarning(QT_BT_ANDROID) << "Search not possible due to missing permission (ACCESS_COARSE|FINE_LOCATION)";
- lastError = QBluetoothDeviceDiscoveryAgent::UnknownError;
- errorString = QBluetoothDeviceDiscoveryAgent::tr("Missing Location permission. Search is not possible.");
- emit q->error(lastError);
- return;
+ // Double check Location service is turned on
+ bool locationTurnedOn = true; // backwards compatible behavior to previous Qt versions
+ const QJniObject locString = QJniObject::getStaticObjectField(
+ "android/content/Context", "LOCATION_SERVICE", "Ljava/lang/String;");
+
+ const QJniObject locService =
+ QJniObject(QNativeInterface::QAndroidApplication::context()).callMethod<jobject>(
+ "getSystemService",
+ locString.object<jstring>());
+
+ if (locService.isValid()) {
+ if (QNativeInterface::QAndroidApplication::sdkVersion() >= 28) {
+ locationTurnedOn = bool(locService.callMethod<jboolean>("isLocationEnabled"));
+ } else {
+ // check whether there is any enabled provider
+ QJniObject listOfEnabledProviders =
+ locService.callMethod<QtJniTypes::List>("getProviders", true);
+
+ if (listOfEnabledProviders.isValid()) {
+ int size = listOfEnabledProviders.callMethod<jint>("size");
+ locationTurnedOn = size > 0;
+ qCDebug(QT_BT_ANDROID) << size << "enabled location providers detected.";
}
}
+ }
- qCWarning(QT_BT_ANDROID) << "ACCESS_COARSE|FINE_LOCATION permission available";
+ if (!locationTurnedOn) {
+ qCWarning(QT_BT_ANDROID) << "Search not possible due to turned off Location service";
+ lastError = QBluetoothDeviceDiscoveryAgent::LocationServiceTurnedOffError;
+ errorString = QBluetoothDeviceDiscoveryAgent::tr("Location service turned off. Search is not possible.");
+ emit q->errorOccurred(lastError);
+ return;
}
+ qCDebug(QT_BT_ANDROID) << "Location turned on";
+
// install Java BroadcastReceiver
if (!receiver) {
// SDP based device discovery
@@ -195,35 +190,71 @@ void QBluetoothDeviceDiscoveryAgentPrivate::start(QBluetoothDeviceDiscoveryAgent
QObject::connect(receiver, SIGNAL(finished()), this, SLOT(processSdpDiscoveryFinished()));
}
+ lastError = QBluetoothDeviceDiscoveryAgent::NoError;
+ errorString.clear();
discoveredDevices.clear();
// by arbitrary definition we run classic search first
if (requestedMethods & QBluetoothDeviceDiscoveryAgent::ClassicMethod) {
const bool success = adapter.callMethod<jboolean>("startDiscovery");
if (!success) {
- lastError = QBluetoothDeviceDiscoveryAgent::InputOutputError;
- errorString = QBluetoothDeviceDiscoveryAgent::tr("Classic Discovery cannot be started");
- emit q->error(lastError);
- return;
- }
-
- m_active = SDPScanActive;
- qCDebug(QT_BT_ANDROID)
- << "QBluetoothDeviceDiscoveryAgentPrivate::start() - Classic search successfully started.";
- } else {
- // LE search only requested
- Q_ASSERT(requestedMethods & QBluetoothDeviceDiscoveryAgent::LowEnergyMethod);
+ qCDebug(QT_BT_ANDROID) << "Classic Discovery cannot be started";
+ // Check if only classic discovery requested -> error out and return.
+ // Otherwise since LE was also requested => don't return but allow the
+ // function to continue to LE scanning
+ if (requestedMethods == QBluetoothDeviceDiscoveryAgent::ClassicMethod) {
+ classicDiscoveryStartFail();
+ return;
+ }
+ } else {
+ m_active = SDPScanActive;
+ if (!deviceDiscoveryStartTimeout) {
+ // In some bluetooth environments device discovery does not start properly
+ // if it is done shortly after (up to 20 seconds) a full service discovery.
+ // In that case we never get DISOVERY_STARTED action and device discovery never
+ // finishes. Here we use a small timeout to guard it; if we don't get the
+ // 'started' action in time, we restart the query. In the normal case the action
+ // is received in < 1 second. See QTBUG-101066
+ deviceDiscoveryStartTimeout = new QTimer(this);
+ deviceDiscoveryStartTimeout->setInterval(deviceDiscoveryStartTimeLimit);
+ deviceDiscoveryStartTimeout->setSingleShot(true);
+ QObject::connect(receiver, &DeviceDiscoveryBroadcastReceiver::discoveryStarted,
+ deviceDiscoveryStartTimeout, &QTimer::stop);
+ QObject::connect(deviceDiscoveryStartTimeout, &QTimer::timeout, this, [this]() {
+ deviceDiscoveryStartAttemptsLeft -= 1;
+ qCWarning(QT_BT_ANDROID) << "Discovery start not received, attempts left:"
+ << deviceDiscoveryStartAttemptsLeft;
+ // Check that bluetooth is not switched off
+ if (setErrorIfPowerOff())
+ return;
+ // If this was the last retry attempt, cancel the discovery just in case
+ // as a good cleanup practice
+ if (deviceDiscoveryStartAttemptsLeft <= 0) {
+ qCWarning(QT_BT_ANDROID) << "Classic device discovery failed to start";
+ (void)adapter.callMethod<jboolean>("cancelDiscovery");
+ }
+ // Restart the discovery and retry timer.
+ // The logic below is similar as in the start()
+ if (deviceDiscoveryStartAttemptsLeft > 0 &&
+ adapter.callMethod<jboolean>("startDiscovery"))
+ deviceDiscoveryStartTimeout->start();
+ else if (requestedMethods == QBluetoothDeviceDiscoveryAgent::ClassicMethod)
+ classicDiscoveryStartFail(); // No LE scan requested, scan is done
+ else
+ startLowEnergyScan(); // Continue to LE scan
+ });
+ }
+ deviceDiscoveryStartAttemptsLeft = deviceDiscoveryStartMaxAttempts;
+ deviceDiscoveryStartTimeout->start();
- if (QtAndroidPrivate::androidSdkVersion() < 18) {
- qCDebug(QT_BT_ANDROID) << "Skipping Bluetooth Low Energy device scan due to"
- "insufficient Android version.";
- m_active = NoScanActive;
- lastError = QBluetoothDeviceDiscoveryAgent::UnsupportedDiscoveryMethod;
- errorString = QBluetoothDeviceDiscoveryAgent::tr("Low Energy Discovery not supported");
- emit q->error(lastError);
+ qCDebug(QT_BT_ANDROID)
+ << "QBluetoothDeviceDiscoveryAgentPrivate::start() - Classic search successfully started.";
return;
}
+ }
+ if (requestedMethods & QBluetoothDeviceDiscoveryAgent::LowEnergyMethod) {
+ // LE search only requested or classic discovery failed but lets try LE scan anyway
startLowEnergyScan();
}
}
@@ -232,20 +263,28 @@ void QBluetoothDeviceDiscoveryAgentPrivate::stop()
{
Q_Q(QBluetoothDeviceDiscoveryAgent);
+ pendingStart = false;
+
+ if (deviceDiscoveryStartTimeout)
+ deviceDiscoveryStartTimeout->stop();
+
if (m_active == NoScanActive)
return;
if (m_active == SDPScanActive) {
- if (pendingCancel)
+ if (pendingCancel) {
+ // If we had both a pending cancel and a pending start,
+ // we now have only a pending cancel.
+ // The pending start was canceled above.
return;
+ }
pendingCancel = true;
- pendingStart = false;
bool success = adapter.callMethod<jboolean>("cancelDiscovery");
if (!success) {
lastError = QBluetoothDeviceDiscoveryAgent::InputOutputError;
errorString = QBluetoothDeviceDiscoveryAgent::tr("Discovery cannot be stopped");
- emit q->error(lastError);
+ emit q->errorOccurred(lastError);
return;
}
} else if (m_active == BtleScanActive) {
@@ -272,30 +311,16 @@ void QBluetoothDeviceDiscoveryAgentPrivate::processSdpDiscoveryFinished()
start(requestedMethods);
} else {
// check that it didn't finish due to turned off Bluetooth Device
- const int state = adapter.callMethod<jint>("getState");
- if (state != 12) { // BluetoothAdapter.STATE_ON
- m_active = NoScanActive;
- lastError = QBluetoothDeviceDiscoveryAgent::PoweredOffError;
- errorString = QBluetoothDeviceDiscoveryAgent::tr("Device is powered off");
- emit q->error(lastError);
+ if (setErrorIfPowerOff())
return;
- }
-
- // no BTLE scan requested
+ // Since no BTLE scan requested and classic scan is done => finished()
if (!(requestedMethods & QBluetoothDeviceDiscoveryAgent::LowEnergyMethod)) {
m_active = NoScanActive;
emit q->finished();
return;
}
- // start LE scan if supported
- if (QtAndroidPrivate::androidSdkVersion() < 18) {
- qCDebug(QT_BT_ANDROID) << "Skipping Bluetooth Low Energy device scan";
- m_active = NoScanActive;
- emit q->finished();
- } else {
- startLowEnergyScan();
- }
+ startLowEnergyScan();
}
}
@@ -316,7 +341,7 @@ void QBluetoothDeviceDiscoveryAgentPrivate::processDiscoveredDevices(
// the advertisement package.
// If address is same but name different then we keep both entries.
- for (int i = 0; i < discoveredDevices.size(); i++) {
+ for (qsizetype i = 0; i < discoveredDevices.size(); ++i) {
if (discoveredDevices[i].address() == info.address()) {
QBluetoothDeviceInfo::Fields updatedFields = QBluetoothDeviceInfo::Field::None;
if (discoveredDevices[i].rssi() != info.rssi()) {
@@ -327,11 +352,18 @@ void QBluetoothDeviceDiscoveryAgentPrivate::processDiscoveredDevices(
}
if (discoveredDevices[i].manufacturerData() != info.manufacturerData()) {
qCDebug(QT_BT_ANDROID) << "Updating manufacturer data for" << info.address();
- const QVector<quint16> keys = info.manufacturerIds();
+ const QList<quint16> keys = info.manufacturerIds();
for (auto key: keys)
discoveredDevices[i].setManufacturerData(key, info.manufacturerData(key));
updatedFields.setFlag(QBluetoothDeviceInfo::Field::ManufacturerData);
}
+ if (discoveredDevices[i].serviceData() != info.serviceData()) {
+ qCDebug(QT_BT_ANDROID) << "Updating service data for" << info.address();
+ const QList<QBluetoothUuid> keys = info.serviceIds();
+ for (auto key : keys)
+ discoveredDevices[i].setServiceData(key, info.serviceData(key));
+ updatedFields.setFlag(QBluetoothDeviceInfo::Field::ServiceData);
+ }
if (lowEnergySearchTimeout > 0) {
if (discoveredDevices[i] != info) {
@@ -372,13 +404,11 @@ void QBluetoothDeviceDiscoveryAgentPrivate::startLowEnergyScan()
m_active = BtleScanActive;
- QAndroidJniEnvironment env;
if (!leScanner.isValid()) {
- leScanner = QAndroidJniObject("org/qtproject/qt5/android/bluetooth/QtBluetoothLE");
- if (env->ExceptionCheck() || !leScanner.isValid()) {
+ leScanner = QJniObject::construct<QtJniTypes::QtBtLECentral>(
+ QNativeInterface::QAndroidApplication::context());
+ if (!leScanner.isValid()) {
qCWarning(QT_BT_ANDROID) << "Cannot load BTLE device scan class";
- env->ExceptionDescribe();
- env->ExceptionClear();
m_active = NoScanActive;
emit q->finished();
return;
@@ -387,7 +417,7 @@ void QBluetoothDeviceDiscoveryAgentPrivate::startLowEnergyScan()
leScanner.setField<jlong>("qtObject", reinterpret_cast<long>(receiver));
}
- jboolean result = leScanner.callMethod<jboolean>("scanForLeDevice", "(Z)Z", true);
+ jboolean result = leScanner.callMethod<jboolean>("scanForLeDevice", true);
if (!result) {
qCWarning(QT_BT_ANDROID) << "Cannot start BTLE device scanner";
m_active = NoScanActive;
@@ -414,7 +444,7 @@ void QBluetoothDeviceDiscoveryAgentPrivate::startLowEnergyScan()
void QBluetoothDeviceDiscoveryAgentPrivate::stopLowEnergyScan()
{
- jboolean result = leScanner.callMethod<jboolean>("scanForLeDevice", "(Z)Z", false);
+ jboolean result = leScanner.callMethod<jboolean>("scanForLeDevice", false);
if (!result)
qCWarning(QT_BT_ANDROID) << "Cannot stop BTLE device scanner";
diff --git a/src/bluetooth/qbluetoothdevicediscoveryagent_bluez.cpp b/src/bluetooth/qbluetoothdevicediscoveryagent_bluez.cpp
index 7dce9dae..24ae2511 100644
--- a/src/bluetooth/qbluetoothdevicediscoveryagent_bluez.cpp
+++ b/src/bluetooth/qbluetoothdevicediscoveryagent_bluez.cpp
@@ -1,51 +1,15 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtCore/QLoggingCategory>
+
+#include <QtCore/qcoreapplication.h>
+
#include "qbluetoothdevicediscoveryagent.h"
#include "qbluetoothdevicediscoveryagent_p.h"
#include "qbluetoothaddress.h"
#include "qbluetoothuuid.h"
-#include "bluez/manager_p.h"
-#include "bluez/adapter_p.h"
-#include "bluez/device_p.h"
#include "bluez/bluez5_helper_p.h"
#include "bluez/objectmanager_p.h"
#include "bluez/adapter1_bluez5_p.h"
@@ -59,46 +23,28 @@ Q_DECLARE_LOGGING_CATEGORY(QT_BT_BLUEZ)
QBluetoothDeviceDiscoveryAgentPrivate::QBluetoothDeviceDiscoveryAgentPrivate(
const QBluetoothAddress &deviceAdapter, QBluetoothDeviceDiscoveryAgent *parent) :
- lastError(QBluetoothDeviceDiscoveryAgent::NoError),
- m_adapterAddress(deviceAdapter),
- pendingCancel(false),
- pendingStart(false),
- useExtendedDiscovery(false),
- lowEnergySearchTimeout(-1), // remains -1 on BlueZ 4 -> timeout not supported
+ adapterAddress(deviceAdapter),
q_ptr(parent)
{
- if (isBluez5()) {
- lowEnergySearchTimeout = 20000;
- managerBluez5 = new OrgFreedesktopDBusObjectManagerInterface(
- QStringLiteral("org.bluez"),
- QStringLiteral("/"),
- QDBusConnection::systemBus(), parent);
- QObject::connect(managerBluez5,
- &OrgFreedesktopDBusObjectManagerInterface::InterfacesAdded,
- q_ptr,
- [this](const QDBusObjectPath &objectPath, InterfaceList interfacesAndProperties) {
- this->_q_InterfacesAdded(objectPath, interfacesAndProperties);
- });
+ initializeBluez5();
+ manager = new OrgFreedesktopDBusObjectManagerInterface(
+ QStringLiteral("org.bluez"),
+ QStringLiteral("/"),
+ QDBusConnection::systemBus(), parent);
+ QObject::connect(manager,
+ &OrgFreedesktopDBusObjectManagerInterface::InterfacesAdded,
+ q_ptr,
+ [this](const QDBusObjectPath &objectPath, InterfaceList interfacesAndProperties) {
+ this->_q_InterfacesAdded(objectPath, interfacesAndProperties);
+ });
- // start private address monitoring
- BluetoothManagement::instance();
- } else {
- manager = new OrgBluezManagerInterface(QStringLiteral("org.bluez"), QStringLiteral("/"),
- QDBusConnection::systemBus(), parent);
- QObject::connect(&extendedDiscoveryTimer,
- &QTimer::timeout, q_ptr, [this]() {
- this->_q_extendedDeviceDiscoveryTimeout();
- });
- extendedDiscoveryTimer.setInterval(10000);
- extendedDiscoveryTimer.setSingleShot(true);
- }
- inquiryType = QBluetoothDeviceDiscoveryAgent::GeneralUnlimitedInquiry;
+ // start private address monitoring
+ BluetoothManagement::instance();
}
QBluetoothDeviceDiscoveryAgentPrivate::~QBluetoothDeviceDiscoveryAgentPrivate()
{
delete adapter;
- delete adapterBluez5;
}
//TODO: Qt6 remove the pendingCancel/pendingStart logic as it is cumbersome.
@@ -115,7 +61,7 @@ bool QBluetoothDeviceDiscoveryAgentPrivate::isActive() const
if (pendingCancel)
return false; //TODO Qt6: remove pending[Cancel|Start] logic (see comment above)
- return (adapter || adapterBluez5);
+ return adapter;
}
QBluetoothDeviceDiscoveryAgent::DiscoveryMethods QBluetoothDeviceDiscoveryAgent::supportedDiscoveryMethods()
@@ -125,137 +71,38 @@ QBluetoothDeviceDiscoveryAgent::DiscoveryMethods QBluetoothDeviceDiscoveryAgent:
void QBluetoothDeviceDiscoveryAgentPrivate::start(QBluetoothDeviceDiscoveryAgent::DiscoveryMethods methods)
{
- // Currently both BlueZ backends do not distinguish discovery methods.
- // The DBus API's always return both device types. Therefore we ignore
- // the passed in methods.
-
if (pendingCancel == true) {
pendingStart = true;
return;
}
+ lastError = QBluetoothDeviceDiscoveryAgent::NoError;
+ errorString.clear();
discoveredDevices.clear();
devicesProperties.clear();
- if (managerBluez5) {
- startBluez5(methods);
- return;
- }
-
- QDBusPendingReply<QDBusObjectPath> reply;
-
- if (m_adapterAddress.isNull())
- reply = manager->DefaultAdapter();
- else
- reply = manager->FindAdapter(m_adapterAddress.toString());
- reply.waitForFinished();
-
- if (reply.isError()) {
- errorString = reply.error().message();
- qCDebug(QT_BT_BLUEZ) << Q_FUNC_INFO << "ERROR: " << errorString;
- lastError = QBluetoothDeviceDiscoveryAgent::InputOutputError;
- Q_Q(QBluetoothDeviceDiscoveryAgent);
- emit q->error(lastError);
- return;
- }
-
- adapter = new OrgBluezAdapterInterface(QStringLiteral("org.bluez"), reply.value().path(),
- QDBusConnection::systemBus());
-
- Q_Q(QBluetoothDeviceDiscoveryAgent);
- QObject::connect(adapter, &OrgBluezAdapterInterface::DeviceFound,
- q, [this](const QString &address, const QVariantMap &dict) {
- this->_q_deviceFound(address, dict);
- });
- QObject::connect(adapter, &OrgBluezAdapterInterface::PropertyChanged,
- q, [this](const QString &name, const QDBusVariant &value) {
- this->_q_propertyChanged(name, value);
- });
-
- QDBusPendingReply<QVariantMap> propertiesReply = adapter->GetProperties();
- propertiesReply.waitForFinished();
- if (propertiesReply.isError()) {
- errorString = propertiesReply.error().message();
- delete adapter;
- adapter = nullptr;
- qCDebug(QT_BT_BLUEZ) << Q_FUNC_INFO << "ERROR: " << errorString;
- lastError = QBluetoothDeviceDiscoveryAgent::InputOutputError;
- Q_Q(QBluetoothDeviceDiscoveryAgent);
- delete adapter;
- adapter = nullptr;
- emit q->error(lastError);
- return;
- }
-
- if (!propertiesReply.value().value(QStringLiteral("Powered")).toBool()) {
- qCDebug(QT_BT_BLUEZ) << "Aborting device discovery due to offline Bluetooth Adapter";
- lastError = QBluetoothDeviceDiscoveryAgent::PoweredOffError;
- errorString = QBluetoothDeviceDiscoveryAgent::tr("Device is powered off");
- delete adapter;
- adapter = nullptr;
- emit q->error(lastError);
- return;
- }
-
- if (propertiesReply.value().value(QStringLiteral("Discovering")).toBool()) {
- /* The discovery session is already ongoing. BTLE devices are advertised
- immediately after the start of the device discovery session. Hence if the
- session is already ongoing, we have just missed the BTLE device
- advertisement.
-
- This always happens during the second device discovery run in
- the current process. The first discovery doesn't have this issue.
- As to why the discovery session remains active despite the previous one
- being terminated is not known. This may be a bug in Bluez4.
-
- To workaround this issue we have to wait for two discovery
- sessions cycles.
- */
- qCDebug(QT_BT_BLUEZ) << "Using BTLE device discovery workaround.";
- useExtendedDiscovery = true;
- } else {
- useExtendedDiscovery = false;
- }
-
- QDBusPendingReply<> discoveryReply = adapter->StartDiscovery();
- discoveryReply.waitForFinished();
- if (discoveryReply.isError()) {
- delete adapter;
- adapter = nullptr;
- errorString = discoveryReply.error().message();
- lastError = QBluetoothDeviceDiscoveryAgent::InputOutputError;
- Q_Q(QBluetoothDeviceDiscoveryAgent);
- qCDebug(QT_BT_BLUEZ) << Q_FUNC_INFO << "ERROR: " << errorString;
- emit q->error(lastError);
- return;
- }
-}
-
-void QBluetoothDeviceDiscoveryAgentPrivate::startBluez5(QBluetoothDeviceDiscoveryAgent::DiscoveryMethods methods)
-{
Q_Q(QBluetoothDeviceDiscoveryAgent);
bool ok = false;
- const QString adapterPath = findAdapterForAddress(m_adapterAddress, &ok);
+ const QString adapterPath = findAdapterForAddress(adapterAddress, &ok);
if (!ok || adapterPath.isEmpty()) {
qCWarning(QT_BT_BLUEZ) << "Cannot find Bluez 5 adapter for device search" << ok;
lastError = QBluetoothDeviceDiscoveryAgent::InputOutputError;
errorString = QBluetoothDeviceDiscoveryAgent::tr("Cannot find valid Bluetooth adapter.");
- q->error(lastError);
+ q->errorOccurred(lastError);
return;
}
- adapterBluez5 = new OrgBluezAdapter1Interface(QStringLiteral("org.bluez"),
- adapterPath,
- QDBusConnection::systemBus());
+ adapter = new OrgBluezAdapter1Interface(QStringLiteral("org.bluez"), adapterPath,
+ QDBusConnection::systemBus());
- if (!adapterBluez5->powered()) {
+ if (!adapter->powered()) {
qCDebug(QT_BT_BLUEZ) << "Aborting device discovery due to offline Bluetooth Adapter";
lastError = QBluetoothDeviceDiscoveryAgent::PoweredOffError;
errorString = QBluetoothDeviceDiscoveryAgent::tr("Device is powered off");
- delete adapterBluez5;
- adapterBluez5 = nullptr;
- emit q->error(lastError);
+ delete adapter;
+ adapter = nullptr;
+ emit q->errorOccurred(lastError);
return;
}
@@ -269,7 +116,7 @@ void QBluetoothDeviceDiscoveryAgentPrivate::startBluez5(QBluetoothDeviceDiscover
// older BlueZ 5.x versions don't have this function
// filterReply returns UnknownMethod which we ignore
- QDBusPendingReply<> filterReply = adapterBluez5->SetDiscoveryFilter(map);
+ QDBusPendingReply<> filterReply = adapter->SetDiscoveryFilter(map);
filterReply.waitForFinished();
if (filterReply.isError()) {
if (filterReply.error().type() == QDBusError::Other
@@ -278,23 +125,34 @@ void QBluetoothDeviceDiscoveryAgentPrivate::startBluez5(QBluetoothDeviceDiscover
lastError = QBluetoothDeviceDiscoveryAgent::UnsupportedDiscoveryMethod;
errorString = QBluetoothDeviceDiscoveryAgent::tr("One or more device discovery methods "
"are not supported on this platform");
- delete adapterBluez5;
- adapterBluez5 = nullptr;
- emit q->error(lastError);
+ delete adapter;
+ adapter = nullptr;
+ emit q->errorOccurred(lastError);
return;
} else if (filterReply.error().type() != QDBusError::UnknownMethod) {
qCDebug(QT_BT_BLUEZ) << "SetDiscoveryFilter failed:" << filterReply.error();
}
}
- QtBluezDiscoveryManager::instance()->registerDiscoveryInterest(adapterBluez5->path());
+ QtBluezDiscoveryManager::instance()->registerDiscoveryInterest(adapter->path());
QObject::connect(QtBluezDiscoveryManager::instance(), &QtBluezDiscoveryManager::discoveryInterrupted,
q, [this](const QString &path){
this->_q_discoveryInterrupted(path);
});
+ OrgFreedesktopDBusPropertiesInterface *prop = new OrgFreedesktopDBusPropertiesInterface(
+ QStringLiteral("org.bluez"), QStringLiteral(""), QDBusConnection::systemBus());
+ QObject::connect(prop, &OrgFreedesktopDBusPropertiesInterface::PropertiesChanged,
+ q, [this](const QString &interface, const QVariantMap &changedProperties,
+ const QStringList &invalidatedProperties,
+ const QDBusMessage &signal) {
+ this->_q_PropertiesChanged(interface, signal.path(), changedProperties, invalidatedProperties);
+ });
+
+ // remember what we have to cleanup
+ propertyMonitors.append(prop);
// collect initial set of information
- QDBusPendingReply<ManagedObjectList> reply = managerBluez5->GetManagedObjects();
+ QDBusPendingReply<ManagedObjectList> reply = manager->GetManagedObjects();
reply.waitForFinished();
if (!reply.isError()) {
ManagedObjectList managedObjectList = reply.value();
@@ -307,10 +165,10 @@ void QBluetoothDeviceDiscoveryAgentPrivate::startBluez5(QBluetoothDeviceDiscover
if (iface == QStringLiteral("org.bluez.Device1")) {
- if (path.path().indexOf(adapterBluez5->path()) != 0)
+ if (path.path().indexOf(adapter->path()) != 0)
continue; //devices whose path doesn't start with same path we skip
- deviceFoundBluez5(path.path(), jt.value());
+ deviceFound(path.path(), jt.value());
if (!isActive()) // Can happen if stop() was called from a slot in user code.
return;
}
@@ -336,72 +194,13 @@ void QBluetoothDeviceDiscoveryAgentPrivate::startBluez5(QBluetoothDeviceDiscover
void QBluetoothDeviceDiscoveryAgentPrivate::stop()
{
- if (!adapter && !adapterBluez5)
+ if (!adapter)
return;
qCDebug(QT_BT_BLUEZ) << Q_FUNC_INFO;
pendingCancel = true;
pendingStart = false;
- if (adapter) {
- QDBusPendingReply<> reply = adapter->StopDiscovery();
- reply.waitForFinished();
- } else {
- _q_discoveryFinished();
- }
-}
-
-void QBluetoothDeviceDiscoveryAgentPrivate::_q_deviceFound(const QString &address,
- const QVariantMap &dict)
-{
- const QBluetoothAddress btAddress(address);
- const QString btName = dict.value(QStringLiteral("Name")).toString();
- quint32 btClass = dict.value(QStringLiteral("Class")).toUInt();
-
- qCDebug(QT_BT_BLUEZ) << "Discovered: " << address << btName
- << "Num UUIDs" << dict.value(QStringLiteral("UUIDs")).toStringList().count()
- << "total device" << discoveredDevices.count() << "cached"
- << dict.value(QStringLiteral("Cached")).toBool()
- << "RSSI" << dict.value(QStringLiteral("RSSI")).toInt();
-
- QBluetoothDeviceInfo device(btAddress, btName, btClass);
- if (dict.value(QStringLiteral("RSSI")).isValid())
- device.setRssi(dict.value(QStringLiteral("RSSI")).toInt());
- QVector<QBluetoothUuid> uuids;
- const QStringList uuidStrings
- = dict.value(QLatin1String("UUIDs")).toStringList();
- for (const QString &u : uuidStrings)
- uuids.append(QBluetoothUuid(u));
- device.setServiceUuids(uuids);
- device.setCached(dict.value(QStringLiteral("Cached")).toBool());
-
-
- /*
- * Bluez v4.1 does not have extra bit which gives information if device is Bluetooth
- * Low Energy device and the way to discover it is with Class property of the Bluetooth device.
- * Low Energy devices do not have property Class.
- */
- if (btClass == 0)
- device.setCoreConfigurations(QBluetoothDeviceInfo::LowEnergyCoreConfiguration);
- else
- device.setCoreConfigurations(QBluetoothDeviceInfo::BaseRateCoreConfiguration);
- for (int i = 0; i < discoveredDevices.size(); i++) {
- if (discoveredDevices[i].address() == device.address()) {
- if (discoveredDevices[i] == device) {
- qCDebug(QT_BT_BLUEZ) << "Duplicate: " << address;
- return;
- }
- discoveredDevices.replace(i, device);
- Q_Q(QBluetoothDeviceDiscoveryAgent);
- qCDebug(QT_BT_BLUEZ) << "Updated: " << address;
-
- emit q->deviceDiscovered(device);
- return; // this works if the list doesn't contain duplicates. Don't let it.
- }
- }
- qCDebug(QT_BT_BLUEZ) << "Emit: " << address;
- discoveredDevices.append(device);
- Q_Q(QBluetoothDeviceDiscoveryAgent);
- emit q->deviceDiscovered(device);
+ _q_discoveryFinished();
}
// Returns invalid QBluetoothDeviceInfo in case of error
@@ -417,7 +216,7 @@ static QBluetoothDeviceInfo createDeviceInfoFromBluez5Device(const QVariantMap&
QBluetoothDeviceInfo deviceInfo(btAddress, btName, btClass);
deviceInfo.setRssi(qvariant_cast<short>(properties[QStringLiteral("RSSI")]));
- QVector<QBluetoothUuid> uuids;
+ QList<QBluetoothUuid> uuids;
bool foundLikelyLowEnergyUuid = false;
const QStringList foundUuids = qvariant_cast<QStringList>(properties[QStringLiteral("UUIDs")]);
for (const auto &u: foundUuids) {
@@ -429,7 +228,8 @@ static QBluetoothDeviceInfo createDeviceInfoFromBluez5Device(const QVariantMap&
//once we found one BTLE service we are done
bool ok = false;
quint16 shortId = id.toUInt16(&ok);
- if (ok && ((shortId & QBluetoothUuid::GenericAccess) == QBluetoothUuid::GenericAccess))
+ quint16 genericAccessInt = static_cast<quint16>(QBluetoothUuid::ServiceClassUuid::GenericAccess);
+ if (ok && ((shortId & genericAccessInt) == genericAccessInt))
foundLikelyLowEnergyUuid = true;
}
uuids.append(id);
@@ -445,16 +245,23 @@ static QBluetoothDeviceInfo createDeviceInfoFromBluez5Device(const QVariantMap&
}
const ManufacturerDataList deviceManufacturerData = qdbus_cast<ManufacturerDataList>(properties[QStringLiteral("ManufacturerData")]);
- const QList<quint16> keys = deviceManufacturerData.keys();
- for (quint16 key : keys)
+ const QList<quint16> keysManufacturer = deviceManufacturerData.keys();
+ for (quint16 key : keysManufacturer)
deviceInfo.setManufacturerData(
key, deviceManufacturerData.value(key).variant().toByteArray());
+ const ServiceDataList deviceServiceData =
+ qdbus_cast<ServiceDataList>(properties[QStringLiteral("ServiceData")]);
+ const QList<QString> keysService = deviceServiceData.keys();
+ for (QString key : keysService)
+ deviceInfo.setServiceData(QBluetoothUuid(key),
+ deviceServiceData.value(key).variant().toByteArray());
+
return deviceInfo;
}
-void QBluetoothDeviceDiscoveryAgentPrivate::deviceFoundBluez5(const QString &devicePath,
- const QVariantMap &properties)
+void QBluetoothDeviceDiscoveryAgentPrivate::deviceFound(const QString &devicePath,
+ const QVariantMap &properties)
{
Q_Q(QBluetoothDeviceDiscoveryAgent);
@@ -462,8 +269,8 @@ void QBluetoothDeviceDiscoveryAgentPrivate::deviceFoundBluez5(const QString &dev
return;
auto deviceAdapter = qvariant_cast<QDBusObjectPath>(properties[QStringLiteral("Adapter")]);
- if (deviceAdapter.path() != adapterBluez5->path())
- return;
+ if (deviceAdapter.path() != adapter->path())
+ return;
// read information
QBluetoothDeviceInfo deviceInfo = createDeviceInfoFromBluez5Device(properties);
@@ -471,26 +278,16 @@ void QBluetoothDeviceDiscoveryAgentPrivate::deviceFoundBluez5(const QString &dev
return;
qCDebug(QT_BT_BLUEZ) << "Discovered: " << deviceInfo.name() << deviceInfo.address()
- << "Num UUIDs" << deviceInfo.serviceUuids().count()
- << "total device" << discoveredDevices.count() << "cached"
+ << "Num UUIDs" << deviceInfo.serviceUuids().size()
+ << "total device" << discoveredDevices.size() << "cached"
<< "RSSI" << deviceInfo.rssi()
- << "Num ManufacturerData" << deviceInfo.manufacturerData().size();
-
- OrgFreedesktopDBusPropertiesInterface *prop = new OrgFreedesktopDBusPropertiesInterface(
- QStringLiteral("org.bluez"), devicePath, QDBusConnection::systemBus(), q);
- QObject::connect(prop, &OrgFreedesktopDBusPropertiesInterface::PropertiesChanged,
- q, [this](const QString &interface, const QVariantMap &changedProperties,
- const QStringList &invalidatedProperties) {
- this->_q_PropertiesChanged(interface, changedProperties, invalidatedProperties);
- });
-
- // remember what we have to cleanup
- propertyMonitors.append(prop);
+ << "Num ManufacturerData" << deviceInfo.manufacturerData().size()
+ << "Num ServiceData" << deviceInfo.serviceData().size();
// Cache the properties so we do not have to access dbus every time to get a value
devicesProperties[devicePath] = properties;
- for (int i = 0; i < discoveredDevices.size(); i++) {
+ for (qsizetype i = 0; i < discoveredDevices.size(); ++i) {
if (discoveredDevices[i].address() == deviceInfo.address()) {
if (lowEnergySearchTimeout > 0 && discoveredDevices[i] == deviceInfo) {
qCDebug(QT_BT_BLUEZ) << "Duplicate: " << deviceInfo.address();
@@ -507,69 +304,6 @@ void QBluetoothDeviceDiscoveryAgentPrivate::deviceFoundBluez5(const QString &dev
emit q->deviceDiscovered(deviceInfo);
}
-void QBluetoothDeviceDiscoveryAgentPrivate::_q_propertyChanged(const QString &name,
- const QDBusVariant &value)
-{
- qCDebug(QT_BT_BLUEZ) << Q_FUNC_INFO << name << value.variant();
-
- if (name == QLatin1String("Discovering")) {
- if (!value.variant().toBool()) {
- Q_Q(QBluetoothDeviceDiscoveryAgent);
- if (pendingCancel && !pendingStart) {
- adapter->deleteLater();
- adapter = nullptr;
-
- pendingCancel = false;
- emit q->canceled();
- } else if (pendingStart) {
- adapter->deleteLater();
- adapter = nullptr;
-
- pendingStart = false;
- pendingCancel = false;
- // start parameter ignored since Bluez 4 doesn't distinguish them
- start(QBluetoothDeviceDiscoveryAgent::ClassicMethod
- | QBluetoothDeviceDiscoveryAgent::LowEnergyMethod);
- } else {
- // happens when agent is created while other agent called StopDiscovery()
- if (!adapter)
- return;
-
- if (useExtendedDiscovery) {
- useExtendedDiscovery = false;
- /* We don't use the Start/StopDiscovery combo here
- Using this combo surppresses the BTLE device.
- */
- extendedDiscoveryTimer.start();
- return;
- }
-
- QDBusPendingReply<> reply = adapter->StopDiscovery();
- reply.waitForFinished();
- adapter->deleteLater();
- adapter = nullptr;
- emit q->finished();
- }
- } else {
- if (extendedDiscoveryTimer.isActive())
- extendedDiscoveryTimer.stop();
- }
- }
-}
-
-void QBluetoothDeviceDiscoveryAgentPrivate::_q_extendedDeviceDiscoveryTimeout()
-{
-
- if (adapter) {
- adapter->deleteLater();
- adapter = nullptr;
- }
- if (isActive()) {
- Q_Q(QBluetoothDeviceDiscoveryAgent);
- emit q->finished();
- }
-}
-
void QBluetoothDeviceDiscoveryAgentPrivate::_q_InterfacesAdded(const QDBusObjectPath &object_path,
InterfaceList interfaces_and_properties)
{
@@ -580,8 +314,9 @@ void QBluetoothDeviceDiscoveryAgentPrivate::_q_InterfacesAdded(const QDBusObject
if (interfaces_and_properties.contains(QStringLiteral("org.bluez.Device1"))) {
// device interfaces belonging to different adapter
- // will be filtered out by deviceFoundBluez5();
- deviceFoundBluez5(object_path.path(), interfaces_and_properties[QStringLiteral("org.bluez.Device1")]);
+ // will be filtered out by deviceFound();
+ deviceFound(object_path.path(),
+ interfaces_and_properties[QStringLiteral("org.bluez.Device1")]);
}
}
@@ -593,13 +328,13 @@ void QBluetoothDeviceDiscoveryAgentPrivate::_q_discoveryFinished()
discoveryTimer->stop();
QtBluezDiscoveryManager::instance()->disconnect(q);
- QtBluezDiscoveryManager::instance()->unregisterDiscoveryInterest(adapterBluez5->path());
+ QtBluezDiscoveryManager::instance()->unregisterDiscoveryInterest(adapter->path());
qDeleteAll(propertyMonitors);
propertyMonitors.clear();
- delete adapterBluez5;
- adapterBluez5 = nullptr;
+ delete adapter;
+ adapter = nullptr;
if (pendingCancel && !pendingStart) {
pendingCancel = false;
@@ -621,7 +356,7 @@ void QBluetoothDeviceDiscoveryAgentPrivate::_q_discoveryInterrupted(const QStrin
if (!q->isActive())
return;
- if (path == adapterBluez5->path()) {
+ if (path == adapter->path()) {
qCWarning(QT_BT_BLUEZ) << "Device discovery aborted due to unexpected adapter changes from another process.";
if (discoveryTimer)
@@ -631,16 +366,17 @@ void QBluetoothDeviceDiscoveryAgentPrivate::_q_discoveryInterrupted(const QStrin
// no need to call unregisterDiscoveryInterest since QtBluezDiscoveryManager
// does this automatically when emitting discoveryInterrupted(QString) signal
- delete adapterBluez5;
- adapterBluez5 = nullptr;
+ delete adapter;
+ adapter = nullptr;
errorString = QBluetoothDeviceDiscoveryAgent::tr("Bluetooth adapter error");
lastError = QBluetoothDeviceDiscoveryAgent::InputOutputError;
- emit q->error(lastError);
+ emit q->errorOccurred(lastError);
}
}
void QBluetoothDeviceDiscoveryAgentPrivate::_q_PropertiesChanged(const QString &interface,
+ const QString &path,
const QVariantMap &changed_properties,
const QStringList &invalidated_properties)
{
@@ -648,12 +384,6 @@ void QBluetoothDeviceDiscoveryAgentPrivate::_q_PropertiesChanged(const QString &
if (interface != QStringLiteral("org.bluez.Device1"))
return;
- OrgFreedesktopDBusPropertiesInterface *props =
- qobject_cast<OrgFreedesktopDBusPropertiesInterface *>(q->sender());
- if (!props)
- return;
-
- const QString path = props->path();
if (!devicesProperties.contains(path))
return;
@@ -675,7 +405,7 @@ void QBluetoothDeviceDiscoveryAgentPrivate::_q_PropertiesChanged(const QString &
if (changed_properties.contains(QStringLiteral("RSSI"))
|| changed_properties.contains(QStringLiteral("ManufacturerData"))) {
- for (int i = 0; i < discoveredDevices.size(); i++) {
+ for (qsizetype i = 0; i < discoveredDevices.size(); ++i) {
if (discoveredDevices[i].address() == info.address()) {
QBluetoothDeviceInfo::Fields updatedFields = QBluetoothDeviceInfo::Field::None;
if (changed_properties.contains(QStringLiteral("RSSI"))) {
diff --git a/src/bluetooth/qbluetoothdevicediscoveryagent_darwin.mm b/src/bluetooth/qbluetoothdevicediscoveryagent_darwin.mm
index 9053e564..0f32898b 100644
--- a/src/bluetooth/qbluetoothdevicediscoveryagent_darwin.mm
+++ b/src/bluetooth/qbluetoothdevicediscoveryagent_darwin.mm
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qbluetoothdevicediscoveryagent_p.h"
#include "qbluetoothdevicediscoveryagent.h"
@@ -60,7 +24,8 @@
#include "qbluetoothuuid.h"
#include <QtCore/qloggingcategory.h>
-#include <QtCore/qscopedpointer.h>
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qpermissions.h>
#include <QtCore/qvector.h>
#include <QtCore/qglobal.h>
#include <QtCore/qstring.h>
@@ -84,22 +49,13 @@ void registerQDeviceDiscoveryMetaType()
initDone = true;
}
}
-#ifdef Q_OS_MACOS
-using InquiryObjC = QT_MANGLE_NAMESPACE(DarwinBTClassicDeviceInquiry);
-#endif // Q_OS_MACOS
-
-using LEInquiryObjC = QT_MANGLE_NAMESPACE(DarwinBTLEDeviceInquiry);
} //namespace
QBluetoothDeviceDiscoveryAgentPrivate::QBluetoothDeviceDiscoveryAgentPrivate(const QBluetoothAddress &adapter,
QBluetoothDeviceDiscoveryAgent *q) :
- inquiryType(QBluetoothDeviceDiscoveryAgent::GeneralUnlimitedInquiry),
- lastError(QBluetoothDeviceDiscoveryAgent::NoError),
- agentState(NonActive),
adapterAddress(adapter),
- startPending(false),
- stopPending(false),
+ agentState(NonActive),
lowEnergySearchTimeout(DarwinBluetooth::defaultLEScanTimeoutMS),
#ifdef Q_OS_MACOS
requestedMethods(QBluetoothDeviceDiscoveryAgent::ClassicMethod | QBluetoothDeviceDiscoveryAgent::LowEnergyMethod),
@@ -111,15 +67,6 @@ QBluetoothDeviceDiscoveryAgentPrivate::QBluetoothDeviceDiscoveryAgentPrivate(con
registerQDeviceDiscoveryMetaType();
Q_ASSERT_X(q != nullptr, Q_FUNC_INFO, "invalid q_ptr (null)");
-
-#ifdef Q_OS_MACOS
- IOBluetoothHostController *hostController = [IOBluetoothHostController defaultController];
- if (!hostController || [hostController powerState] != kBluetoothHCIPowerStateON) {
- qCCritical(QT_BT_DARWIN) << "no default host controller or adapter is off";
- return;
- }
- controller.reset(hostController, DarwinBluetooth::RetainPolicy::doInitialRetain);
-#endif
}
QBluetoothDeviceDiscoveryAgentPrivate::~QBluetoothDeviceDiscoveryAgentPrivate()
@@ -128,7 +75,7 @@ QBluetoothDeviceDiscoveryAgentPrivate::~QBluetoothDeviceDiscoveryAgentPrivate()
// We want the LE scan to stop as soon as possible.
if (dispatch_queue_t leQueue = DarwinBluetooth::qt_LE_queue()) {
// Local variable to be retained ...
- LEInquiryObjC *inq = inquiryLE.getAs<LEInquiryObjC>();
+ DarwinBTLEDeviceInquiry *inq = inquiryLE.getAs<DarwinBTLEDeviceInquiry>();
dispatch_sync(leQueue, ^{
[inq stop];
});
@@ -149,19 +96,59 @@ bool QBluetoothDeviceDiscoveryAgentPrivate::isActive() const
void QBluetoothDeviceDiscoveryAgentPrivate::start(QBluetoothDeviceDiscoveryAgent::DiscoveryMethods methods)
{
+ using namespace DarwinBluetooth;
+
Q_ASSERT(!isActive());
- Q_ASSERT(lastError != QBluetoothDeviceDiscoveryAgent::InvalidBluetoothAdapterError);
Q_ASSERT(methods & (QBluetoothDeviceDiscoveryAgent::ClassicMethod
| QBluetoothDeviceDiscoveryAgent::LowEnergyMethod));
#ifdef Q_OS_MACOS
if (!controller) {
- setError(QBluetoothDeviceDiscoveryAgent::InvalidBluetoothAdapterError);
- emit q_ptr->error(lastError);
- return;
+ IOBluetoothHostController *hostController = [IOBluetoothHostController defaultController];
+ if (!hostController) {
+ qCWarning(QT_BT_DARWIN) << "No default Bluetooth controller found";
+ setError(QBluetoothDeviceDiscoveryAgent::InvalidBluetoothAdapterError);
+ emit q_ptr->errorOccurred(lastError);
+ return;
+ } else if ([hostController powerState] != kBluetoothHCIPowerStateON) {
+ qCWarning(QT_BT_DARWIN) << "Default Bluetooth controller is OFF";
+ setError(QBluetoothDeviceDiscoveryAgent::PoweredOffError);
+ emit q_ptr->errorOccurred(lastError);
+ return;
+ } else if (!adapterAddress.isNull()) {
+ // If user has provided the local address, check that it matches with the actual
+ NSString *const hciAddress = [hostController addressAsString];
+ if (adapterAddress != QBluetoothAddress(QString::fromNSString(hciAddress))) {
+ qCWarning(QT_BT_DARWIN) << "Provided address" << adapterAddress
+ << "does not match with adapter:" << hciAddress;
+ setError(QBluetoothDeviceDiscoveryAgent::InvalidBluetoothAdapterError);
+ emit q_ptr->errorOccurred(lastError);
+ return;
+ }
+ }
+ controller.reset(hostController, DarwinBluetooth::RetainPolicy::doInitialRetain);
}
#endif // Q_OS_MACOS
+ // To be able to scan for devices, iOS requires Info.plist containing
+ // NSBluetoothAlwaysUsageDescription entry with a string, explaining
+ // the usage of Bluetooth interface. macOS also requires this description,
+ // starting from Monterey.
+
+ // No Classic on iOS, and Classic does not require a description on macOS:
+ if (methods.testFlag(QBluetoothDeviceDiscoveryAgent::LowEnergyMethod)) {
+ const auto permissionStatus = qApp->checkPermission(QBluetoothPermission{});
+ if (permissionStatus != Qt::PermissionStatus::Granted) {
+ qCWarning(QT_BT_DARWIN,
+ "Use of Bluetooth LE requires explicitly requested permissions.");
+ setError(QBluetoothDeviceDiscoveryAgent::MissingPermissionsError);
+ emit q_ptr->errorOccurred(lastError);
+ // Arguably, Classic scan is still possible, but let's keep the logic
+ // simple.
+ return;
+ }
+ }
+
requestedMethods = methods;
if (stopPending) {
@@ -196,25 +183,25 @@ void QBluetoothDeviceDiscoveryAgentPrivate::startClassic()
if (!inquiry) {
// The first Classic scan for this DDA.
- inquiry.reset([[InquiryObjC alloc] initWithDelegate:this],
+ inquiry.reset([[DarwinBTClassicDeviceInquiry alloc] initWithDelegate:this],
DarwinBluetooth::RetainPolicy::noInitialRetain);
if (!inquiry) {
qCCritical(QT_BT_DARWIN) << "failed to initialize an Classic device inquiry";
setError(QBluetoothDeviceDiscoveryAgent::UnknownError,
QCoreApplication::translate(DEV_DISCOVERY, DD_NOT_STARTED));
- emit q_ptr->error(lastError);
+ emit q_ptr->errorOccurred(lastError);
return;
}
}
agentState = ClassicScan;
- const IOReturn res = [inquiry.getAs<InquiryObjC>() start];
+ const IOReturn res = [inquiry.getAs<DarwinBTClassicDeviceInquiry>() start];
if (res != kIOReturnSuccess) {
setError(res, QCoreApplication::translate(DEV_DISCOVERY, DD_NOT_STARTED));
agentState = NonActive;
- emit q_ptr->error(lastError);
+ emit q_ptr->errorOccurred(lastError);
}
}
@@ -227,38 +214,38 @@ void QBluetoothDeviceDiscoveryAgentPrivate::startLE()
using namespace DarwinBluetooth;
- QScopedPointer<LECBManagerNotifier> notifier(new LECBManagerNotifier);
+ std::unique_ptr<LECBManagerNotifier> notifier = std::make_unique<LECBManagerNotifier>();
// Connections:
using ErrMemFunPtr = void (LECBManagerNotifier::*)(QBluetoothDeviceDiscoveryAgent::Error);
- notifier->connect(notifier.data(), ErrMemFunPtr(&LECBManagerNotifier::CBManagerError),
+ notifier->connect(notifier.get(), ErrMemFunPtr(&LECBManagerNotifier::CBManagerError),
this, &QBluetoothDeviceDiscoveryAgentPrivate::LEinquiryError);
- notifier->connect(notifier.data(), &LECBManagerNotifier::LEnotSupported,
+ notifier->connect(notifier.get(), &LECBManagerNotifier::LEnotSupported,
this, &QBluetoothDeviceDiscoveryAgentPrivate::LEnotSupported);
- notifier->connect(notifier.data(), &LECBManagerNotifier::discoveryFinished,
+ notifier->connect(notifier.get(), &LECBManagerNotifier::discoveryFinished,
this, &QBluetoothDeviceDiscoveryAgentPrivate::LEinquiryFinished);
using DeviceMemFunPtr = void (QBluetoothDeviceDiscoveryAgentPrivate::*)(const QBluetoothDeviceInfo &);
- notifier->connect(notifier.data(), &LECBManagerNotifier::deviceDiscovered,
+ notifier->connect(notifier.get(), &LECBManagerNotifier::deviceDiscovered,
this, DeviceMemFunPtr(&QBluetoothDeviceDiscoveryAgentPrivate::deviceFound));
// Check queue and create scanner:
- inquiryLE.reset([[LEInquiryObjC alloc] initWithNotifier:notifier.data()],
+ inquiryLE.reset([[DarwinBTLEDeviceInquiry alloc] initWithNotifier:notifier.get()],
DarwinBluetooth::RetainPolicy::noInitialRetain);
if (inquiryLE)
- notifier.take(); // Whatever happens next, inquiryLE is already the owner ...
+ notifier.release(); // Whatever happens next, inquiryLE is already the owner ...
dispatch_queue_t leQueue(qt_LE_queue());
if (!leQueue || !inquiryLE) {
setError(QBluetoothDeviceDiscoveryAgent::UnknownError,
QCoreApplication::translate(DEV_DISCOVERY, DD_NOT_STARTED_LE));
agentState = NonActive;
- emit q_ptr->error(lastError);
+ emit q_ptr->errorOccurred(lastError);
return;
}
// Now start in on LE queue:
agentState = LEScan;
// We need the local variable so that it's retained ...
- LEInquiryObjC *inq = inquiryLE.getAs<LEInquiryObjC>();
+ DarwinBTLEDeviceInquiry *inq = inquiryLE.getAs<DarwinBTLEDeviceInquiry>();
dispatch_async(leQueue, ^{
[inq startWithTimeout:lowEnergySearchTimeout];
});
@@ -280,23 +267,23 @@ void QBluetoothDeviceDiscoveryAgentPrivate::stop()
#ifdef Q_OS_MACOS
if (agentState == ClassicScan) {
- const IOReturn res = [inquiry.getAs<InquiryObjC>() stop];
+ const IOReturn res = [inquiry.getAs<DarwinBTClassicDeviceInquiry>() stop];
if (res != kIOReturnSuccess) {
qCWarning(QT_BT_DARWIN) << "failed to stop";
startPending = prevStart;
stopPending = false;
setError(res, QCoreApplication::translate(DEV_DISCOVERY, DD_NOT_STOPPED));
- emit q_ptr->error(lastError);
+ emit q_ptr->errorOccurred(lastError);
}
} else {
#else
{
- Q_UNUSED(prevStart)
+ Q_UNUSED(prevStart);
#endif // Q_OS_MACOS
dispatch_queue_t leQueue(qt_LE_queue());
Q_ASSERT(leQueue);
// We need the local variable so that it's retained ...
- LEInquiryObjC *inq = inquiryLE.getAs<LEInquiryObjC>();
+ DarwinBTLEDeviceInquiry *inq = inquiryLE.getAs<DarwinBTLEDeviceInquiry>();
dispatch_sync(leQueue, ^{
[inq stop];
});
@@ -341,7 +328,7 @@ void QBluetoothDeviceDiscoveryAgentPrivate::error(IOReturn error)
setError(error);
- emit q_ptr->error(lastError);
+ emit q_ptr->errorOccurred(lastError);
}
void QBluetoothDeviceDiscoveryAgentPrivate::classicDeviceFound(void *obj)
@@ -371,7 +358,7 @@ void QBluetoothDeviceDiscoveryAgentPrivate::classicDeviceFound(void *obj)
deviceInfo.setCoreConfigurations(QBluetoothDeviceInfo::BaseRateCoreConfiguration);
deviceInfo.setRssi(device.RSSI);
- const QVector<QBluetoothUuid> uuids(DarwinBluetooth::extract_services_uuids(device));
+ const QList<QBluetoothUuid> uuids(DarwinBluetooth::extract_services_uuids(device));
deviceInfo.setServiceUuids(uuids);
deviceFound(deviceInfo);
@@ -393,7 +380,7 @@ void QBluetoothDeviceDiscoveryAgentPrivate::setError(QBluetoothDeviceDiscoveryAg
{
lastError = error;
- if (text.length() > 0) {
+ if (!text.isEmpty()) {
errorString = text;
} else {
switch (lastError) {
@@ -412,6 +399,9 @@ void QBluetoothDeviceDiscoveryAgentPrivate::setError(QBluetoothDeviceDiscoveryAg
case QBluetoothDeviceDiscoveryAgent::UnsupportedPlatformError:
errorString = QCoreApplication::translate(DEV_DISCOVERY, DD_NOTSUPPORTED);
break;
+ case QBluetoothDeviceDiscoveryAgent::MissingPermissionsError:
+ errorString = QCoreApplication::translate(DEV_DISCOVERY, DD_MISSING_PERMISSION);
+ break;
case QBluetoothDeviceDiscoveryAgent::UnknownError:
default:
errorString = QCoreApplication::translate(DEV_DISCOVERY, DD_UNKNOWN_ERROR);
@@ -422,7 +412,8 @@ void QBluetoothDeviceDiscoveryAgentPrivate::setError(QBluetoothDeviceDiscoveryAg
void QBluetoothDeviceDiscoveryAgentPrivate::LEinquiryError(QBluetoothDeviceDiscoveryAgent::Error error)
{
Q_ASSERT(error == QBluetoothDeviceDiscoveryAgent::PoweredOffError
- || error == QBluetoothDeviceDiscoveryAgent::UnsupportedDiscoveryMethod);
+ || error == QBluetoothDeviceDiscoveryAgent::UnsupportedDiscoveryMethod
+ || error == QBluetoothDeviceDiscoveryAgent::MissingPermissionsError);
inquiryLE.reset();
@@ -430,7 +421,7 @@ void QBluetoothDeviceDiscoveryAgentPrivate::LEinquiryError(QBluetoothDeviceDisco
stopPending = false;
agentState = NonActive;
setError(error);
- emit q_ptr->error(lastError);
+ emit q_ptr->errorOccurred(lastError);
}
void QBluetoothDeviceDiscoveryAgentPrivate::LEnotSupported()
@@ -453,7 +444,7 @@ void QBluetoothDeviceDiscoveryAgentPrivate::LEnotSupported()
startPending = false;
stopPending = false;
setError(QBluetoothDeviceDiscoveryAgent::UnsupportedPlatformError);
- emit q_ptr->error(lastError);
+ emit q_ptr->errorOccurred(lastError);
#endif
}
@@ -486,7 +477,7 @@ void QBluetoothDeviceDiscoveryAgentPrivate::deviceFound(const QBluetoothDeviceIn
#else
true;
#endif // Q_OS_MACOS
- for (int i = 0, e = discoveredDevices.size(); i < e; ++i) {
+ for (qsizetype i = 0, e = discoveredDevices.size(); i < e; ++i) {
if (isLE) {
if (discoveredDevices[i].deviceUuid() == newDeviceInfo.deviceUuid()) {
QBluetoothDeviceInfo::Fields updatedFields = QBluetoothDeviceInfo::Field::None;
@@ -499,12 +490,20 @@ void QBluetoothDeviceDiscoveryAgentPrivate::deviceFound(const QBluetoothDeviceIn
if (discoveredDevices[i].manufacturerData() != newDeviceInfo.manufacturerData()) {
qCDebug(QT_BT_DARWIN) << "Updating manufacturer data for" << newDeviceInfo.address();
- const QVector<quint16> keys = newDeviceInfo.manufacturerIds();
+ const QList<quint16> keys = newDeviceInfo.manufacturerIds();
for (auto key: keys)
discoveredDevices[i].setManufacturerData(key, newDeviceInfo.manufacturerData(key));
updatedFields.setFlag(QBluetoothDeviceInfo::Field::ManufacturerData);
}
+ if (discoveredDevices[i].serviceData() != newDeviceInfo.serviceData()) {
+ qCDebug(QT_BT_DARWIN) << "Updating service data for" << newDeviceInfo.address();
+ const QList<QBluetoothUuid> keys = newDeviceInfo.serviceIds();
+ for (auto key : keys)
+ discoveredDevices[i].setServiceData(key, newDeviceInfo.serviceData(key));
+ updatedFields.setFlag(QBluetoothDeviceInfo::Field::ServiceData);
+ }
+
if (lowEnergySearchTimeout > 0) {
if (discoveredDevices[i] != newDeviceInfo) {
discoveredDevices.replace(i, newDeviceInfo);
diff --git a/src/bluetooth/qbluetoothdevicediscoveryagent_p.cpp b/src/bluetooth/qbluetoothdevicediscoveryagent_p.cpp
index e3646db9..ddb9e4c7 100644
--- a/src/bluetooth/qbluetoothdevicediscoveryagent_p.cpp
+++ b/src/bluetooth/qbluetoothdevicediscoveryagent_p.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qbluetoothdevicediscoveryagent.h"
#include "qbluetoothdevicediscoveryagent_p.h"
@@ -51,9 +15,7 @@ QT_BEGIN_NAMESPACE
QBluetoothDeviceDiscoveryAgentPrivate::QBluetoothDeviceDiscoveryAgentPrivate(
const QBluetoothAddress &deviceAdapter,
QBluetoothDeviceDiscoveryAgent *parent)
- : inquiryType(QBluetoothDeviceDiscoveryAgent::GeneralUnlimitedInquiry),
- lastError(QBluetoothDeviceDiscoveryAgent::NoError),
- lowEnergySearchTimeout(-1),
+ : lowEnergySearchTimeout(-1),
q_ptr(parent)
{
Q_UNUSED(deviceAdapter);
@@ -80,7 +42,7 @@ void QBluetoothDeviceDiscoveryAgentPrivate::start(QBluetoothDeviceDiscoveryAgent
lastError = QBluetoothDeviceDiscoveryAgent::UnsupportedPlatformError;
errorString = QBluetoothDeviceDiscoveryAgent::tr("Device discovery not supported on this platform");
- emit q->error(lastError);
+ emit q->errorOccurred(lastError);
}
void QBluetoothDeviceDiscoveryAgentPrivate::stop()
@@ -90,3 +52,5 @@ void QBluetoothDeviceDiscoveryAgentPrivate::stop()
QT_END_NAMESPACE
+
+#include "moc_qbluetoothdevicediscoveryagent_p.cpp"
diff --git a/src/bluetooth/qbluetoothdevicediscoveryagent_p.h b/src/bluetooth/qbluetoothdevicediscoveryagent_p.h
index 263ab9ca..3e5f2a0c 100644
--- a/src/bluetooth/qbluetoothdevicediscoveryagent_p.h
+++ b/src/bluetooth/qbluetoothdevicediscoveryagent_p.h
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2014 Denis Shienkov <denis.shienkov@gmail.com>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2014 Denis Shienkov <denis.shienkov@gmail.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QBLUETOOTHDEVICEDISCOVERYAGENT_P_H
#define QBLUETOOTHDEVICEDISCOVERYAGENT_P_H
@@ -54,7 +18,7 @@
#include "qbluetoothdevicediscoveryagent.h"
#ifdef QT_ANDROID_BLUETOOTH
-#include <QtAndroidExtras/QAndroidJniObject>
+#include <QtCore/QJniObject>
#include "android/devicediscoverybroadcastreceiver_p.h"
#include <QtCore/QTimer>
#endif
@@ -84,25 +48,14 @@ class QDBusVariant;
QT_END_NAMESPACE
#endif
-#ifdef QT_WIN_BLUETOOTH
-QT_BEGIN_NAMESPACE
-class QThread;
-
-class ThreadWorkerDeviceDiscovery : public QObject
-{
- Q_OBJECT
-signals:
- void discoveryCompleted(const QVariant res);
-};
-
-QT_END_NAMESPACE
-
-#elif defined(QT_WINRT_BLUETOOTH)
+#ifdef QT_WINRT_BLUETOOTH
#include <QtCore/QPointer>
#include <QtCore/QTimer>
using ManufacturerData = QHash<quint16, QByteArray>;
-Q_DECLARE_METATYPE(ManufacturerData)
+using ServiceData = QHash<QBluetoothUuid, QByteArray>;
+QT_DECL_METATYPE_EXTERN(ManufacturerData, Q_BLUETOOTH_EXPORT)
+QT_DECL_METATYPE_EXTERN(ServiceData, Q_BLUETOOTH_EXPORT)
#endif
QT_BEGIN_NAMESPACE
@@ -112,7 +65,7 @@ class QWinRTBluetoothDeviceDiscoveryWorker;
#endif
class QBluetoothDeviceDiscoveryAgentPrivate
-#if defined(QT_ANDROID_BLUETOOTH) || defined(QT_WINRT_BLUETOOTH) || defined(QT_WIN_BLUETOOTH) \
+#if defined(QT_ANDROID_BLUETOOTH) || defined(QT_WINRT_BLUETOOTH) \
|| defined(Q_OS_DARWIN)
: public QObject
#if defined(Q_OS_MACOS)
@@ -135,24 +88,22 @@ public:
bool isActive() const;
#if QT_CONFIG(bluez)
- void _q_deviceFound(const QString &address, const QVariantMap &dict);
- void _q_propertyChanged(const QString &name, const QDBusVariant &value);
void _q_InterfacesAdded(const QDBusObjectPath &object_path,
InterfaceList interfaces_and_properties);
void _q_discoveryFinished();
void _q_discoveryInterrupted(const QString &path);
void _q_PropertiesChanged(const QString &interface,
+ const QString &path,
const QVariantMap &changed_properties,
const QStringList &invalidated_properties);
- void _q_extendedDeviceDiscoveryTimeout();
#endif
private:
QList<QBluetoothDeviceInfo> discoveredDevices;
- QBluetoothDeviceDiscoveryAgent::InquiryType inquiryType;
- QBluetoothDeviceDiscoveryAgent::Error lastError;
+ QBluetoothDeviceDiscoveryAgent::Error lastError = QBluetoothDeviceDiscoveryAgent::NoError;
QString errorString;
+ QBluetoothAddress adapterAddress;
#ifdef QT_ANDROID_BLUETOOTH
private slots:
@@ -163,72 +114,43 @@ private slots:
private:
void startLowEnergyScan();
+ void classicDiscoveryStartFail();
+ bool setErrorIfPowerOff();
- DeviceDiscoveryBroadcastReceiver *receiver;
- QBluetoothAddress m_adapterAddress;
+ DeviceDiscoveryBroadcastReceiver *receiver = nullptr;
short m_active;
- QAndroidJniObject adapter;
- QAndroidJniObject leScanner;
- QTimer *leScanTimeout;
-
- bool pendingCancel, pendingStart;
+ QJniObject adapter;
+ QJniObject leScanner;
+ QTimer *leScanTimeout = nullptr;
+ QTimer *deviceDiscoveryStartTimeout = nullptr;
+ short deviceDiscoveryStartAttemptsLeft;
+
+ bool pendingCancel = false;
+ bool pendingStart = false;
#elif QT_CONFIG(bluez)
- QBluetoothAddress m_adapterAddress;
- bool pendingCancel;
- bool pendingStart;
- OrgBluezManagerInterface *manager = nullptr;
- OrgBluezAdapterInterface *adapter = nullptr;
- OrgFreedesktopDBusObjectManagerInterface *managerBluez5 = nullptr;
- OrgBluezAdapter1Interface *adapterBluez5 = nullptr;
+ bool pendingCancel = false;
+ bool pendingStart = false;
+ OrgFreedesktopDBusObjectManagerInterface *manager = nullptr;
+ OrgBluezAdapter1Interface *adapter = nullptr;
QTimer *discoveryTimer = nullptr;
QList<OrgFreedesktopDBusPropertiesInterface *> propertyMonitors;
- void deviceFoundBluez5(const QString &devicePath, const QVariantMap &properties);
- void startBluez5(QBluetoothDeviceDiscoveryAgent::DiscoveryMethods methods);
+ void deviceFound(const QString &devicePath, const QVariantMap &properties);
- bool useExtendedDiscovery;
- QTimer extendedDiscoveryTimer;
QMap<QString, QVariantMap> devicesProperties;
#endif
-#ifdef QT_WIN_BLUETOOTH
-public:
- static QString discoveredLeDeviceSystemPath(const QBluetoothAddress &deviceAddress);
-
-private:
- void cancelDiscovery();
- void restartDiscovery();
- void finishDiscovery(QBluetoothDeviceDiscoveryAgent::Error errorCode, const QString &errorText);
-
- void startLeDevicesDiscovery();
- void completeLeDevicesDiscovery(const QVariant &res);
- void startClassicDevicesDiscovery(Qt::HANDLE hSearch = nullptr);
- void completeClassicDevicesDiscovery(const QVariant &res);
-
- void processDiscoveredDevice(const QBluetoothDeviceInfo &foundDevice);
-
- QBluetoothAddress adapterAddress;
- bool pendingCancel;
- bool pendingStart;
- bool active;
-
- QThread *threadLE = nullptr;
- QThread *threadClassic = nullptr;
- ThreadWorkerDeviceDiscovery *threadWorkerLE = nullptr;
- ThreadWorkerDeviceDiscovery *threadWorkerClassic = nullptr;
-#endif
-
#ifdef QT_WINRT_BLUETOOTH
private slots:
void registerDevice(const QBluetoothDeviceInfo &info);
void updateDeviceData(const QBluetoothAddress &address, QBluetoothDeviceInfo::Fields fields,
- qint16 rssi, ManufacturerData manufacturerData);
+ qint16 rssi, ManufacturerData manufacturerData, ServiceData serviceData);
+ void onErrorOccured(QBluetoothDeviceDiscoveryAgent::Error e);
void onScanFinished();
private:
void disconnectAndClearWorker();
- QPointer<QWinRTBluetoothDeviceDiscoveryWorker> worker;
- QTimer *leScanTimer;
+ std::shared_ptr<QWinRTBluetoothDeviceDiscoveryWorker> worker = nullptr;
#endif
#ifdef Q_OS_DARWIN
@@ -266,10 +188,8 @@ private:
LEScan
} agentState;
- QBluetoothAddress adapterAddress;
-
- bool startPending;
- bool stopPending;
+ bool startPending = false;
+ bool stopPending = false;
#ifdef Q_OS_MACOS
@@ -282,7 +202,7 @@ private:
#endif // Q_OS_DARWIN
- int lowEnergySearchTimeout;
+ int lowEnergySearchTimeout = 40000;
QBluetoothDeviceDiscoveryAgent::DiscoveryMethods requestedMethods;
QBluetoothDeviceDiscoveryAgent *q_ptr;
};
diff --git a/src/bluetooth/qbluetoothdevicediscoveryagent_win.cpp b/src/bluetooth/qbluetoothdevicediscoveryagent_win.cpp
deleted file mode 100644
index a2bfdeb6..00000000
--- a/src/bluetooth/qbluetoothdevicediscoveryagent_win.cpp
+++ /dev/null
@@ -1,557 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Copyright (C) 2014 Denis Shienkov <denis.shienkov@gmail.com>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qbluetoothdevicediscoveryagent.h"
-#include "qbluetoothuuid.h"
-#include "qbluetoothdevicediscoveryagent_p.h"
-#include "qbluetoothlocaldevice_p.h"
-
-#include <QtCore/qmutex.h>
-#include <QtCore/QThread>
-#include <QtCore/QLoggingCategory>
-
-#include <qt_windows.h>
-#include <setupapi.h>
-#include <bluetoothapis.h>
-
-QT_BEGIN_NAMESPACE
-
-Q_DECLARE_LOGGING_CATEGORY(QT_BT_WINDOWS)
-
-struct LeDeviceEntry {
- QString devicePath;
- QBluetoothAddress deviceAddress;
-};
-
-Q_GLOBAL_STATIC(QVector<LeDeviceEntry>, cachedLeDeviceEntries)
-Q_GLOBAL_STATIC(QMutex, cachedLeDeviceEntriesGuard)
-
-static QString devicePropertyString(
- HDEVINFO hDeviceInfo,
- const PSP_DEVINFO_DATA deviceInfoData,
- DWORD registryProperty)
-{
- DWORD propertyRegDataType = 0;
- DWORD propertyBufferSize = 0;
- QByteArray propertyBuffer;
-
- while (!::SetupDiGetDeviceRegistryProperty(
- hDeviceInfo,
- deviceInfoData,
- registryProperty,
- &propertyRegDataType,
- propertyBuffer.isEmpty() ? nullptr : reinterpret_cast<PBYTE>(propertyBuffer.data()),
- propertyBuffer.size(),
- &propertyBufferSize)) {
-
- const DWORD error = ::GetLastError();
- if (error != ERROR_INSUFFICIENT_BUFFER
- || (propertyRegDataType != REG_SZ
- && propertyRegDataType != REG_EXPAND_SZ)) {
- return QString();
- }
-
- // add +2 byte to allow to successfully convert to qstring
- propertyBuffer.fill(0, propertyBufferSize + sizeof(wchar_t));
- }
-
- return QString::fromWCharArray(reinterpret_cast<const wchar_t *>(
- propertyBuffer.constData()));
-}
-
-static QString deviceName(HDEVINFO hDeviceInfo, PSP_DEVINFO_DATA deviceInfoData)
-{
- return devicePropertyString(hDeviceInfo, deviceInfoData, SPDRP_FRIENDLYNAME);
-}
-
-static QString deviceSystemPath(const PSP_INTERFACE_DEVICE_DETAIL_DATA detailData)
-{
- return QString::fromWCharArray(detailData->DevicePath);
-}
-
-static QBluetoothAddress deviceAddress(const QString &devicePath)
-{
- const int firstbound = devicePath.indexOf(QStringLiteral("dev_"));
- const int lastbound = devicePath.indexOf(QLatin1Char('#'), firstbound);
- const QString hex = devicePath.mid(firstbound + 4, lastbound - firstbound - 4);
- bool ok = false;
- return QBluetoothAddress(hex.toULongLong(&ok, 16));
-}
-
-static QBluetoothDeviceInfo createClassicDeviceInfo(const BLUETOOTH_DEVICE_INFO &foundDevice)
-{
- QBluetoothDeviceInfo deviceInfo(
- QBluetoothAddress(foundDevice.Address.ullLong),
- QString::fromWCharArray(foundDevice.szName),
- foundDevice.ulClassofDevice);
-
- deviceInfo.setCoreConfigurations(QBluetoothDeviceInfo::BaseRateCoreConfiguration);
-
- if (foundDevice.fRemembered)
- deviceInfo.setCached(true);
- return deviceInfo;
-}
-
-static QBluetoothDeviceInfo findFirstClassicDevice(
- DWORD *systemErrorCode, HBLUETOOTH_DEVICE_FIND *hSearch)
-{
- BLUETOOTH_DEVICE_SEARCH_PARAMS searchParams = {};
- searchParams.dwSize = sizeof(searchParams);
- searchParams.cTimeoutMultiplier = 10; // 12.8 sec
- searchParams.fIssueInquiry = TRUE;
- searchParams.fReturnAuthenticated = TRUE;
- searchParams.fReturnConnected = TRUE;
- searchParams.fReturnRemembered = TRUE;
- searchParams.fReturnUnknown = TRUE;
- searchParams.hRadio = nullptr;
-
- BLUETOOTH_DEVICE_INFO deviceInfo = {};
- deviceInfo.dwSize = sizeof(deviceInfo);
-
- const HBLUETOOTH_DEVICE_FIND hFind = ::BluetoothFindFirstDevice(
- &searchParams, &deviceInfo);
-
- QBluetoothDeviceInfo foundDevice;
- if (hFind) {
- *hSearch = hFind;
- *systemErrorCode = NO_ERROR;
- foundDevice = createClassicDeviceInfo(deviceInfo);
- } else {
- *systemErrorCode = int(::GetLastError());
- }
-
- return foundDevice;
-}
-
-static QBluetoothDeviceInfo findNextClassicDevice(
- DWORD *systemErrorCode, HBLUETOOTH_DEVICE_FIND hSearch)
-{
- BLUETOOTH_DEVICE_INFO deviceInfo = {};
- deviceInfo.dwSize = sizeof(deviceInfo);
-
- QBluetoothDeviceInfo foundDevice;
- if (!::BluetoothFindNextDevice(hSearch, &deviceInfo)) {
- *systemErrorCode = int(::GetLastError());
- } else {
- *systemErrorCode = NO_ERROR;
- foundDevice = createClassicDeviceInfo(deviceInfo);
- }
-
- return foundDevice;
-}
-
-static void closeClassicSearch(HBLUETOOTH_DEVICE_FIND hSearch)
-{
- if (hSearch)
- ::BluetoothFindDeviceClose(hSearch);
-}
-
-static QVector<QBluetoothDeviceInfo> enumerateLeDevices(
- DWORD *systemErrorCode)
-{
- // GUID_BLUETOOTHLE_DEVICE_INTERFACE
- const QUuid deviceInterfaceGuid("781aee18-7733-4ce4-add0-91f41c67b592");
- const HDEVINFO hDeviceInfo = ::SetupDiGetClassDevs(
- reinterpret_cast<const GUID *>(&deviceInterfaceGuid),
- nullptr,
- nullptr,
- DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
-
- if (hDeviceInfo == INVALID_HANDLE_VALUE) {
- *systemErrorCode = int(::GetLastError());
- return QVector<QBluetoothDeviceInfo>();
- }
-
- QVector<QBluetoothDeviceInfo> foundDevices;
- DWORD index = 0;
-
- QVector<LeDeviceEntry> cachedEntries;
-
- for (;;) {
- SP_DEVICE_INTERFACE_DATA deviceInterfaceData = {};
- deviceInterfaceData.cbSize = sizeof(deviceInterfaceData);
-
- if (!::SetupDiEnumDeviceInterfaces(
- hDeviceInfo,
- nullptr,
- reinterpret_cast<const GUID *>(&deviceInterfaceGuid),
- index++,
- &deviceInterfaceData)) {
- *systemErrorCode = int(::GetLastError());
- break;
- }
-
- DWORD deviceInterfaceDetailDataSize = 0;
- if (!::SetupDiGetDeviceInterfaceDetail(
- hDeviceInfo,
- &deviceInterfaceData,
- nullptr,
- deviceInterfaceDetailDataSize,
- &deviceInterfaceDetailDataSize,
- nullptr)) {
- if (::GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
- *systemErrorCode = int(::GetLastError());
- break;
- }
- }
-
- SP_DEVINFO_DATA deviceInfoData = {};
- deviceInfoData.cbSize = sizeof(deviceInfoData);
-
- QByteArray deviceInterfaceDetailDataBuffer(
- deviceInterfaceDetailDataSize, 0);
-
- PSP_INTERFACE_DEVICE_DETAIL_DATA deviceInterfaceDetailData =
- reinterpret_cast<PSP_INTERFACE_DEVICE_DETAIL_DATA>
- (deviceInterfaceDetailDataBuffer.data());
-
- deviceInterfaceDetailData->cbSize =
- sizeof(SP_INTERFACE_DEVICE_DETAIL_DATA);
-
- if (!::SetupDiGetDeviceInterfaceDetail(
- hDeviceInfo,
- &deviceInterfaceData,
- deviceInterfaceDetailData,
- deviceInterfaceDetailDataBuffer.size(),
- &deviceInterfaceDetailDataSize,
- &deviceInfoData)) {
- *systemErrorCode = int(::GetLastError());
- break;
- }
-
- const QString systemPath = deviceSystemPath(deviceInterfaceDetailData);
- const QBluetoothAddress address = deviceAddress(systemPath);
- if (address.isNull())
- continue;
- const QString name = deviceName(hDeviceInfo, &deviceInfoData);
-
- QBluetoothDeviceInfo deviceInfo(address, name, QBluetoothDeviceInfo::MiscellaneousDevice);
- deviceInfo.setCoreConfigurations(QBluetoothDeviceInfo::LowEnergyCoreConfiguration);
- deviceInfo.setCached(true);
-
- foundDevices << deviceInfo;
- cachedEntries << LeDeviceEntry{systemPath, address};
- }
-
- QMutexLocker locker(cachedLeDeviceEntriesGuard());
- cachedLeDeviceEntries()->swap(cachedEntries);
-
- ::SetupDiDestroyDeviceInfoList(hDeviceInfo);
- return foundDevices;
-}
-
-struct DiscoveryResult {
- QVector<QBluetoothDeviceInfo> devices;
- DWORD systemErrorCode;
- HBLUETOOTH_DEVICE_FIND hSearch; // Used only for classic devices
-};
-
-QString QBluetoothDeviceDiscoveryAgentPrivate::discoveredLeDeviceSystemPath(
- const QBluetoothAddress &deviceAddress)
-{
- // update LE devices cache
- DWORD dummyErrorCode;
- enumerateLeDevices(&dummyErrorCode);
-
- QMutexLocker locker(cachedLeDeviceEntriesGuard());
- for (const LeDeviceEntry &e: *cachedLeDeviceEntries) {
- if (e.deviceAddress == deviceAddress)
- return e.devicePath;
- }
- return QString();
-}
-
-QBluetoothDeviceDiscoveryAgentPrivate::QBluetoothDeviceDiscoveryAgentPrivate(
- const QBluetoothAddress &deviceAdapter,
- QBluetoothDeviceDiscoveryAgent *parent)
- : inquiryType(QBluetoothDeviceDiscoveryAgent::GeneralUnlimitedInquiry)
- , lastError(QBluetoothDeviceDiscoveryAgent::NoError)
- , adapterAddress(deviceAdapter)
- , pendingCancel(false)
- , pendingStart(false)
- , active(false)
- , lowEnergySearchTimeout(-1) // remains -1 -> timeout not supported
- , q_ptr(parent)
-{
- threadLE = new QThread;
- threadWorkerLE = new ThreadWorkerDeviceDiscovery;
- threadWorkerLE->moveToThread(threadLE);
- connect(threadWorkerLE, &ThreadWorkerDeviceDiscovery::discoveryCompleted, this, &QBluetoothDeviceDiscoveryAgentPrivate::completeLeDevicesDiscovery);
- connect(threadLE, &QThread::finished, threadWorkerLE, &ThreadWorkerDeviceDiscovery::deleteLater);
- connect(threadLE, &QThread::finished, threadLE, &QThread::deleteLater);
- threadLE->start();
-
- threadClassic = new QThread;
- threadWorkerClassic = new ThreadWorkerDeviceDiscovery;
- threadWorkerClassic->moveToThread(threadClassic);
- connect(threadWorkerClassic, &ThreadWorkerDeviceDiscovery::discoveryCompleted, this, &QBluetoothDeviceDiscoveryAgentPrivate::completeClassicDevicesDiscovery);
- connect(threadClassic, &QThread::finished, threadWorkerClassic, &ThreadWorkerDeviceDiscovery::deleteLater);
- connect(threadClassic, &QThread::finished, threadClassic, &QThread::deleteLater);
- threadClassic->start();
-}
-
-QBluetoothDeviceDiscoveryAgentPrivate::~QBluetoothDeviceDiscoveryAgentPrivate()
-{
- if (active)
- stop();
- if (threadLE)
- threadLE->quit();
- if (threadClassic)
- threadClassic->quit();
-}
-
-bool QBluetoothDeviceDiscoveryAgentPrivate::isActive() const
-{
- if (pendingStart)
- return true;
- if (pendingCancel)
- return false;
- return active;
-}
-
-QBluetoothDeviceDiscoveryAgent::DiscoveryMethods QBluetoothDeviceDiscoveryAgent::supportedDiscoveryMethods()
-{
- return (LowEnergyMethod | ClassicMethod);
-}
-
-void QBluetoothDeviceDiscoveryAgentPrivate::start(QBluetoothDeviceDiscoveryAgent::DiscoveryMethods methods)
-{
- requestedMethods = methods;
-
- if (pendingCancel == true) {
- pendingStart = true;
- return;
- }
-
- const QList<QBluetoothHostInfo> foundLocalAdapters =
- QBluetoothLocalDevicePrivate::localAdapters();
-
- Q_Q(QBluetoothDeviceDiscoveryAgent);
-
- if (foundLocalAdapters.isEmpty()) {
- qCWarning(QT_BT_WINDOWS) << "Device does not support Bluetooth";
- lastError = QBluetoothDeviceDiscoveryAgent::InputOutputError;
- errorString = QBluetoothDeviceDiscoveryAgent::tr("Device does not support Bluetooth");
- emit q->error(lastError);
- return;
- }
-
- // Check for the local adapter address.
- auto equals = [this](const QBluetoothHostInfo &adapterInfo) {
- return adapterAddress == QBluetoothAddress()
- || adapterAddress == adapterInfo.address();
- };
- const auto end = foundLocalAdapters.cend();
- const auto it = std::find_if(foundLocalAdapters.cbegin(), end, equals);
- if (it == end) {
- qCWarning(QT_BT_WINDOWS) << "Incorrect local adapter passed.";
- lastError = QBluetoothDeviceDiscoveryAgent::InvalidBluetoothAdapterError;
- errorString = QBluetoothDeviceDiscoveryAgent::tr("Passed address is not a local device.");
- emit q->error(lastError);
- return;
- }
-
- discoveredDevices.clear();
- active = true;
-
- // We run LE search first, as it is fast on windows.
- if (requestedMethods & QBluetoothDeviceDiscoveryAgent::LowEnergyMethod)
- startLeDevicesDiscovery();
- else if (requestedMethods & QBluetoothDeviceDiscoveryAgent::ClassicMethod)
- startClassicDevicesDiscovery();
-}
-
-void QBluetoothDeviceDiscoveryAgentPrivate::stop()
-{
- if (!active)
- return;
-
- pendingCancel = true;
- pendingStart = false;
-}
-
-void QBluetoothDeviceDiscoveryAgentPrivate::cancelDiscovery()
-{
- Q_Q(QBluetoothDeviceDiscoveryAgent);
- active = false;
- pendingCancel = false;
- emit q->canceled();
-}
-
-void QBluetoothDeviceDiscoveryAgentPrivate::restartDiscovery()
-{
- pendingStart = false;
- pendingCancel = false;
- start(requestedMethods);
-}
-
-void QBluetoothDeviceDiscoveryAgentPrivate::finishDiscovery(QBluetoothDeviceDiscoveryAgent::Error errorCode, const QString &errorText)
-{
- active = false;
- pendingStart = false;
- pendingCancel = false;
- lastError = errorCode;
- errorString = errorText;
-
- Q_Q(QBluetoothDeviceDiscoveryAgent);
- if (errorCode == QBluetoothDeviceDiscoveryAgent::NoError)
- emit q->finished();
- else
- emit q->error(lastError);
-}
-
-void QBluetoothDeviceDiscoveryAgentPrivate::startLeDevicesDiscovery()
-{
- const auto threadWorker = threadWorkerLE;
- QMetaObject::invokeMethod(threadWorkerLE, [threadWorker]()
- {
- DiscoveryResult result; // Do not use hSearch here!
- result.systemErrorCode = NO_ERROR;
- result.devices = enumerateLeDevices(&result.systemErrorCode);
- emit threadWorker->discoveryCompleted(QVariant::fromValue(result));
- }, Qt::QueuedConnection);
-}
-
-void QBluetoothDeviceDiscoveryAgentPrivate::completeLeDevicesDiscovery(const QVariant &res)
-{
- if (pendingCancel && !pendingStart) {
- cancelDiscovery();
- } else if (pendingStart) {
- restartDiscovery();
- } else {
- const DiscoveryResult result = res.value<DiscoveryResult>();
- if (result.systemErrorCode == NO_ERROR || result.systemErrorCode == ERROR_NO_MORE_ITEMS) {
- for (const QBluetoothDeviceInfo &device : result.devices)
- processDiscoveredDevice(device);
-
- // We run classic search at second, as it is slow on windows.
- if (requestedMethods & QBluetoothDeviceDiscoveryAgent::ClassicMethod)
- startClassicDevicesDiscovery();
- else
- finishDiscovery(QBluetoothDeviceDiscoveryAgent::NoError, qt_error_string(NO_ERROR));
- } else {
- const QBluetoothDeviceDiscoveryAgent::Error error = (result.systemErrorCode == ERROR_INVALID_HANDLE)
- ? QBluetoothDeviceDiscoveryAgent::InvalidBluetoothAdapterError
- : QBluetoothDeviceDiscoveryAgent::InputOutputError;
- finishDiscovery(error, qt_error_string(result.systemErrorCode));
- }
- }
-}
-
-void QBluetoothDeviceDiscoveryAgentPrivate::startClassicDevicesDiscovery(Qt::HANDLE hSearch)
-{
- const auto threadWorker = threadWorkerClassic;
- QMetaObject::invokeMethod(threadWorker, [threadWorker, hSearch]()
- {
- DiscoveryResult result;
- result.hSearch = hSearch;
- result.systemErrorCode = NO_ERROR;
-
- const QBluetoothDeviceInfo device = hSearch
- ? findNextClassicDevice(&result.systemErrorCode, result.hSearch)
- : findFirstClassicDevice(&result.systemErrorCode, &result.hSearch);
-
- result.devices.append(device);
- emit threadWorker->discoveryCompleted(QVariant::fromValue(result));
- }, Qt::QueuedConnection);
-}
-
-void QBluetoothDeviceDiscoveryAgentPrivate::completeClassicDevicesDiscovery(const QVariant &res)
-{
- const DiscoveryResult result = res.value<DiscoveryResult>();
- if (pendingCancel && !pendingStart) {
- closeClassicSearch(result.hSearch);
- cancelDiscovery();
- } else if (pendingStart) {
- closeClassicSearch(result.hSearch);
- restartDiscovery();
- } else {
- if (result.systemErrorCode == ERROR_NO_MORE_ITEMS) {
- closeClassicSearch(result.hSearch);
- finishDiscovery(QBluetoothDeviceDiscoveryAgent::NoError, QString());
- } else if (result.systemErrorCode == NO_ERROR) {
- if (result.hSearch) {
- for (const QBluetoothDeviceInfo &device : result.devices)
- processDiscoveredDevice(device);
-
- startClassicDevicesDiscovery(result.hSearch);
- } else {
- finishDiscovery(QBluetoothDeviceDiscoveryAgent::NoError, QString());
- }
- } else {
- closeClassicSearch(result.hSearch);
- const QBluetoothDeviceDiscoveryAgent::Error error = (result.systemErrorCode == ERROR_INVALID_HANDLE)
- ? QBluetoothDeviceDiscoveryAgent::InvalidBluetoothAdapterError
- : QBluetoothDeviceDiscoveryAgent::InputOutputError;
- finishDiscovery(error, qt_error_string(result.systemErrorCode));
- }
- }
-}
-
-void QBluetoothDeviceDiscoveryAgentPrivate::processDiscoveredDevice(
- const QBluetoothDeviceInfo &foundDevice)
-{
- Q_Q(QBluetoothDeviceDiscoveryAgent);
-
- auto equalAddress = [foundDevice](const QBluetoothDeviceInfo &targetDevice) {
- return foundDevice.address() == targetDevice.address(); };
- auto end = discoveredDevices.end();
- auto deviceIt = std::find_if(discoveredDevices.begin(), end, equalAddress);
- if (deviceIt == end) {
- qCDebug(QT_BT_WINDOWS) << "Found device: " << foundDevice.name() << foundDevice.address();
- discoveredDevices.append(foundDevice);
- emit q->deviceDiscovered(foundDevice);
- } else {
- qCDebug(QT_BT_WINDOWS) << "Updating device:" << deviceIt->name() << deviceIt->address();
- // merge service uuids
- QVector<QBluetoothUuid> uuids = deviceIt->serviceUuids();
- uuids.append(foundDevice.serviceUuids());
- const QSet<QBluetoothUuid> uuidSet(uuids.begin(), uuids.end());
- if (deviceIt->serviceUuids().count() != uuidSet.count())
- deviceIt->setServiceUuids(uuidSet.values().toVector());
- if (deviceIt->coreConfigurations() != foundDevice.coreConfigurations())
- deviceIt->setCoreConfigurations(
- QBluetoothDeviceInfo::BaseRateAndLowEnergyCoreConfiguration);
- }
-}
-
-QT_END_NAMESPACE
-
-Q_DECLARE_METATYPE(DiscoveryResult)
diff --git a/src/bluetooth/qbluetoothdevicediscoveryagent_winrt.cpp b/src/bluetooth/qbluetoothdevicediscoveryagent_winrt.cpp
index 01b67921..298f720c 100644
--- a/src/bluetooth/qbluetoothdevicediscoveryagent_winrt.cpp
+++ b/src/bluetooth/qbluetoothdevicediscoveryagent_winrt.cpp
@@ -1,836 +1,736 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qbluetoothdevicediscoveryagent.h"
#include "qbluetoothdevicediscoveryagent_p.h"
#include "qbluetoothaddress.h"
#include "qbluetoothuuid.h"
-#ifdef CLASSIC_APP_BUILD
-#define Q_OS_WINRT
-#endif
-#include "qfunctions_winrt.h"
-
-#include <QtBluetooth/private/qtbluetoothglobal_p.h>
+#include <QtBluetooth/private/qbluetoothdevicewatcher_winrt_p.h>
#include <QtBluetooth/private/qbluetoothutils_winrt_p.h>
+#include <QtBluetooth/private/qtbluetoothglobal_p.h>
+
#include <QtCore/QLoggingCategory>
-#include <QtCore/qmutex.h>
-#include <QtCore/private/qeventdispatcher_winrt_p.h>
-#include <QtCore/qmutex.h>
-
-#include <robuffer.h>
-#include <wrl.h>
-#include <windows.devices.enumeration.h>
-#include <windows.devices.bluetooth.h>
-#include <windows.foundation.collections.h>
-#include <windows.storage.streams.h>
-
-#include <windows.devices.bluetooth.advertisement.h>
-
-using namespace Microsoft::WRL;
-using namespace Microsoft::WRL::Wrappers;
-using namespace ABI::Windows::Foundation;
-using namespace ABI::Windows::Foundation::Collections;
-using namespace ABI::Windows::Devices;
-using namespace ABI::Windows::Devices::Bluetooth;
-using namespace ABI::Windows::Devices::Bluetooth::Advertisement;
-using namespace ABI::Windows::Devices::Enumeration;
-using namespace ABI::Windows::Storage::Streams;
+#include <QtCore/QMutex>
+#include <QtCore/qendian.h>
+
+#include <winrt/Windows.Devices.Bluetooth.h>
+#include <winrt/Windows.Devices.Bluetooth.Advertisement.h>
+#include <winrt/Windows.Devices.Bluetooth.Rfcomm.h>
+#include <winrt/Windows.Devices.Bluetooth.GenericAttributeProfile.h>
+#include <winrt/Windows.Devices.Enumeration.h>
+#include <winrt/Windows.Foundation.h>
+#include <winrt/Windows.Foundation.Collections.h>
+#include <winrt/Windows.Storage.Streams.h>
+
+using namespace winrt::Windows::Devices::Bluetooth;
+using namespace winrt::Windows::Devices::Bluetooth::Advertisement;
+using namespace winrt::Windows::Devices::Bluetooth::GenericAttributeProfile;
+using namespace winrt::Windows::Devices::Bluetooth::Rfcomm;
+using namespace winrt::Windows::Devices::Enumeration;
+using namespace winrt::Windows::Foundation;
+using namespace winrt::Windows::Storage::Streams;
QT_BEGIN_NAMESPACE
-Q_DECLARE_LOGGING_CATEGORY(QT_BT_WINRT)
+QT_IMPL_METATYPE_EXTERN(ManufacturerData)
+QT_IMPL_METATYPE_EXTERN(ServiceData)
-#define WARN_AND_RETURN_IF_FAILED(msg, ret) \
- if (FAILED(hr)) { \
- qCWarning(QT_BT_WINRT) << msg; \
- ret; \
- }
+Q_DECLARE_LOGGING_CATEGORY(QT_BT_WINDOWS)
-#define WARN_AND_CONTINUE_IF_FAILED(msg) \
- if (FAILED(hr)) { \
- qCWarning(QT_BT_WINRT) << msg; \
- continue; \
- }
+static QByteArray byteArrayFromBuffer(const IBuffer &buffer)
+{
+ const uint8_t *data = buffer.data();
+ return QByteArray(reinterpret_cast<const char *>(data),
+ static_cast<qsizetype>(buffer.Length()));
+}
-static ManufacturerData extractManufacturerData(ComPtr<IBluetoothLEAdvertisement> ad)
+static ManufacturerData extractManufacturerData(const BluetoothLEAdvertisement &ad)
{
ManufacturerData ret;
- ComPtr<IVector<BluetoothLEManufacturerData*>> data;
- HRESULT hr = ad->get_ManufacturerData(&data);
- WARN_AND_RETURN_IF_FAILED("Could not obtain list of manufacturer data.", return ret);
- quint32 size;
- hr = data->get_Size(&size);
- WARN_AND_RETURN_IF_FAILED("Could not obtain manufacturer data's list size.", return ret);
- for (quint32 i = 0; i < size; ++i) {
- ComPtr<IBluetoothLEManufacturerData> d;
- hr = data->GetAt(i, &d);
- WARN_AND_CONTINUE_IF_FAILED("Could not obtain manufacturer data.");
- quint16 id;
- hr = d->get_CompanyId(&id);
- WARN_AND_CONTINUE_IF_FAILED("Could not obtain manufacturer data company id.");
- ComPtr<IBuffer> buffer;
- hr = d->get_Data(&buffer);
- WARN_AND_CONTINUE_IF_FAILED("Could not obtain manufacturer data set.");
- const QByteArray bufferData = byteArrayFromBuffer(buffer);
+ const auto data = ad.ManufacturerData();
+ for (const auto &item : data) {
+ const uint16_t id = item.CompanyId();
+ const QByteArray bufferData = byteArrayFromBuffer(item.Data());
if (ret.contains(id))
- qCWarning(QT_BT_WINRT) << "Company ID already present in manufacturer data.";
+ qCWarning(QT_BT_WINDOWS) << "Company ID already present in manufacturer data.";
ret.insert(id, bufferData);
}
return ret;
}
-class QWinRTBluetoothDeviceDiscoveryWorker : public QObject
+static ServiceData extractServiceData(const BluetoothLEAdvertisement &ad)
+{
+ static constexpr int serviceDataTypes[3] = { 0x16, 0x20, 0x21 };
+
+ ServiceData ret;
+
+ for (const auto &serviceDataType : serviceDataTypes) {
+ const auto dataSections = ad.GetSectionsByType(serviceDataType);
+ for (const auto &section : dataSections) {
+ const unsigned char dataType = section.DataType();
+ const QByteArray bufferData = byteArrayFromBuffer(section.Data());
+ if (dataType == 0x16) {
+ Q_ASSERT(bufferData.size() >= 2);
+ ret.insert(QBluetoothUuid(qFromLittleEndian<quint16>(bufferData.constData())),
+ bufferData + 2);
+ } else if (dataType == 0x20) {
+ Q_ASSERT(bufferData.size() >= 4);
+ ret.insert(QBluetoothUuid(qFromLittleEndian<quint32>(bufferData.constData())),
+ bufferData + 4);
+ } else if (dataType == 0x21) {
+ Q_ASSERT(bufferData.size() >= 16);
+ ret.insert(QBluetoothUuid(qToBigEndian<QUuid::Id128Bytes>(
+ qFromLittleEndian<QUuid::Id128Bytes>(bufferData.constData()))),
+ bufferData + 16);
+ }
+ }
+ }
+
+ return ret;
+}
+
+// Needed because there is no explicit conversion
+static GUID fromWinRtGuid(const winrt::guid &guid)
+{
+ const GUID uuid {
+ guid.Data1,
+ guid.Data2,
+ guid.Data3,
+ { guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3],
+ guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7] }
+ };
+ return uuid;
+}
+
+class AdvertisementWatcherWrapper : public QObject,
+ public std::enable_shared_from_this<AdvertisementWatcherWrapper>
+{
+ Q_OBJECT
+public:
+ AdvertisementWatcherWrapper() {}
+ ~AdvertisementWatcherWrapper()
+ {
+ stop();
+ }
+ void init()
+ {
+ m_watcher.ScanningMode(BluetoothLEScanningMode::Active);
+ }
+ void start() {
+ subscribeToEvents();
+ m_watcher.Start();
+ }
+ void stop()
+ {
+ if (canStop()) {
+ unsubscribeFromEvents();
+ m_watcher.Stop();
+ }
+ }
+
+signals:
+ // The signal will be emitted from a separate thread,
+ // so we need to use Qt::QueuedConnection
+ void advertisementDataReceived(quint64 address, qint16 rssi,
+ const ManufacturerData &manufacturerData,
+ const ServiceData &serviceData,
+ const QList<QBluetoothUuid> &uuids);
+private:
+ void subscribeToEvents()
+ {
+ // The callbacks are triggered from separate threads. So we capture
+ // thisPtr to make sure that the object is valid.
+ auto thisPtr = shared_from_this();
+ m_receivedToken = m_watcher.Received(
+ [thisPtr](BluetoothLEAdvertisementWatcher,
+ BluetoothLEAdvertisementReceivedEventArgs args) {
+ const uint64_t address = args.BluetoothAddress();
+ const short rssi = args.RawSignalStrengthInDBm();
+ const BluetoothLEAdvertisement ad = args.Advertisement();
+
+ const ManufacturerData manufacturerData = extractManufacturerData(ad);
+ const ServiceData serviceData = extractServiceData(ad);
+
+ QList<QBluetoothUuid> serviceUuids;
+ const auto guids = ad.ServiceUuids();
+ for (const auto &guid : guids) {
+ const GUID uuid = fromWinRtGuid(guid);
+ serviceUuids.append(QBluetoothUuid(uuid));
+ }
+
+ emit thisPtr->advertisementDataReceived(address, rssi, manufacturerData,
+ serviceData, serviceUuids);
+ });
+ }
+ void unsubscribeFromEvents()
+ {
+ m_watcher.Received(m_receivedToken);
+ }
+ bool canStop() const
+ {
+ const auto status = m_watcher.Status();
+ return status == BluetoothLEAdvertisementWatcherStatus::Started
+ || status == BluetoothLEAdvertisementWatcherStatus::Aborted;
+ }
+
+ BluetoothLEAdvertisementWatcher m_watcher;
+ winrt::event_token m_receivedToken;
+};
+
+// Both constants are taken from Microsoft's docs:
+// https://docs.microsoft.com/en-us/windows/uwp/devices-sensors/aep-service-class-ids
+// Alternatively we could create separate watchers for paired and unpaired devices.
+static const winrt::hstring ClassicDeviceSelector =
+ L"System.Devices.Aep.ProtocolId:=\"{e0cbf06c-cd8b-4647-bb8a-263b43f0f974}\"";
+// Do not use it for now, so comment out. Do not delete in case we want to reuse it.
+//static const winrt::hstring LowEnergyDeviceSelector =
+// L"System.Devices.Aep.ProtocolId:=\"{bb7bb05e-5972-42b5-94fc-76eaa7084d49}\"";
+
+class QWinRTBluetoothDeviceDiscoveryWorker : public QObject,
+ public std::enable_shared_from_this<QWinRTBluetoothDeviceDiscoveryWorker>
{
Q_OBJECT
public:
- explicit QWinRTBluetoothDeviceDiscoveryWorker(QBluetoothDeviceDiscoveryAgent::DiscoveryMethods methods);
+ QWinRTBluetoothDeviceDiscoveryWorker(QBluetoothDeviceDiscoveryAgent::DiscoveryMethods methods,
+ int interval);
~QWinRTBluetoothDeviceDiscoveryWorker();
void start();
- void stopLEWatcher();
+ void stop();
private:
void startDeviceDiscovery(QBluetoothDeviceDiscoveryAgent::DiscoveryMethod mode);
- void onDeviceDiscoveryFinished(IAsyncOperation<DeviceInformationCollection *> *op,
- QBluetoothDeviceDiscoveryAgent::DiscoveryMethod mode);
- void gatherDeviceInformation(IDeviceInformation *deviceInfo,
- QBluetoothDeviceDiscoveryAgent::DiscoveryMethod mode);
- void gatherMultipleDeviceInformation(quint32 deviceCount, IVectorView<DeviceInformation *> *devices,
- QBluetoothDeviceDiscoveryAgent::DiscoveryMethod mode);
- void setupLEDeviceWatcher();
- void classicBluetoothInfoFromDeviceIdAsync(HSTRING deviceId);
- void leBluetoothInfoFromDeviceIdAsync(HSTRING deviceId);
- void leBluetoothInfoFromAddressAsync(quint64 address);
- HRESULT onPairedClassicBluetoothDeviceFoundAsync(IAsyncOperation<BluetoothDevice *> *op, AsyncStatus status );
- HRESULT onPairedBluetoothLEDeviceFoundAsync(IAsyncOperation<BluetoothLEDevice *> *op, AsyncStatus status);
- HRESULT onBluetoothLEDeviceFoundAsync(IAsyncOperation<BluetoothLEDevice *> *op, AsyncStatus status);
- enum PairingCheck {
- CheckForPairing,
- OmitPairingCheck
- };
- HRESULT onBluetoothLEDeviceFound(ComPtr<IBluetoothLEDevice> device, PairingCheck pairingCheck);
-#if QT_CONFIG(winrt_btle_no_pairing)
- HRESULT onBluetoothLEDeviceFound(ComPtr<IBluetoothLEDevice> device);
-#endif
-public slots:
+ std::shared_ptr<QBluetoothDeviceWatcherWinRT> createDeviceWatcher(winrt::hstring selector,
+ int watcherId);
+ void generateError(QBluetoothDeviceDiscoveryAgent::Error error, const char *msg = nullptr);
+ void invokeDeviceFoundWithDebug(const QBluetoothDeviceInfo &info);
void finishDiscovery();
+ bool isFinished() const;
+
+ // Bluetooth Classic handlers
+ void getClassicDeviceFromId(const winrt::hstring &id);
+ void handleClassicDevice(const BluetoothDevice &device);
+ void handleRfcommServices(const RfcommDeviceServicesResult &servicesResult,
+ uint64_t address, const QString &name, uint32_t classOfDeviceInt);
+
+ // Bluetooth Low Energy handlers
+ void getLowEnergyDeviceFromId(const winrt::hstring &id);
+ void handleLowEnergyDevice(const BluetoothLEDevice &device);
+ void handleGattServices(const GattDeviceServicesResult &servicesResult,
+ QBluetoothDeviceInfo &info);
+
+ // Bluetooth Low Energy Advertising handlers
+ std::shared_ptr<AdvertisementWatcherWrapper> createAdvertisementWatcher();
+
+ // invokable methods for handling finish conditions
+ Q_INVOKABLE void decrementPendingDevicesCountAndCheckFinished(
+ std::shared_ptr<QWinRTBluetoothDeviceDiscoveryWorker> worker);
Q_SIGNALS:
void deviceFound(const QBluetoothDeviceInfo &info);
void deviceDataChanged(const QBluetoothAddress &address, QBluetoothDeviceInfo::Fields,
- qint16 rssi, ManufacturerData manufacturerData);
+ qint16 rssi, ManufacturerData manufacturerData, ServiceData serviceData);
+ void errorOccured(QBluetoothDeviceDiscoveryAgent::Error error);
void scanFinished();
-public:
- quint8 requestedModes;
+private slots:
+ void onBluetoothDeviceFound(winrt::hstring deviceId, int watcherId);
+ void onDeviceEnumerationCompleted(int watcherId);
+
+ void onAdvertisementDataReceived(quint64 address, qint16 rssi,
+ const ManufacturerData &manufacturerData,
+ const ServiceData &serviceData,
+ const QList<QBluetoothUuid> &uuids);
+
+ void stopAdvertisementWatcher();
private:
- ComPtr<IBluetoothLEAdvertisementWatcher> m_leWatcher;
- EventRegistrationToken m_leDeviceAddedToken;
-#if QT_CONFIG(winrt_btle_no_pairing)
- QMutex m_foundDevicesMutex;
struct LEAdvertisingInfo {
- QVector<QBluetoothUuid> services;
+ QList<QBluetoothUuid> services;
+ ManufacturerData manufacturerData;
+ ServiceData serviceData;
qint16 rssi = 0;
};
+ quint8 requestedModes = 0;
+ QMutex m_leDevicesMutex;
QMap<quint64, LEAdvertisingInfo> m_foundLEDevicesMap;
-#endif
- QMap<quint64, qint16> m_foundLEDevices;
- QMap<quint64, ManufacturerData> m_foundLEManufacturerData;
- int m_pendingPairedDevices;
+ int m_pendingDevices = 0;
+
+ static constexpr int ClassicWatcherId = 1;
+ static constexpr int LowEnergyWatcherId = 2;
- ComPtr<IBluetoothDeviceStatics> m_deviceStatics;
- ComPtr<IBluetoothLEDeviceStatics> m_leDeviceStatics;
+ std::shared_ptr<QBluetoothDeviceWatcherWinRT> m_classicWatcher;
+ std::shared_ptr<QBluetoothDeviceWatcherWinRT> m_lowEnergyWatcher;
+ std::shared_ptr<AdvertisementWatcherWrapper> m_advertisementWatcher;
+ bool m_classicScanStarted = false;
+ bool m_lowEnergyScanStarted = false;
+ QTimer *m_leScanTimer = nullptr;
};
-QWinRTBluetoothDeviceDiscoveryWorker::QWinRTBluetoothDeviceDiscoveryWorker(QBluetoothDeviceDiscoveryAgent::DiscoveryMethods methods)
+static void invokeDecrementPendingDevicesCountAndCheckFinished(
+ std::shared_ptr<QWinRTBluetoothDeviceDiscoveryWorker> worker)
+{
+ QMetaObject::invokeMethod(worker.get(), "decrementPendingDevicesCountAndCheckFinished",
+ Qt::QueuedConnection,
+ Q_ARG(std::shared_ptr<QWinRTBluetoothDeviceDiscoveryWorker>,
+ worker));
+}
+
+QWinRTBluetoothDeviceDiscoveryWorker::QWinRTBluetoothDeviceDiscoveryWorker(
+ QBluetoothDeviceDiscoveryAgent::DiscoveryMethods methods, int interval)
: requestedModes(methods)
- , m_pendingPairedDevices(0)
{
qRegisterMetaType<QBluetoothDeviceInfo>();
qRegisterMetaType<QBluetoothDeviceInfo::Fields>();
qRegisterMetaType<ManufacturerData>();
-
-#ifdef CLASSIC_APP_BUILD
- CoInitialize(NULL);
-#endif
- HRESULT hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Devices_Bluetooth_BluetoothDevice).Get(), &m_deviceStatics);
- Q_ASSERT_SUCCEEDED(hr);
- hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Devices_Bluetooth_BluetoothLEDevice).Get(), &m_leDeviceStatics);
- Q_ASSERT_SUCCEEDED(hr);
+ qRegisterMetaType<std::shared_ptr<QWinRTBluetoothDeviceDiscoveryWorker>>();
+
+ m_classicWatcher = createDeviceWatcher(ClassicDeviceSelector, ClassicWatcherId);
+ // For LE scan use DeviceWatcher to handle only paired devices.
+ // Non-paired devices will be found using BluetoothLEAdvertisementWatcher.
+ const auto leSelector = BluetoothLEDevice::GetDeviceSelectorFromPairingState(true);
+ m_lowEnergyWatcher = createDeviceWatcher(leSelector, LowEnergyWatcherId);
+ m_advertisementWatcher = createAdvertisementWatcher();
+
+ // Docs claim that a negative interval means that the backend handles it on its own
+ if (interval < 0)
+ interval = 40000;
+
+ if (interval != 0) {
+ m_leScanTimer = new QTimer(this);
+ m_leScanTimer->setSingleShot(true);
+ m_leScanTimer->setInterval(interval);
+ connect(m_leScanTimer, &QTimer::timeout, this,
+ &QWinRTBluetoothDeviceDiscoveryWorker::stopAdvertisementWatcher);
+ }
}
QWinRTBluetoothDeviceDiscoveryWorker::~QWinRTBluetoothDeviceDiscoveryWorker()
{
- stopLEWatcher();
-#ifdef CLASSIC_APP_BUILD
- CoUninitialize();
-#endif
+ stop();
}
void QWinRTBluetoothDeviceDiscoveryWorker::start()
{
- QEventDispatcherWinRT::runOnXamlThread([this]() {
- if (requestedModes & QBluetoothDeviceDiscoveryAgent::ClassicMethod)
- startDeviceDiscovery(QBluetoothDeviceDiscoveryAgent::ClassicMethod);
-
- if (requestedModes & QBluetoothDeviceDiscoveryAgent::LowEnergyMethod) {
- startDeviceDiscovery(QBluetoothDeviceDiscoveryAgent::LowEnergyMethod);
- setupLEDeviceWatcher();
+ if (requestedModes & QBluetoothDeviceDiscoveryAgent::ClassicMethod) {
+ if (m_classicWatcher && m_classicWatcher->init()) {
+ m_classicWatcher->start();
+ m_classicScanStarted = true;
+ } else {
+ generateError(QBluetoothDeviceDiscoveryAgent::Error::UnknownError,
+ "Could not start classic device watcher");
}
- return S_OK;
- });
+ }
+ if (requestedModes & QBluetoothDeviceDiscoveryAgent::LowEnergyMethod) {
+ if (m_lowEnergyWatcher && m_lowEnergyWatcher->init()) {
+ m_lowEnergyWatcher->start();
+ m_lowEnergyScanStarted = true;
+ } else {
+ generateError(QBluetoothDeviceDiscoveryAgent::Error::UnknownError,
+ "Could not start low energy device watcher");
+ }
+ if (m_advertisementWatcher) {
+ m_advertisementWatcher->init();
+ m_advertisementWatcher->start();
+ if (m_leScanTimer)
+ m_leScanTimer->start();
+ } else {
+ generateError(QBluetoothDeviceDiscoveryAgent::Error::UnknownError,
+ "Could not start low energy advertisement watcher");
+ }
+ }
- qCDebug(QT_BT_WINRT) << "Worker started";
+ qCDebug(QT_BT_WINDOWS) << "Worker started";
}
-void QWinRTBluetoothDeviceDiscoveryWorker::stopLEWatcher()
+void QWinRTBluetoothDeviceDiscoveryWorker::stop()
{
- if (m_leWatcher) {
- HRESULT hr = m_leWatcher->Stop();
- Q_ASSERT_SUCCEEDED(hr);
- if (m_leDeviceAddedToken.value) {
- hr = m_leWatcher->remove_Received(m_leDeviceAddedToken);
- Q_ASSERT_SUCCEEDED(hr);
- }
- }
+ if (m_leScanTimer && m_leScanTimer->isActive())
+ m_leScanTimer->stop();
+ m_classicWatcher->stop();
+ m_lowEnergyWatcher->stop();
+ m_advertisementWatcher->stop();
}
-void QWinRTBluetoothDeviceDiscoveryWorker::startDeviceDiscovery(QBluetoothDeviceDiscoveryAgent::DiscoveryMethod mode)
-{
- HString deviceSelector;
- ComPtr<IDeviceInformationStatics> deviceInformationStatics;
- HRESULT hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Devices_Enumeration_DeviceInformation).Get(), &deviceInformationStatics);
- WARN_AND_RETURN_IF_FAILED("Could not obtain device information statics", return);
- if (mode == QBluetoothDeviceDiscoveryAgent::LowEnergyMethod)
- m_leDeviceStatics->GetDeviceSelector(deviceSelector.GetAddressOf());
- else
- m_deviceStatics->GetDeviceSelector(deviceSelector.GetAddressOf());
- ComPtr<IAsyncOperation<DeviceInformationCollection *>> op;
- hr = deviceInformationStatics->FindAllAsyncAqsFilter(deviceSelector.Get(), &op);
- WARN_AND_RETURN_IF_FAILED("Could not start bluetooth device discovery operation", return);
- QPointer<QWinRTBluetoothDeviceDiscoveryWorker> thisPointer(this);
- hr = op->put_Completed(
- Callback<IAsyncOperationCompletedHandler<DeviceInformationCollection *>>([thisPointer, mode](IAsyncOperation<DeviceInformationCollection *> *op, AsyncStatus status) {
- if (status == Completed && thisPointer)
- thisPointer->onDeviceDiscoveryFinished(op, mode);
- return S_OK;
- }).Get());
- WARN_AND_RETURN_IF_FAILED("Could not add callback to bluetooth device discovery operation", return);
-}
-
-void QWinRTBluetoothDeviceDiscoveryWorker::onDeviceDiscoveryFinished(IAsyncOperation<DeviceInformationCollection *> *op, QBluetoothDeviceDiscoveryAgent::DiscoveryMethod mode)
-{
- qCDebug(QT_BT_WINRT) << (mode == QBluetoothDeviceDiscoveryAgent::ClassicMethod ? "BT" : "BTLE")
- << " scan completed";
- ComPtr<IVectorView<DeviceInformation *>> devices;
- HRESULT hr;
- hr = op->GetResults(&devices);
- Q_ASSERT_SUCCEEDED(hr);
- quint32 deviceCount;
- hr = devices->get_Size(&deviceCount);
- Q_ASSERT_SUCCEEDED(hr);
-
- // For classic discovery only paired devices will be found. If we only do classic disovery and
- // no device is found, the scan is finished.
- if (requestedModes == QBluetoothDeviceDiscoveryAgent::ClassicMethod &&
- deviceCount == 0) {
- finishDiscovery();
- return;
- }
+void QWinRTBluetoothDeviceDiscoveryWorker::finishDiscovery()
+{
+ stop();
+ emit scanFinished();
+}
- m_pendingPairedDevices += deviceCount;
- gatherMultipleDeviceInformation(deviceCount, devices.Get(), mode);
+bool QWinRTBluetoothDeviceDiscoveryWorker::isFinished() const
+{
+ // If the interval is set to 0, we do not start a timer, and that means
+ // that we need to wait for the user to explicitly call stop()
+ return (m_pendingDevices == 0) && !m_lowEnergyScanStarted && !m_classicScanStarted
+ && (m_leScanTimer && !m_leScanTimer->isActive());
}
-void QWinRTBluetoothDeviceDiscoveryWorker::gatherDeviceInformation(IDeviceInformation *deviceInfo, QBluetoothDeviceDiscoveryAgent::DiscoveryMethod mode)
+void QWinRTBluetoothDeviceDiscoveryWorker::onBluetoothDeviceFound(winrt::hstring deviceId, int watcherId)
{
- HString deviceId;
- HRESULT hr;
- hr = deviceInfo->get_Id(deviceId.GetAddressOf());
- Q_ASSERT_SUCCEEDED(hr);
- if (mode == QBluetoothDeviceDiscoveryAgent::LowEnergyMethod)
- leBluetoothInfoFromDeviceIdAsync(deviceId.Get());
- else
- classicBluetoothInfoFromDeviceIdAsync(deviceId.Get());
+ if (watcherId == ClassicWatcherId)
+ getClassicDeviceFromId(deviceId);
+ else if (watcherId == LowEnergyWatcherId)
+ getLowEnergyDeviceFromId(deviceId);
}
-void QWinRTBluetoothDeviceDiscoveryWorker::gatherMultipleDeviceInformation(quint32 deviceCount, IVectorView<DeviceInformation *> *devices, QBluetoothDeviceDiscoveryAgent::DiscoveryMethod mode)
+void QWinRTBluetoothDeviceDiscoveryWorker::onDeviceEnumerationCompleted(int watcherId)
{
- for (quint32 i = 0; i < deviceCount; ++i) {
- ComPtr<IDeviceInformation> device;
- HRESULT hr;
- hr = devices->GetAt(i, &device);
- Q_ASSERT_SUCCEEDED(hr);
- gatherDeviceInformation(device.Get(), mode);
+ qCDebug(QT_BT_WINDOWS) << (watcherId == ClassicWatcherId ? "BT" : "BTLE")
+ << "enumeration completed";
+ if (watcherId == ClassicWatcherId) {
+ m_classicWatcher->stop();
+ m_classicScanStarted = false;
+ } else if (watcherId == LowEnergyWatcherId) {
+ m_lowEnergyWatcher->stop();
+ m_lowEnergyScanStarted = false;
}
+ if (isFinished())
+ finishDiscovery();
}
-void QWinRTBluetoothDeviceDiscoveryWorker::setupLEDeviceWatcher()
+// this function executes in main worker thread
+void QWinRTBluetoothDeviceDiscoveryWorker::onAdvertisementDataReceived(
+ quint64 address, qint16 rssi, const ManufacturerData &manufacturerData,
+ const ServiceData &serviceData, const QList<QBluetoothUuid> &uuids)
{
- HRESULT hr = RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_Devices_Bluetooth_Advertisement_BluetoothLEAdvertisementWatcher).Get(), &m_leWatcher);
- Q_ASSERT_SUCCEEDED(hr);
-#if QT_CONFIG(winrt_btle_no_pairing)
- if (supportsNewLEApi()) {
- hr = m_leWatcher->put_ScanningMode(BluetoothLEScanningMode_Active);
- Q_ASSERT_SUCCEEDED(hr);
- }
-#endif // winrt_btle_no_pairing
- hr = m_leWatcher->add_Received(Callback<ITypedEventHandler<BluetoothLEAdvertisementWatcher *, BluetoothLEAdvertisementReceivedEventArgs *>>([this](IBluetoothLEAdvertisementWatcher *, IBluetoothLEAdvertisementReceivedEventArgs *args) {
- quint64 address;
- HRESULT hr;
- hr = args->get_BluetoothAddress(&address);
- Q_ASSERT_SUCCEEDED(hr);
- qint16 rssi;
- hr = args->get_RawSignalStrengthInDBm(&rssi);
- Q_ASSERT_SUCCEEDED(hr);
- ComPtr<IBluetoothLEAdvertisement> ad;
- hr = args->get_Advertisement(&ad);
- Q_ASSERT_SUCCEEDED(hr);
- const ManufacturerData manufacturerData = extractManufacturerData(ad);
- QBluetoothDeviceInfo::Fields changedFields = QBluetoothDeviceInfo::Field::None;
- if (!m_foundLEManufacturerData.contains(address)) {
- m_foundLEManufacturerData.insert(address, manufacturerData);
- changedFields.setFlag(QBluetoothDeviceInfo::Field::ManufacturerData);
- } else if (m_foundLEManufacturerData.value(address) != manufacturerData) {
- m_foundLEManufacturerData[address] = manufacturerData;
- changedFields.setFlag(QBluetoothDeviceInfo::Field::ManufacturerData);
- }
-#if QT_CONFIG(winrt_btle_no_pairing)
- if (supportsNewLEApi()) {
- ComPtr<IVector<GUID>> guids;
- hr = ad->get_ServiceUuids(&guids);
- Q_ASSERT_SUCCEEDED(hr);
- quint32 size;
- hr = guids->get_Size(&size);
- Q_ASSERT_SUCCEEDED(hr);
- QVector<QBluetoothUuid> serviceUuids;
- for (quint32 i = 0; i < size; ++i) {
- GUID guid;
- hr = guids->GetAt(i, &guid);
- Q_ASSERT_SUCCEEDED(hr);
- QBluetoothUuid uuid(guid);
- serviceUuids.append(uuid);
+ // Merge newly found services with list of currently found ones
+ bool needDiscoverServices = false;
+ {
+ QMutexLocker locker(&m_leDevicesMutex);
+ if (m_foundLEDevicesMap.contains(address)) {
+ QBluetoothDeviceInfo::Fields changedFields = QBluetoothDeviceInfo::Field::None;
+ const LEAdvertisingInfo adInfo = m_foundLEDevicesMap.value(address);
+ QList<QBluetoothUuid> foundServices = adInfo.services;
+ if (adInfo.rssi != rssi) {
+ m_foundLEDevicesMap[address].rssi = rssi;
+ changedFields.setFlag(QBluetoothDeviceInfo::Field::RSSI);
}
- QMutexLocker locker(&m_foundDevicesMutex);
- // Merge newly found services with list of currently found ones
- if (m_foundLEDevicesMap.contains(address)) {
- if (size == 0)
- return S_OK;
- const LEAdvertisingInfo adInfo = m_foundLEDevicesMap.value(address);
- QVector<QBluetoothUuid> foundServices = adInfo.services;
- if (adInfo.rssi != rssi) {
- m_foundLEDevicesMap[address].rssi = rssi;
- changedFields.setFlag(QBluetoothDeviceInfo::Field::RSSI);
- }
- bool newServiceAdded = false;
- for (const QBluetoothUuid &uuid : qAsConst(serviceUuids)) {
- if (!foundServices.contains(uuid)) {
- foundServices.append(uuid);
- newServiceAdded = true;
- }
- }
- if (!newServiceAdded) {
- if (!changedFields.testFlag(QBluetoothDeviceInfo::Field::None)) {
- QMetaObject::invokeMethod(this, "deviceDataChanged", Qt::AutoConnection,
- Q_ARG(QBluetoothAddress, QBluetoothAddress(address)),
- Q_ARG(QBluetoothDeviceInfo::Fields, changedFields),
- Q_ARG(qint16, rssi),
- Q_ARG(ManufacturerData, manufacturerData));
- }
- return S_OK;
- }
- m_foundLEDevicesMap[address].services = foundServices;
- } else {
- LEAdvertisingInfo info;
- info.services = std::move(serviceUuids);
- info.rssi = rssi;
- m_foundLEDevicesMap.insert(address, info);
+ if (adInfo.manufacturerData != manufacturerData) {
+ m_foundLEDevicesMap[address].manufacturerData.insert(manufacturerData);
+ if (adInfo.manufacturerData != m_foundLEDevicesMap[address].manufacturerData)
+ changedFields.setFlag(QBluetoothDeviceInfo::Field::ManufacturerData);
}
-
- locker.unlock();
- } else
-#endif
- {
- if (m_foundLEDevices.contains(address)) {
- if (m_foundLEDevices.value(address) != rssi) {
- m_foundLEDevices[address] = rssi;
- changedFields.setFlag(QBluetoothDeviceInfo::Field::RSSI);
+ if (adInfo.serviceData != serviceData) {
+ m_foundLEDevicesMap[address].serviceData.insert(serviceData);
+ if (adInfo.serviceData != m_foundLEDevicesMap[address].serviceData)
+ changedFields.setFlag((QBluetoothDeviceInfo::Field::ServiceData));
+ }
+ for (const QBluetoothUuid &uuid : std::as_const(uuids)) {
+ if (!foundServices.contains(uuid)) {
+ foundServices.append(uuid);
+ needDiscoverServices = true;
}
+ }
+ if (!needDiscoverServices) {
if (!changedFields.testFlag(QBluetoothDeviceInfo::Field::None)) {
QMetaObject::invokeMethod(this, "deviceDataChanged", Qt::AutoConnection,
Q_ARG(QBluetoothAddress, QBluetoothAddress(address)),
Q_ARG(QBluetoothDeviceInfo::Fields, changedFields),
Q_ARG(qint16, rssi),
- Q_ARG(ManufacturerData, manufacturerData));
+ Q_ARG(ManufacturerData, manufacturerData),
+ Q_ARG(ServiceData, serviceData));
}
- return S_OK;
}
- m_foundLEDevices.insert(address, rssi);
+ m_foundLEDevicesMap[address].services = foundServices;
+ } else {
+ needDiscoverServices = true;
+ LEAdvertisingInfo info;
+ info.services = std::move(uuids);
+ info.manufacturerData = std::move(manufacturerData);
+ info.serviceData = std::move(serviceData);
+ info.rssi = rssi;
+ m_foundLEDevicesMap.insert(address, info);
}
- leBluetoothInfoFromAddressAsync(address);
- return S_OK;
- }).Get(), &m_leDeviceAddedToken);
- Q_ASSERT_SUCCEEDED(hr);
- hr = m_leWatcher->Start();
- Q_ASSERT_SUCCEEDED(hr);
-}
-
-void QWinRTBluetoothDeviceDiscoveryWorker::finishDiscovery()
-{
- emit scanFinished();
- stopLEWatcher();
- deleteLater();
-}
-
-// "deviceFound" will be emitted at the end of the deviceFromIdOperation callback
-void QWinRTBluetoothDeviceDiscoveryWorker::classicBluetoothInfoFromDeviceIdAsync(HSTRING deviceId)
-{
- HRESULT hr;
- hr = QEventDispatcherWinRT::runOnXamlThread([deviceId, this]() {
- ComPtr<IAsyncOperation<BluetoothDevice *>> deviceFromIdOperation;
- // on Windows 10 FromIdAsync might ask for device permission. We cannot wait here but have to handle that asynchronously
- HRESULT hr = m_deviceStatics->FromIdAsync(deviceId, &deviceFromIdOperation);
- if (FAILED(hr)) {
- --m_pendingPairedDevices;
- if (!m_pendingPairedDevices
- && !(requestedModes & QBluetoothDeviceDiscoveryAgent::LowEnergyMethod))
- finishDiscovery();
- qCWarning(QT_BT_WINRT) << "Could not obtain bluetooth device from id";
- return S_OK;
- }
- QPointer<QWinRTBluetoothDeviceDiscoveryWorker> thisPointer(this);
- hr = deviceFromIdOperation->put_Completed(Callback<IAsyncOperationCompletedHandler<BluetoothDevice *>>
- ([thisPointer](IAsyncOperation<BluetoothDevice *> *op, AsyncStatus status)
- {
- if (thisPointer) {
- if (status == Completed)
- thisPointer->onPairedClassicBluetoothDeviceFoundAsync(op, status);
- --thisPointer->m_pendingPairedDevices;
+ }
+ if (needDiscoverServices) {
+ ++m_pendingDevices; // as if we discovered a new LE device
+ auto thisPtr = shared_from_this();
+ auto asyncOp = BluetoothLEDevice::FromBluetoothAddressAsync(address);
+ asyncOp.Completed([thisPtr, address](auto &&op, AsyncStatus status) {
+ if (thisPtr) {
+ if (status == AsyncStatus::Completed) {
+ BluetoothLEDevice device = op.GetResults();
+ if (device) {
+ thisPtr->handleLowEnergyDevice(device);
+ return;
+ }
+ }
+ // status != Completed or failed to extract result
+ qCDebug(QT_BT_WINDOWS) << "Failed to get LE device from address"
+ << QBluetoothAddress(address);
+ invokeDecrementPendingDevicesCountAndCheckFinished(thisPtr);
}
- return S_OK;
- }).Get());
- if (FAILED(hr)) {
- --m_pendingPairedDevices;
- if (!m_pendingPairedDevices
- && !(requestedModes & QBluetoothDeviceDiscoveryAgent::LowEnergyMethod))
- finishDiscovery();
- qCWarning(QT_BT_WINRT) << "Could not register device found callback";
- return S_OK;
- }
- return S_OK;
- });
- Q_ASSERT_SUCCEEDED(hr);
+ });
+ }
}
-// "deviceFound" will be emitted at the end of the deviceFromIdOperation callback
-void QWinRTBluetoothDeviceDiscoveryWorker::leBluetoothInfoFromDeviceIdAsync(HSTRING deviceId)
+void QWinRTBluetoothDeviceDiscoveryWorker::stopAdvertisementWatcher()
{
- HRESULT hr;
- hr = QEventDispatcherWinRT::runOnXamlThread([deviceId, this]() {
- ComPtr<IAsyncOperation<BluetoothLEDevice *>> deviceFromIdOperation;
- // on Windows 10 FromIdAsync might ask for device permission. We cannot wait here but have to handle that asynchronously
- HRESULT hr = m_leDeviceStatics->FromIdAsync(deviceId, &deviceFromIdOperation);
- if (FAILED(hr)) {
- --m_pendingPairedDevices;
- qCWarning(QT_BT_WINRT) << "Could not obtain bluetooth device from id";
- return S_OK;
- }
- QPointer<QWinRTBluetoothDeviceDiscoveryWorker> thisPointer(this);
- hr = deviceFromIdOperation->put_Completed(Callback<IAsyncOperationCompletedHandler<BluetoothLEDevice *>>
- ([thisPointer] (IAsyncOperation<BluetoothLEDevice *> *op, AsyncStatus status)
- {
- if (thisPointer) {
- if (status == Completed)
- thisPointer->onPairedBluetoothLEDeviceFoundAsync(op, status);
- --thisPointer->m_pendingPairedDevices;
- }
- return S_OK;
- }).Get());
- if (FAILED(hr)) {
- --m_pendingPairedDevices;
- qCWarning(QT_BT_WINRT) << "Could not register device found callback";
- return S_OK;
- }
- return S_OK;
- });
- Q_ASSERT_SUCCEEDED(hr);
+ m_advertisementWatcher->stop();
+ if (isFinished())
+ finishDiscovery();
}
-// "deviceFound" will be emitted at the end of the deviceFromAdressOperation callback
-void QWinRTBluetoothDeviceDiscoveryWorker::leBluetoothInfoFromAddressAsync(quint64 address)
+std::shared_ptr<QBluetoothDeviceWatcherWinRT>
+QWinRTBluetoothDeviceDiscoveryWorker::createDeviceWatcher(winrt::hstring selector, int watcherId)
{
- HRESULT hr;
- hr = QEventDispatcherWinRT::runOnXamlThread([address, this]() {
- ComPtr<IAsyncOperation<BluetoothLEDevice *>> deviceFromAddressOperation;
- // on Windows 10 FromBluetoothAddressAsync might ask for device permission. We cannot wait
- // here but have to handle that asynchronously
- HRESULT hr = m_leDeviceStatics->FromBluetoothAddressAsync(address, &deviceFromAddressOperation);
- if (FAILED(hr)) {
- qCWarning(QT_BT_WINRT) << "Could not obtain bluetooth device from address";
- return S_OK;
- }
- QPointer<QWinRTBluetoothDeviceDiscoveryWorker> thisPointer(this);
- hr = deviceFromAddressOperation->put_Completed(Callback<IAsyncOperationCompletedHandler<BluetoothLEDevice *>>
- ([thisPointer](IAsyncOperation<BluetoothLEDevice *> *op, AsyncStatus status)
- {
- if (status == Completed && thisPointer)
- thisPointer->onBluetoothLEDeviceFoundAsync(op, status);
- return S_OK;
- }).Get());
- if (FAILED(hr)) {
- qCWarning(QT_BT_WINRT) << "Could not register device found callback";
- return S_OK;
- }
- return S_OK;
- });
- Q_ASSERT_SUCCEEDED(hr);
-}
-
-HRESULT QWinRTBluetoothDeviceDiscoveryWorker::onPairedClassicBluetoothDeviceFoundAsync(IAsyncOperation<BluetoothDevice *> *op, AsyncStatus status)
-{
- --m_pendingPairedDevices;
- if (status != AsyncStatus::Completed)
- return S_OK;
-
- ComPtr<IBluetoothDevice> device;
- HRESULT hr = op->GetResults(&device);
- Q_ASSERT_SUCCEEDED(hr);
-
- if (!device)
- return S_OK;
-
- UINT64 address;
- HString name;
- ComPtr<IBluetoothClassOfDevice> classOfDevice;
- UINT32 classOfDeviceInt;
- hr = device->get_BluetoothAddress(&address);
- Q_ASSERT_SUCCEEDED(hr);
- hr = device->get_Name(name.GetAddressOf());
- Q_ASSERT_SUCCEEDED(hr);
- const QString btName = QString::fromWCharArray(WindowsGetStringRawBuffer(name.Get(), nullptr));
- hr = device->get_ClassOfDevice(&classOfDevice);
- Q_ASSERT_SUCCEEDED(hr);
- hr = classOfDevice->get_RawValue(&classOfDeviceInt);
- Q_ASSERT_SUCCEEDED(hr);
- IVectorView <Rfcomm::RfcommDeviceService *> *deviceServices;
- hr = device->get_RfcommServices(&deviceServices);
- if (hr == E_ACCESSDENIED) {
- qCWarning(QT_BT_WINRT) << "Could not obtain device services. Please check you have "
- "permission to access the device.";
- } else {
- Q_ASSERT_SUCCEEDED(hr);
- uint serviceCount;
- hr = deviceServices->get_Size(&serviceCount);
- Q_ASSERT_SUCCEEDED(hr);
- QVector<QBluetoothUuid> uuids;
- for (uint i = 0; i < serviceCount; ++i) {
- ComPtr<Rfcomm::IRfcommDeviceService> service;
- hr = deviceServices->GetAt(i, &service);
- Q_ASSERT_SUCCEEDED(hr);
- ComPtr<Rfcomm::IRfcommServiceId> id;
- hr = service->get_ServiceId(&id);
- Q_ASSERT_SUCCEEDED(hr);
- GUID uuid;
- hr = id->get_Uuid(&uuid);
- Q_ASSERT_SUCCEEDED(hr);
- uuids.append(QBluetoothUuid(uuid));
- }
-
- qCDebug(QT_BT_WINRT) << "Discovered BT device: " << QString::number(address) << btName
- << "Num UUIDs" << uuids.count();
-
- QBluetoothDeviceInfo info(QBluetoothAddress(address), btName, classOfDeviceInt);
- info.setCoreConfigurations(QBluetoothDeviceInfo::BaseRateCoreConfiguration);
- info.setServiceUuids(uuids);
- info.setCached(true);
-
- QMetaObject::invokeMethod(this, "deviceFound", Qt::AutoConnection,
- Q_ARG(QBluetoothDeviceInfo, info));
+ auto watcher = std::make_shared<QBluetoothDeviceWatcherWinRT>(
+ watcherId, selector, DeviceInformationKind::AssociationEndpoint);
+ if (watcher) {
+ connect(watcher.get(), &QBluetoothDeviceWatcherWinRT::deviceAdded,
+ this, &QWinRTBluetoothDeviceDiscoveryWorker::onBluetoothDeviceFound,
+ Qt::QueuedConnection);
+ connect(watcher.get(), &QBluetoothDeviceWatcherWinRT::enumerationCompleted,
+ this, &QWinRTBluetoothDeviceDiscoveryWorker::onDeviceEnumerationCompleted,
+ Qt::QueuedConnection);
}
- if (!m_pendingPairedDevices && !(requestedModes & QBluetoothDeviceDiscoveryAgent::LowEnergyMethod))
- finishDiscovery();
- return S_OK;
+ return watcher;
}
-HRESULT QWinRTBluetoothDeviceDiscoveryWorker::onPairedBluetoothLEDeviceFoundAsync(IAsyncOperation<BluetoothLEDevice *> *op, AsyncStatus status)
+void QWinRTBluetoothDeviceDiscoveryWorker::generateError(
+ QBluetoothDeviceDiscoveryAgent::Error error, const char *msg)
{
- --m_pendingPairedDevices;
- if (status != AsyncStatus::Completed)
- return S_OK;
-
- ComPtr<IBluetoothLEDevice> device;
- HRESULT hr;
- hr = op->GetResults(&device);
- Q_ASSERT_SUCCEEDED(hr);
-#if QT_CONFIG(winrt_btle_no_pairing)
- if (supportsNewLEApi())
- return onBluetoothLEDeviceFound(device);
- else
-#endif
- return onBluetoothLEDeviceFound(device, OmitPairingCheck);
+ emit errorOccured(error);
+ qCWarning(QT_BT_WINDOWS) << msg;
}
-HRESULT QWinRTBluetoothDeviceDiscoveryWorker::onBluetoothLEDeviceFoundAsync(IAsyncOperation<BluetoothLEDevice *> *op, AsyncStatus status)
+void QWinRTBluetoothDeviceDiscoveryWorker::invokeDeviceFoundWithDebug(const QBluetoothDeviceInfo &info)
{
- if (status != AsyncStatus::Completed)
- return S_OK;
+ qCDebug(QT_BT_WINDOWS) << "Discovered BTLE device: " << info.address() << info.name()
+ << "Num UUIDs" << info.serviceUuids().size() << "RSSI:" << info.rssi()
+ << "Num manufacturer data" << info.manufacturerData().size()
+ << "Num service data" << info.serviceData().size();
- ComPtr<IBluetoothLEDevice> device;
- HRESULT hr;
- hr = op->GetResults(&device);
- Q_ASSERT_SUCCEEDED(hr);
-#if QT_CONFIG(winrt_btle_no_pairing)
- if (supportsNewLEApi())
- return onBluetoothLEDeviceFound(device);
- else
-#endif
- return onBluetoothLEDeviceFound(device, PairingCheck::CheckForPairing);
+ QMetaObject::invokeMethod(this, "deviceFound", Qt::AutoConnection,
+ Q_ARG(QBluetoothDeviceInfo, info));
}
-HRESULT QWinRTBluetoothDeviceDiscoveryWorker::onBluetoothLEDeviceFound(ComPtr<IBluetoothLEDevice> device, PairingCheck pairingCheck)
+// this function executes in main worker thread
+void QWinRTBluetoothDeviceDiscoveryWorker::getClassicDeviceFromId(const winrt::hstring &id)
{
- if (!device) {
- qCDebug(QT_BT_WINRT) << "onBluetoothLEDeviceFound: No device given";
- return S_OK;
- }
-
- if (pairingCheck == CheckForPairing) {
- ComPtr<IBluetoothLEDevice2> device2;
- HRESULT hr = device.As(&device2);
- Q_ASSERT_SUCCEEDED(hr);
- ComPtr<IDeviceInformation> deviceInfo;
- hr = device2->get_DeviceInformation(&deviceInfo);
- Q_ASSERT_SUCCEEDED(hr);
- if (!deviceInfo) {
- qCDebug(QT_BT_WINRT) << "onBluetoothLEDeviceFound: Could not obtain device information";
- return S_OK;
- }
- ComPtr<IDeviceInformation2> deviceInfo2;
- hr = deviceInfo.As(&deviceInfo2);
- Q_ASSERT_SUCCEEDED(hr);
- ComPtr<IDeviceInformationPairing> pairing;
- hr = deviceInfo2->get_Pairing(&pairing);
- Q_ASSERT_SUCCEEDED(hr);
- boolean isPaired;
- hr = pairing->get_IsPaired(&isPaired);
- Q_ASSERT_SUCCEEDED(hr);
- // We need a paired device in order to be able to obtain its information
- if (!isPaired) {
- ComPtr<IAsyncOperation<DevicePairingResult *>> pairingOp;
- QPointer<QWinRTBluetoothDeviceDiscoveryWorker> tPointer(this);
- hr = pairing.Get()->PairAsync(&pairingOp);
- Q_ASSERT_SUCCEEDED(hr);
- pairingOp->put_Completed(
- Callback<IAsyncOperationCompletedHandler<DevicePairingResult *>>([device, tPointer](IAsyncOperation<DevicePairingResult *> *op, AsyncStatus status) {
- if (!tPointer)
- return S_OK;
-
- if (status != AsyncStatus::Completed) {
- qCDebug(QT_BT_WINRT) << "Could not pair device";
- return S_OK;
+ ++m_pendingDevices;
+ auto thisPtr = shared_from_this();
+ auto asyncOp = BluetoothDevice::FromIdAsync(id);
+ asyncOp.Completed([thisPtr](auto &&op, AsyncStatus status) {
+ if (thisPtr) {
+ if (status == AsyncStatus::Completed) {
+ BluetoothDevice device = op.GetResults();
+ if (device) {
+ thisPtr->handleClassicDevice(device);
+ return;
}
+ }
+ // status != Completed or failed to extract result
+ qCDebug(QT_BT_WINDOWS) << "Failed to get Classic device from id";
+ invokeDecrementPendingDevicesCountAndCheckFinished(thisPtr);
+ }
+ });
+}
- ComPtr<IDevicePairingResult> result;
- op->GetResults(&result);
-
- DevicePairingResultStatus pairingStatus;
- result.Get()->get_Status(&pairingStatus);
-
- if (pairingStatus != DevicePairingResultStatus_Paired) {
- qCDebug(QT_BT_WINRT) << "Could not pair device";
- return S_OK;
+// this is a callback - executes in a new thread
+void QWinRTBluetoothDeviceDiscoveryWorker::handleClassicDevice(const BluetoothDevice &device)
+{
+ const uint64_t address = device.BluetoothAddress();
+ const std::wstring name { device.Name() }; // via operator std::wstring_view()
+ const QString btName = QString::fromStdWString(name);
+ const uint32_t deviceClass = device.ClassOfDevice().RawValue();
+ auto thisPtr = shared_from_this();
+ auto asyncOp = device.GetRfcommServicesAsync();
+ asyncOp.Completed([thisPtr, address, btName, deviceClass](auto &&op, AsyncStatus status) {
+ if (thisPtr) {
+ if (status == AsyncStatus::Completed) {
+ auto servicesResult = op.GetResults();
+ if (servicesResult) {
+ thisPtr->handleRfcommServices(servicesResult, address, btName, deviceClass);
+ return;
}
-
- tPointer->onBluetoothLEDeviceFound(device, OmitPairingCheck);
- return S_OK;
- }).Get());
- return S_OK;
+ }
+ // Failed to get services
+ qCDebug(QT_BT_WINDOWS) << "Failed to get RFCOMM services for device" << btName;
+ invokeDecrementPendingDevicesCountAndCheckFinished(thisPtr);
}
+ });
+}
+
+// this is a callback - executes in a new thread
+void QWinRTBluetoothDeviceDiscoveryWorker::handleRfcommServices(
+ const RfcommDeviceServicesResult &servicesResult, uint64_t address,
+ const QString &name, uint32_t classOfDeviceInt)
+{
+ // need to perform the check even if some of the operations fails
+ auto shared = shared_from_this();
+ auto guard = qScopeGuard([shared]() {
+ invokeDecrementPendingDevicesCountAndCheckFinished(shared);
+ });
+ Q_UNUSED(guard); // to suppress warning
+
+ const auto error = servicesResult.Error();
+ if (error != BluetoothError::Success) {
+ qCWarning(QT_BT_WINDOWS) << "Obtain device services completed with BluetoothError"
+ << static_cast<int>(error);
+ return;
}
- UINT64 address;
- HString name;
- HRESULT hr = device->get_BluetoothAddress(&address);
- Q_ASSERT_SUCCEEDED(hr);
- hr = device->get_Name(name.GetAddressOf());
- Q_ASSERT_SUCCEEDED(hr);
- const QString btName = QString::fromWCharArray(WindowsGetStringRawBuffer(name.Get(), nullptr));
- IVectorView <GenericAttributeProfile::GattDeviceService *> *deviceServices;
- hr = device->get_GattServices(&deviceServices);
- Q_ASSERT_SUCCEEDED(hr);
- uint serviceCount;
- hr = deviceServices->get_Size(&serviceCount);
- Q_ASSERT_SUCCEEDED(hr);
- QVector<QBluetoothUuid> uuids;
- for (uint i = 0; i < serviceCount; ++i) {
- ComPtr<GenericAttributeProfile::IGattDeviceService> service;
- hr = deviceServices->GetAt(i, &service);
- Q_ASSERT_SUCCEEDED(hr);
- ComPtr<Rfcomm::IRfcommServiceId> id;
- GUID uuid;
- hr = service->get_Uuid(&uuid);
- Q_ASSERT_SUCCEEDED(hr);
+ const auto services = servicesResult.Services();
+ QList<QBluetoothUuid> uuids;
+ for (const auto &service : services) {
+ const auto serviceId = service.ServiceId();
+ const GUID uuid = fromWinRtGuid(serviceId.Uuid());
uuids.append(QBluetoothUuid(uuid));
}
- const qint16 rssi = m_foundLEDevices.value(address);
- const ManufacturerData manufacturerData = m_foundLEManufacturerData.value(address);
- qCDebug(QT_BT_WINRT) << "Discovered BTLE device: " << QString::number(address) << btName
- << "Num UUIDs" << uuids.count() << "RSSI:" << rssi
- << "Num manufacturer data" << manufacturerData.count();
+ const QBluetoothAddress btAddress(address);
- QBluetoothDeviceInfo info(QBluetoothAddress(address), btName, 0);
- info.setCoreConfigurations(QBluetoothDeviceInfo::LowEnergyCoreConfiguration);
+ qCDebug(QT_BT_WINDOWS) << "Discovered BT device: " << btAddress << name
+ << "Num UUIDs" << uuids.size();
+
+ QBluetoothDeviceInfo info(btAddress, name, classOfDeviceInt);
+ info.setCoreConfigurations(QBluetoothDeviceInfo::BaseRateCoreConfiguration);
info.setServiceUuids(uuids);
- info.setRssi(rssi);
- for (const quint16 key : manufacturerData.keys())
- info.setManufacturerData(key, manufacturerData.value(key));
info.setCached(true);
QMetaObject::invokeMethod(this, "deviceFound", Qt::AutoConnection,
Q_ARG(QBluetoothDeviceInfo, info));
- return S_OK;
}
-#if QT_CONFIG(winrt_btle_no_pairing)
-HRESULT QWinRTBluetoothDeviceDiscoveryWorker::onBluetoothLEDeviceFound(ComPtr<IBluetoothLEDevice> device)
+void QWinRTBluetoothDeviceDiscoveryWorker::decrementPendingDevicesCountAndCheckFinished(
+ std::shared_ptr<QWinRTBluetoothDeviceDiscoveryWorker> worker)
{
- if (!device) {
- qCDebug(QT_BT_WINRT) << "onBluetoothLEDeviceFound: No device given";
- return S_OK;
- }
+ --m_pendingDevices;
+ if (isFinished())
+ finishDiscovery();
+ // Worker is passed here simply to make sure that the object is still alive
+ // when we call this method via QObject::invoke().
+ Q_UNUSED(worker)
+}
- UINT64 address;
- HString name;
- HRESULT hr = device->get_BluetoothAddress(&address);
- Q_ASSERT_SUCCEEDED(hr);
- hr = device->get_Name(name.GetAddressOf());
- Q_ASSERT_SUCCEEDED(hr);
- const QString btName = QString::fromWCharArray(WindowsGetStringRawBuffer(name.Get(), nullptr));
-
- ComPtr<IBluetoothLEDevice2> device2;
- hr = device.As(&device2);
- Q_ASSERT_SUCCEEDED(hr);
- ComPtr<IDeviceInformation> deviceInfo;
- hr = device2->get_DeviceInformation(&deviceInfo);
- Q_ASSERT_SUCCEEDED(hr);
- if (!deviceInfo) {
- qCDebug(QT_BT_WINRT) << "onBluetoothLEDeviceFound: Could not obtain device information";
- return S_OK;
- }
- ComPtr<IDeviceInformation2> deviceInfo2;
- hr = deviceInfo.As(&deviceInfo2);
- Q_ASSERT_SUCCEEDED(hr);
- ComPtr<IDeviceInformationPairing> pairing;
- hr = deviceInfo2->get_Pairing(&pairing);
- Q_ASSERT_SUCCEEDED(hr);
- boolean isPaired;
- hr = pairing->get_IsPaired(&isPaired);
- Q_ASSERT_SUCCEEDED(hr);
- QVector<QBluetoothUuid> uuids;
+// this function executes in main worker thread
+void QWinRTBluetoothDeviceDiscoveryWorker::getLowEnergyDeviceFromId(const winrt::hstring &id)
+{
+ ++m_pendingDevices;
+ auto asyncOp = BluetoothLEDevice::FromIdAsync(id);
+ auto thisPtr = shared_from_this();
+ asyncOp.Completed([thisPtr](auto &&op, AsyncStatus status) {
+ if (thisPtr) {
+ if (status == AsyncStatus::Completed) {
+ BluetoothLEDevice device = op.GetResults();
+ if (device) {
+ thisPtr->handleLowEnergyDevice(device);
+ return;
+ }
+ }
+ // status != Completed or failed to extract result
+ qCDebug(QT_BT_WINDOWS) << "Failed to get LE device from id";
+ invokeDecrementPendingDevicesCountAndCheckFinished(thisPtr);
+ }
+ });
+}
+
+// this is a callback - executes in a new thread
+void QWinRTBluetoothDeviceDiscoveryWorker::handleLowEnergyDevice(const BluetoothLEDevice &device)
+{
+ const uint64_t address = device.BluetoothAddress();
+ const std::wstring name { device.Name() }; // via operator std::wstring_view()
+ const QString btName = QString::fromStdWString(name);
+ const bool isPaired = device.DeviceInformation().Pairing().IsPaired();
+ m_leDevicesMutex.lock();
const LEAdvertisingInfo adInfo = m_foundLEDevicesMap.value(address);
+ m_leDevicesMutex.unlock();
+ const ManufacturerData manufacturerData = adInfo.manufacturerData;
+ const ServiceData serviceData = adInfo.serviceData;
const qint16 rssi = adInfo.rssi;
- // Use the services obtained from the advertisement data if the device is not paired
- if (!isPaired) {
- uuids = adInfo.services;
- } else {
- IVectorView <GenericAttributeProfile::GattDeviceService *> *deviceServices;
- hr = device->get_GattServices(&deviceServices);
- Q_ASSERT_SUCCEEDED(hr);
- uint serviceCount;
- hr = deviceServices->get_Size(&serviceCount);
- Q_ASSERT_SUCCEEDED(hr);
- for (uint i = 0; i < serviceCount; ++i) {
- ComPtr<GenericAttributeProfile::IGattDeviceService> service;
- hr = deviceServices->GetAt(i, &service);
- Q_ASSERT_SUCCEEDED(hr);
- GUID uuid;
- hr = service->get_Uuid(&uuid);
- Q_ASSERT_SUCCEEDED(hr);
- uuids.append(QBluetoothUuid(uuid));
- }
- }
- const ManufacturerData manufacturerData = m_foundLEManufacturerData.value(address);
-
- qCDebug(QT_BT_WINRT) << "Discovered BTLE device: " << QString::number(address) << btName
- << "Num UUIDs" << uuids.count() << "RSSI:" << rssi
- << "Num manufacturer data" << manufacturerData.count();
QBluetoothDeviceInfo info(QBluetoothAddress(address), btName, 0);
info.setCoreConfigurations(QBluetoothDeviceInfo::LowEnergyCoreConfiguration);
- info.setServiceUuids(uuids);
info.setRssi(rssi);
for (quint16 key : manufacturerData.keys())
info.setManufacturerData(key, manufacturerData.value(key));
+ for (QBluetoothUuid key : serviceData.keys())
+ info.setServiceData(key, serviceData.value(key));
info.setCached(true);
- QMetaObject::invokeMethod(this, "deviceFound", Qt::AutoConnection,
- Q_ARG(QBluetoothDeviceInfo, info));
- return S_OK;
+ // Use the services obtained from the advertisement data if the device is not paired
+ if (!isPaired) {
+ info.setServiceUuids(adInfo.services);
+ invokeDecrementPendingDevicesCountAndCheckFinished(shared_from_this());
+ invokeDeviceFoundWithDebug(info);
+ } else {
+ auto asyncOp = device.GetGattServicesAsync();
+ auto thisPtr = shared_from_this();
+ asyncOp.Completed([thisPtr, info](auto &&op, AsyncStatus status) mutable {
+ if (status == AsyncStatus::Completed) {
+ auto servicesResult = op.GetResults();
+ if (servicesResult) {
+ thisPtr->handleGattServices(servicesResult, info);
+ return;
+ }
+ }
+ // Failed to get services
+ qCDebug(QT_BT_WINDOWS) << "Failed to get GATT services for device" << info.name();
+ invokeDecrementPendingDevicesCountAndCheckFinished(thisPtr);
+ });
+ }
}
-#endif // QT_CONFIG(winrt_btle_no_pairing)
-QBluetoothDeviceDiscoveryAgentPrivate::QBluetoothDeviceDiscoveryAgentPrivate(
- const QBluetoothAddress &deviceAdapter,
- QBluetoothDeviceDiscoveryAgent *parent)
+// this is a callback - executes in a new thread
+void QWinRTBluetoothDeviceDiscoveryWorker::handleGattServices(
+ const GattDeviceServicesResult &servicesResult, QBluetoothDeviceInfo &info)
+{
+ // need to perform the check even if some of the operations fails
+ auto shared = shared_from_this();
+ auto guard = qScopeGuard([shared]() {
+ invokeDecrementPendingDevicesCountAndCheckFinished(shared);
+ });
+ Q_UNUSED(guard); // to suppress warning
+
+ const auto status = servicesResult.Status();
+ if (status == GattCommunicationStatus::Success) {
+ const auto services = servicesResult.Services();
+ QList<QBluetoothUuid> uuids;
+ for (const auto &service : services) {
+ const GUID uuid = fromWinRtGuid(service.Uuid());
+ uuids.append(QBluetoothUuid(uuid));
+ }
+ info.setServiceUuids(uuids);
+ } else {
+ qCWarning(QT_BT_WINDOWS) << "Obtaining LE services finished with status"
+ << static_cast<int>(status);
+ }
+ invokeDeviceFoundWithDebug(info);
+}
+
+std::shared_ptr<AdvertisementWatcherWrapper>
+QWinRTBluetoothDeviceDiscoveryWorker::createAdvertisementWatcher()
+{
+ auto watcher = std::make_shared<AdvertisementWatcherWrapper>();
+ if (watcher) {
+ connect(watcher.get(), &AdvertisementWatcherWrapper::advertisementDataReceived,
+ this, &QWinRTBluetoothDeviceDiscoveryWorker::onAdvertisementDataReceived,
+ Qt::QueuedConnection);
+ }
+ return watcher;
+}
- : inquiryType(QBluetoothDeviceDiscoveryAgent::GeneralUnlimitedInquiry),
- lastError(QBluetoothDeviceDiscoveryAgent::NoError),
- lowEnergySearchTimeout(25000),
- q_ptr(parent),
- leScanTimer(0)
+QBluetoothDeviceDiscoveryAgentPrivate::QBluetoothDeviceDiscoveryAgentPrivate(
+ const QBluetoothAddress &deviceAdapter, QBluetoothDeviceDiscoveryAgent *parent)
+ : q_ptr(parent), adapterAddress(deviceAdapter)
{
- Q_UNUSED(deviceAdapter);
+ mainThreadCoInit(this);
}
QBluetoothDeviceDiscoveryAgentPrivate::~QBluetoothDeviceDiscoveryAgentPrivate()
{
disconnectAndClearWorker();
+ mainThreadCoUninit(this);
}
bool QBluetoothDeviceDiscoveryAgentPrivate::isActive() const
{
- return worker;
+ return worker != nullptr;
}
QBluetoothDeviceDiscoveryAgent::DiscoveryMethods QBluetoothDeviceDiscoveryAgent::supportedDiscoveryMethods()
@@ -840,41 +740,48 @@ QBluetoothDeviceDiscoveryAgent::DiscoveryMethods QBluetoothDeviceDiscoveryAgent:
void QBluetoothDeviceDiscoveryAgentPrivate::start(QBluetoothDeviceDiscoveryAgent::DiscoveryMethods methods)
{
+ QBluetoothLocalDevice adapter(adapterAddress);
+ if (!adapter.isValid()) {
+ qCWarning(QT_BT_WINDOWS) << "Cannot find Bluetooth adapter for device search";
+ lastError = QBluetoothDeviceDiscoveryAgent::InvalidBluetoothAdapterError;
+ errorString = QBluetoothDeviceDiscoveryAgent::tr("Cannot find valid Bluetooth adapter.");
+ emit q_ptr->errorOccurred(lastError);
+ return;
+ } else if (adapter.hostMode() == QBluetoothLocalDevice::HostPoweredOff) {
+ qCWarning(QT_BT_WINDOWS) << "Bluetooth adapter powered off";
+ lastError = QBluetoothDeviceDiscoveryAgent::PoweredOffError;
+ errorString = QBluetoothDeviceDiscoveryAgent::tr("Bluetooth adapter powered off.");
+ emit q_ptr->errorOccurred(lastError);
+ return;
+ }
+
if (worker)
return;
- worker = new QWinRTBluetoothDeviceDiscoveryWorker(methods);
+ worker = std::make_shared<QWinRTBluetoothDeviceDiscoveryWorker>(methods,
+ lowEnergySearchTimeout);
+ lastError = QBluetoothDeviceDiscoveryAgent::NoError;
+ errorString.clear();
discoveredDevices.clear();
- connect(worker, &QWinRTBluetoothDeviceDiscoveryWorker::deviceFound,
+ connect(worker.get(), &QWinRTBluetoothDeviceDiscoveryWorker::deviceFound,
this, &QBluetoothDeviceDiscoveryAgentPrivate::registerDevice);
- connect(worker, &QWinRTBluetoothDeviceDiscoveryWorker::deviceDataChanged,
+ connect(worker.get(), &QWinRTBluetoothDeviceDiscoveryWorker::deviceDataChanged,
this, &QBluetoothDeviceDiscoveryAgentPrivate::updateDeviceData);
- connect(worker, &QWinRTBluetoothDeviceDiscoveryWorker::scanFinished,
+ connect(worker.get(), &QWinRTBluetoothDeviceDiscoveryWorker::errorOccured,
+ this, &QBluetoothDeviceDiscoveryAgentPrivate::onErrorOccured);
+ connect(worker.get(), &QWinRTBluetoothDeviceDiscoveryWorker::scanFinished,
this, &QBluetoothDeviceDiscoveryAgentPrivate::onScanFinished);
worker->start();
-
- if (lowEnergySearchTimeout > 0 && methods & QBluetoothDeviceDiscoveryAgent::LowEnergyMethod) { // otherwise no timeout and stop() required
- if (!leScanTimer) {
- leScanTimer = new QTimer(this);
- leScanTimer->setSingleShot(true);
- }
- connect(leScanTimer, &QTimer::timeout,
- worker, &QWinRTBluetoothDeviceDiscoveryWorker::finishDiscovery);
- leScanTimer->setInterval(lowEnergySearchTimeout);
- leScanTimer->start();
- }
}
void QBluetoothDeviceDiscoveryAgentPrivate::stop()
{
Q_Q(QBluetoothDeviceDiscoveryAgent);
if (worker) {
- worker->stopLEWatcher();
+ worker->stop();
disconnectAndClearWorker();
emit q->canceled();
}
- if (leScanTimer)
- leScanTimer->stop();
}
void QBluetoothDeviceDiscoveryAgentPrivate::registerDevice(const QBluetoothDeviceInfo &info)
@@ -884,16 +791,12 @@ void QBluetoothDeviceDiscoveryAgentPrivate::registerDevice(const QBluetoothDevic
for (QList<QBluetoothDeviceInfo>::iterator iter = discoveredDevices.begin();
iter != discoveredDevices.end(); ++iter) {
if (iter->address() == info.address()) {
- qCDebug(QT_BT_WINRT) << "Updating device" << iter->name() << iter->address();
+ qCDebug(QT_BT_WINDOWS) << "Updating device" << iter->name() << iter->address();
// merge service uuids
-#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
- QVector<QBluetoothUuid> uuids = iter->serviceUuids();
-#else
QList<QBluetoothUuid> uuids = iter->serviceUuids();
-#endif
uuids.append(info.serviceUuids());
const QSet<QBluetoothUuid> uuidSet(uuids.begin(), uuids.end());
- if (iter->serviceUuids().count() != uuidSet.count())
+ if (iter->serviceUuids().size() != uuidSet.size())
iter->setServiceUuids(uuidSet.values().toVector());
if (iter->coreConfigurations() != info.coreConfigurations())
iter->setCoreConfigurations(QBluetoothDeviceInfo::BaseRateAndLowEnergyCoreConfiguration);
@@ -908,7 +811,8 @@ void QBluetoothDeviceDiscoveryAgentPrivate::registerDevice(const QBluetoothDevic
void QBluetoothDeviceDiscoveryAgentPrivate::updateDeviceData(const QBluetoothAddress &address,
QBluetoothDeviceInfo::Fields fields,
qint16 rssi,
- ManufacturerData manufacturerData)
+ ManufacturerData manufacturerData,
+ ServiceData serviceData)
{
if (fields.testFlag(QBluetoothDeviceInfo::Field::None))
return;
@@ -917,18 +821,28 @@ void QBluetoothDeviceDiscoveryAgentPrivate::updateDeviceData(const QBluetoothAdd
for (QList<QBluetoothDeviceInfo>::iterator iter = discoveredDevices.begin();
iter != discoveredDevices.end(); ++iter) {
if (iter->address() == address) {
- qCDebug(QT_BT_WINRT) << "Updating data for device" << iter->name() << iter->address();
+ qCDebug(QT_BT_WINDOWS) << "Updating data for device" << iter->name() << iter->address();
if (fields.testFlag(QBluetoothDeviceInfo::Field::RSSI))
iter->setRssi(rssi);
if (fields.testFlag(QBluetoothDeviceInfo::Field::ManufacturerData))
for (quint16 key : manufacturerData.keys())
iter->setManufacturerData(key, manufacturerData.value(key));
+ if (fields.testFlag(QBluetoothDeviceInfo::Field::ServiceData))
+ for (QBluetoothUuid key : serviceData.keys())
+ iter->setServiceData(key, serviceData.value(key));
emit q->deviceUpdated(*iter, fields);
return;
}
}
}
+void QBluetoothDeviceDiscoveryAgentPrivate::onErrorOccured(QBluetoothDeviceDiscoveryAgent::Error e)
+{
+ Q_Q(QBluetoothDeviceDiscoveryAgent);
+ lastError = e;
+ emit q->errorOccurred(e);
+}
+
void QBluetoothDeviceDiscoveryAgentPrivate::onScanFinished()
{
Q_Q(QBluetoothDeviceDiscoveryAgent);
@@ -941,17 +855,16 @@ void QBluetoothDeviceDiscoveryAgentPrivate::disconnectAndClearWorker()
if (!worker)
return;
- disconnect(worker, &QWinRTBluetoothDeviceDiscoveryWorker::scanFinished,
+ disconnect(worker.get(), &QWinRTBluetoothDeviceDiscoveryWorker::scanFinished,
this, &QBluetoothDeviceDiscoveryAgentPrivate::onScanFinished);
- disconnect(worker, &QWinRTBluetoothDeviceDiscoveryWorker::deviceFound,
+ disconnect(worker.get(), &QWinRTBluetoothDeviceDiscoveryWorker::deviceFound,
this, &QBluetoothDeviceDiscoveryAgentPrivate::registerDevice);
- disconnect(worker, &QWinRTBluetoothDeviceDiscoveryWorker::deviceDataChanged,
+ disconnect(worker.get(), &QWinRTBluetoothDeviceDiscoveryWorker::deviceDataChanged,
this, &QBluetoothDeviceDiscoveryAgentPrivate::updateDeviceData);
- if (leScanTimer) {
- disconnect(leScanTimer, &QTimer::timeout,
- worker, &QWinRTBluetoothDeviceDiscoveryWorker::finishDiscovery);
- }
- worker.clear();
+ disconnect(worker.get(), &QWinRTBluetoothDeviceDiscoveryWorker::errorOccured,
+ this, &QBluetoothDeviceDiscoveryAgentPrivate::onErrorOccured);
+
+ worker = nullptr;
}
QT_END_NAMESPACE
diff --git a/src/bluetooth/qbluetoothdeviceinfo.cpp b/src/bluetooth/qbluetoothdeviceinfo.cpp
index 443902dc..e85149dc 100644
--- a/src/bluetooth/qbluetoothdeviceinfo.cpp
+++ b/src/bluetooth/qbluetoothdeviceinfo.cpp
@@ -1,47 +1,16 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qbluetoothdeviceinfo.h"
#include "qbluetoothdeviceinfo_p.h"
QT_BEGIN_NAMESPACE
+QT_IMPL_METATYPE_EXTERN(QBluetoothDeviceInfo)
+#ifdef QT_WINRT_BLUETOOTH
+QT_IMPL_METATYPE_EXTERN_TAGGED(QBluetoothDeviceInfo::Fields, QBluetoothDeviceInfo__Fields)
+#endif
+
/*!
\class QBluetoothDeviceInfo
\inmodule QtBluetooth
@@ -61,9 +30,6 @@ QT_BEGIN_NAMESPACE
\value MiscellaneousDevice A miscellaneous device.
\value ComputerDevice A computer device or PDA.
\value PhoneDevice A telephone device.
- \value LANAccessDevice A device that provides access to a local area network
- (deprecated since Qt 5.13 and replaced by
- \l QBluetoothDeviceInfo::NetworkDevice).
\value NetworkDevice A device that provides access to a local area network (since Qt 5.13).
\value AudioVideoDevice A device capable of playback or capture of audio and/or video.
\value PeripheralDevice A peripheral device such as a keyboard, mouse, and so on.
@@ -83,6 +49,7 @@ QT_BEGIN_NAMESPACE
\value None None of the values changed.
\value RSSI The \l rssi() value of the device changed.
\value ManufacturerData The \l manufacturerData() field changed
+ \value ServiceData The \l serviceData() field changed
\value All Matches every possible field.
\since 5.12
@@ -253,17 +220,6 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \enum QBluetoothDeviceInfo::DataCompleteness
-
- This enum describes the completeness of the received data.
-
- \value DataComplete The data is complete.
- \value DataIncomplete The data is incomplete. Addition datum is available via other
- interfaces.
- \value DataUnavailable No data is available.
-*/
-
-/*!
\enum QBluetoothDeviceInfo::CoreConfiguration
\since 5.4
@@ -275,17 +231,7 @@ QT_BEGIN_NAMESPACE
for standard and Low Energy device.
\value LowEnergyCoreConfiguration The device is a Bluetooth Low Energy device.
*/
-QBluetoothDeviceInfoPrivate::QBluetoothDeviceInfoPrivate() :
- valid(false),
- cached(false),
- rssi(1),
- serviceClasses(QBluetoothDeviceInfo::NoService),
- majorDeviceClass(QBluetoothDeviceInfo::MiscellaneousDevice),
- minorDeviceClass(0),
-#if QT_DEPRECATED_SINCE(5, 13)
- serviceUuidsCompleteness(QBluetoothDeviceInfo::DataUnavailable),
-#endif
- deviceCoreConfiguration(QBluetoothDeviceInfo::UnknownCoreConfiguration)
+QBluetoothDeviceInfoPrivate::QBluetoothDeviceInfoPrivate()
{
}
@@ -324,10 +270,6 @@ QBluetoothDeviceInfo::QBluetoothDeviceInfo(const QBluetoothAddress &address, con
d->majorDeviceClass = static_cast<MajorDeviceClass>((classOfDevice >> 8) & 0x1f);
d->serviceClasses = static_cast<ServiceClasses>((classOfDevice >> 13) & 0x7ff);
-#if QT_DEPRECATED_SINCE(5, 13)
- d->serviceUuidsCompleteness = DataUnavailable;
-#endif
-
d->valid = true;
d->cached = false;
d->rssi = 0;
@@ -357,10 +299,6 @@ QBluetoothDeviceInfo::QBluetoothDeviceInfo(const QBluetoothUuid &uuid, const QSt
d->majorDeviceClass = static_cast<MajorDeviceClass>((classOfDevice >> 8) & 0x1f);
d->serviceClasses = static_cast<ServiceClasses>((classOfDevice >> 13) & 0x7ff);
-#if QT_DEPRECATED_SINCE(5, 13)
- d->serviceUuidsCompleteness = DataUnavailable;
-#endif
-
d->valid = true;
d->cached = false;
d->rssi = 0;
@@ -426,11 +364,9 @@ QBluetoothDeviceInfo &QBluetoothDeviceInfo::operator=(const QBluetoothDeviceInfo
d->serviceClasses = other.d_func()->serviceClasses;
d->valid = other.d_func()->valid;
d->cached = other.d_func()->cached;
-#if QT_DEPRECATED_SINCE(5, 13)
- d->serviceUuidsCompleteness = other.d_func()->serviceUuidsCompleteness;
-#endif
d->serviceUuids = other.d_func()->serviceUuids;
d->manufacturerData = other.d_func()->manufacturerData;
+ d->serviceData = other.d_func()->serviceData;
d->rssi = other.d_func()->rssi;
d->deviceCoreConfiguration = other.d_func()->deviceCoreConfiguration;
d->deviceUuid = other.d_func()->deviceUuid;
@@ -439,55 +375,54 @@ QBluetoothDeviceInfo &QBluetoothDeviceInfo::operator=(const QBluetoothDeviceInfo
}
/*!
- Returns true if the \a other QBluetoothDeviceInfo object and this are identical.
- */
-bool QBluetoothDeviceInfo::operator==(const QBluetoothDeviceInfo &other) const
-{
- Q_D(const QBluetoothDeviceInfo);
+ \fn bool QBluetoothDeviceInfo::operator==(const QBluetoothDeviceInfo &a, const QBluetoothDeviceInfo &b)
+ \brief Returns \c true if the two QBluetoothDeviceInfo objects \a a and \a b are equal.
+*/
+
+/*!
+ \fn bool QBluetoothDeviceInfo::operator!=(const QBluetoothDeviceInfo &a,
+ const QBluetoothDeviceInfo &b)
+ \brief Returns \c true if the two QBluetoothDeviceInfo objects \a a and \a b are not equal.
+*/
- if (d->cached != other.d_func()->cached)
+/*!
+ \brief Returns true if the \a other QBluetoothDeviceInfo object and this are identical.
+ \internal
+*/
+
+bool QBluetoothDeviceInfo::equals(const QBluetoothDeviceInfo &a, const QBluetoothDeviceInfo &b)
+{
+ if (a.d_func()->cached != b.d_func()->cached)
return false;
- if (d->valid != other.d_func()->valid)
+ if (a.d_func()->valid != b.d_func()->valid)
return false;
- if (d->majorDeviceClass != other.d_func()->majorDeviceClass)
+ if (a.d_func()->majorDeviceClass != b.d_func()->majorDeviceClass)
return false;
- if (d->minorDeviceClass != other.d_func()->minorDeviceClass)
+ if (a.d_func()->minorDeviceClass != b.d_func()->minorDeviceClass)
return false;
- if (d->serviceClasses != other.d_func()->serviceClasses)
+ if (a.d_func()->serviceClasses != b.d_func()->serviceClasses)
return false;
- if (d->name != other.d_func()->name)
+ if (a.d_func()->name != b.d_func()->name)
return false;
- if (d->address != other.d_func()->address)
+ if (a.d_func()->address != b.d_func()->address)
return false;
-#if QT_DEPRECATED_SINCE(5, 13)
- if (d->serviceUuidsCompleteness != other.d_func()->serviceUuidsCompleteness)
+ if (a.d_func()->serviceUuids.size() != b.d_func()->serviceUuids.size())
return false;
-#endif
- if (d->serviceUuids.count() != other.d_func()->serviceUuids.count())
+ if (a.d_func()->serviceUuids != b.d_func()->serviceUuids)
return false;
- if (d->serviceUuids != other.d_func()->serviceUuids)
+ if (a.d_func()->manufacturerData != b.d_func()->manufacturerData)
return false;
- if (d->manufacturerData != other.d_func()->manufacturerData)
+ if (a.d_func()->serviceData != b.d_func()->serviceData)
return false;
- if (d->deviceCoreConfiguration != other.d_func()->deviceCoreConfiguration)
+ if (a.d_func()->deviceCoreConfiguration != b.d_func()->deviceCoreConfiguration)
return false;
- if (d->deviceUuid != other.d_func()->deviceUuid)
+ if (a.d_func()->deviceUuid != b.d_func()->deviceUuid)
return false;
return true;
}
/*!
- Returns true if this object is different from \a other, or false otherwise.
-
- \sa operator==()
-*/
-bool QBluetoothDeviceInfo::operator!=(const QBluetoothDeviceInfo &other) const
-{
- return !(*this == other);
-}
-
-/*!
Returns the address of the device.
\note On iOS and \macos this address is invalid. Instead \l deviceUuid() should be used.
@@ -514,6 +449,18 @@ QString QBluetoothDeviceInfo::name() const
}
/*!
+ Sets the \a name of the device.
+
+ \since 6.2
+ */
+void QBluetoothDeviceInfo::setName(const QString &name)
+{
+ Q_D(QBluetoothDeviceInfo);
+
+ d->name = name;
+}
+
+/*!
Returns the service class of the device.
*/
QBluetoothDeviceInfo::ServiceClasses QBluetoothDeviceInfo::serviceClasses() const
@@ -548,109 +495,41 @@ quint8 QBluetoothDeviceInfo::minorDeviceClass() const
return d->minorDeviceClass;
}
-#if QT_DEPRECATED_SINCE(5, 13)
-/*!
- \deprecated
-
- Sets the list of service UUIDs to \a uuids and the completeness of the data to \a completeness.
-*/
-void QBluetoothDeviceInfo::setServiceUuids(const QList<QBluetoothUuid> &uuids,
- DataCompleteness completeness)
-{
- Q_D(QBluetoothDeviceInfo);
-
- d->serviceUuids = uuids.toVector();
- d->serviceUuidsCompleteness = completeness;
-}
-#endif
-
/*!
Sets the list of service UUIDs to \a uuids.
\since 5.13
*/
-void QBluetoothDeviceInfo::setServiceUuids(const QVector<QBluetoothUuid> &uuids)
+void QBluetoothDeviceInfo::setServiceUuids(const QList<QBluetoothUuid> &uuids)
{
Q_D(QBluetoothDeviceInfo);
d->serviceUuids = uuids;
}
-#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
/*!
- Returns the list of service UUIDS supported by the device. Most commonly this
- list of uuids represents custom uuids or a uuid value specified by
- \l QBluetoothUuid::ServiceClassUuid.
+ Returns the list of service UUIDs supported by the device. Most commonly this
+ list of UUIDs represents custom service UUIDs or a service UUID value specified
+ by \l QBluetoothUuid::ServiceClassUuid.
\sa serviceUuids()
\since 6.0
*/
-QVector<QBluetoothUuid> QBluetoothDeviceInfo::serviceUuids() const
-{
- Q_D(const QBluetoothDeviceInfo);
- return d->serviceUuids;
-}
-
-#elif QT_DEPRECATED_SINCE(5, 13)
-
-/*!
- Returns the list of service UUIDS supported by the device. If \a completeness is not 0 it will
- be set to DataComplete and the complete list of UUIDs supported by the device is returned.
- DataIncomplete if additional service UUIDs are supported by the device and DataUnavailable if
- no service UUID information is available.
-
- This function requires both the Bluetooth devices to support the 2.1 specification.
-*/
-QList<QBluetoothUuid> QBluetoothDeviceInfo::serviceUuids(DataCompleteness *completeness) const
-{
- Q_D(const QBluetoothDeviceInfo);
-
- if (completeness)
- *completeness = d->serviceUuidsCompleteness;
-
- return d->serviceUuids.toList();
-}
-
-#else
-
-/*!
- Returns the list of service UUIDS supported by the device. Most commonly this
- list of uuids represents custom uuids or a uuid value specified by
- \l QBluetoothUuid::ServiceClassUuid.
-*/
QList<QBluetoothUuid> QBluetoothDeviceInfo::serviceUuids() const
{
Q_D(const QBluetoothDeviceInfo);
- return d->serviceUuids.toList();
-}
-
-#endif //QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
-
-#if QT_DEPRECATED_SINCE(5, 13)
-/*!
- \deprecated
-
- Returns the completeness of the service UUID list. If DataComplete is returned,
- serviceUuids() returns the complete list of service UUIDs supported by the device, otherwise
- only the partial or empty list of service UUIDs. To get a list
- of all services supported by the device, a full service discovery needs to be performed.
-*/
-QBluetoothDeviceInfo::DataCompleteness QBluetoothDeviceInfo::serviceUuidsCompleteness() const
-{
- Q_D(const QBluetoothDeviceInfo);
- return d->serviceUuidsCompleteness;
+ return d->serviceUuids;
}
-#endif
/*!
- Returns all manufacturer ids attached to this device information.
+ Returns all manufacturer IDs from advertisement packets attached to this device information.
\sa manufacturerData(), setManufacturerData()
\since 5.12
*/
-QVector<quint16> QBluetoothDeviceInfo::manufacturerIds() const
+QList<quint16> QBluetoothDeviceInfo::manufacturerIds() const
{
Q_D(const QBluetoothDeviceInfo);
- return d->manufacturerData.keys().toVector();
+ return d->manufacturerData.keys().toList();
}
/*!
@@ -695,19 +574,19 @@ QByteArray QBluetoothDeviceInfo::manufacturerData(quint16 manufacturerId) const
bool QBluetoothDeviceInfo::setManufacturerData(quint16 manufacturerId, const QByteArray &data)
{
Q_D(QBluetoothDeviceInfo);
- QHash<quint16, QByteArray>::const_iterator it = d->manufacturerData.find(manufacturerId);
- while (it != d->manufacturerData.end() && it.key() == manufacturerId) {
+ auto it = d->manufacturerData.constFind(manufacturerId);
+ while (it != d->manufacturerData.cend() && it.key() == manufacturerId) {
if (*it == data)
return false;
it++;
}
- d->manufacturerData.insertMulti(manufacturerId, data);
+ d->manufacturerData.insert(manufacturerId, data);
return true;
}
/*!
- Returns the complete set of all manufacturer data.
+ Returns the complete set of all manufacturer data from advertisement packets.
Some devices may provide multiple manufacturer data entries per manufacturer ID.
An example might be a Bluetooth Low Energy device that sends a different manufacturer data via
@@ -717,13 +596,87 @@ bool QBluetoothDeviceInfo::setManufacturerData(quint16 manufacturerId, const QBy
\sa setManufacturerData
\since 5.12
*/
-QHash<quint16, QByteArray> QBluetoothDeviceInfo::manufacturerData() const
+QMultiHash<quint16, QByteArray> QBluetoothDeviceInfo::manufacturerData() const
{
Q_D(const QBluetoothDeviceInfo);
return d->manufacturerData;
}
/*!
+ Returns all service data IDs from advertisement packets attached to this device information.
+
+ \sa serviceData(), setServiceData()
+ \since 6.3
+ */
+QList<QBluetoothUuid> QBluetoothDeviceInfo::serviceIds() const
+{
+ Q_D(const QBluetoothDeviceInfo);
+ return d->serviceData.keys().toList();
+}
+
+/*!
+ Returns the data associated with the given \a serviceId.
+
+ Service data is defined by
+ the Supplement to the Bluetooth Core Specification and consists of two segments:
+
+ \list
+ \li Service UUID
+ \li Sequence of arbitrary data octets
+ \endlist
+
+ \note The remote device may provide multiple data entries per \a serviceId.
+ This function only returns the first entry. If all entries are needed use
+ \l serviceData() which returns a multi hash.
+
+ \sa serviceIds(), setServiceData()
+ \since 6.3
+ */
+QByteArray QBluetoothDeviceInfo::serviceData(const QBluetoothUuid &serviceId) const
+{
+ Q_D(const QBluetoothDeviceInfo);
+ return d->serviceData.value(serviceId);
+}
+
+/*!
+ Sets the advertised service \a data for the given \a serviceId.
+ Returns \c true if it was inserted, \c false if it was already known.
+
+ \sa serviceData
+ \since 6.3
+*/
+bool QBluetoothDeviceInfo::setServiceData(const QBluetoothUuid &serviceId, const QByteArray &data)
+{
+ Q_D(QBluetoothDeviceInfo);
+ auto it = d->serviceData.constFind(serviceId);
+ while (it != d->serviceData.cend() && it.key() == serviceId) {
+ if (*it == data)
+ return false;
+ it++;
+ }
+
+ d->serviceData.insert(serviceId, data);
+ return true;
+}
+
+/*!
+ Returns the complete set of all service data from advertisement packets.
+
+ Some devices may provide multiple service data entries per service data ID.
+ An example might be a Bluetooth Low Energy device that sends a different service data via
+ advertisement packets and scan response packets respectively. Therefore the returned hash table
+ may have multiple entries per service data ID or hash key.
+
+ \sa setServiceData
+ \since 6.3
+*/
+QMultiHash<QBluetoothUuid, QByteArray> QBluetoothDeviceInfo::serviceData() const
+{
+ Q_D(const QBluetoothDeviceInfo);
+ return d->serviceData;
+}
+
+/*!
Sets the CoreConfigurations of the device to \a coreConfigs. This will help to make a difference
between regular and Low Energy devices.
diff --git a/src/bluetooth/qbluetoothdeviceinfo.h b/src/bluetooth/qbluetoothdeviceinfo.h
index c4fa01ec..fd8fd50f 100644
--- a/src/bluetooth/qbluetoothdeviceinfo.h
+++ b/src/bluetooth/qbluetoothdeviceinfo.h
@@ -1,51 +1,16 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QBLUETOOTHDEVICEINFO_H
#define QBLUETOOTHDEVICEINFO_H
#include <QtBluetooth/qtbluetoothglobal.h>
+#include <QtBluetooth/QBluetoothUuid>
-#include <QtCore/qstring.h>
-#include <QtCore/qmetatype.h>
#include <QtCore/qbytearray.h>
-#include <QtCore/qvector.h>
+#include <QtCore/qlist.h>
+#include <QtCore/qmetatype.h>
+#include <QtCore/qstring.h>
QT_BEGIN_NAMESPACE
@@ -60,9 +25,6 @@ public:
MiscellaneousDevice = 0,
ComputerDevice = 1,
PhoneDevice = 2,
-#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
- LANAccessDevice = 3,
-#endif
NetworkDevice = 3,
AudioVideoDevice = 4,
PeripheralDevice = 5,
@@ -194,19 +156,11 @@ public:
};
Q_DECLARE_FLAGS(ServiceClasses, ServiceClass)
-#if QT_DEPRECATED_SINCE(5, 13)
- // adding QT_DEPRECATED causes compile failure with gcc 7
- enum DataCompleteness {
- DataComplete,
- DataIncomplete,
- DataUnavailable
- };
-#endif
-
enum class Field {
None = 0x0000,
RSSI = 0x0001,
ManufacturerData = 0x0002,
+ ServiceData = 0x0004,
All = 0x7fff
};
Q_DECLARE_FLAGS(Fields, Field)
@@ -233,11 +187,18 @@ public:
void setCached(bool cached);
QBluetoothDeviceInfo &operator=(const QBluetoothDeviceInfo &other);
- bool operator==(const QBluetoothDeviceInfo &other) const;
- bool operator!=(const QBluetoothDeviceInfo &other) const;
+ friend bool operator==(const QBluetoothDeviceInfo &a, const QBluetoothDeviceInfo &b)
+ {
+ return equals(a, b);
+ }
+ friend bool operator!=(const QBluetoothDeviceInfo &a, const QBluetoothDeviceInfo &b)
+ {
+ return !equals(a, b);
+ }
QBluetoothAddress address() const;
QString name() const;
+ void setName(const QString &name);
ServiceClasses serviceClasses() const;
MajorDeviceClass majorDeviceClass() const;
@@ -246,30 +207,18 @@ public:
qint16 rssi() const;
void setRssi(qint16 signal);
-#if QT_DEPRECATED_SINCE(5, 13)
- QT_DEPRECATED void setServiceUuids(const QList<QBluetoothUuid> &uuids, DataCompleteness completeness);
- QT_DEPRECATED DataCompleteness serviceUuidsCompleteness() const;
-#endif
-
-#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
-#ifndef Q_QDOC //suppress qdoc warnings
- QVector<QBluetoothUuid> serviceUuids() const;
-#endif // Q_QDOC
-#elif QT_DEPRECATED_SINCE(5, 13)
- QList<QBluetoothUuid> serviceUuids(DataCompleteness *completeness = nullptr) const;
-#else
QList<QBluetoothUuid> serviceUuids() const;
-#endif
- void setServiceUuids(const QVector<QBluetoothUuid> &uuids);
+ void setServiceUuids(const QList<QBluetoothUuid> &uuids);
- // TODO Qt6 manufacturerData()
- // manufacturerData() and manufacturerData(quint16) return types should be modified to
- // cope with multiple data entires per manufacturer ID. QHash<quint16, QByteArray>
- // may stay though if it retains insertMulti() in Qt 6.
- QVector<quint16> manufacturerIds() const;
+ QList<quint16> manufacturerIds() const;
QByteArray manufacturerData(quint16 manufacturerId) const;
bool setManufacturerData(quint16 manufacturerId, const QByteArray &data);
- QHash<quint16, QByteArray> manufacturerData() const;
+ QMultiHash<quint16, QByteArray> manufacturerData() const;
+
+ QList<QBluetoothUuid> serviceIds() const;
+ QByteArray serviceData(const QBluetoothUuid &serviceId) const;
+ bool setServiceData(const QBluetoothUuid &serviceId, const QByteArray &data);
+ QMultiHash<QBluetoothUuid, QByteArray> serviceData() const;
void setCoreConfigurations(QBluetoothDeviceInfo::CoreConfigurations coreConfigs);
QBluetoothDeviceInfo::CoreConfigurations coreConfigurations() const;
@@ -281,6 +230,7 @@ protected:
QBluetoothDeviceInfoPrivate *d_ptr;
private:
+ static bool equals(const QBluetoothDeviceInfo &a, const QBluetoothDeviceInfo &b);
Q_DECLARE_PRIVATE(QBluetoothDeviceInfo)
};
@@ -289,9 +239,10 @@ Q_DECLARE_OPERATORS_FOR_FLAGS(QBluetoothDeviceInfo::ServiceClasses)
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(QBluetoothDeviceInfo)
+QT_DECL_METATYPE_EXTERN(QBluetoothDeviceInfo, Q_BLUETOOTH_EXPORT)
#ifdef QT_WINRT_BLUETOOTH
-Q_DECLARE_METATYPE(QBluetoothDeviceInfo::Fields)
+QT_DECL_METATYPE_EXTERN_TAGGED(QBluetoothDeviceInfo::Fields, QBluetoothDeviceInfo__Fields,
+ Q_BLUETOOTH_EXPORT)
#endif
#endif
diff --git a/src/bluetooth/qbluetoothdeviceinfo_p.h b/src/bluetooth/qbluetoothdeviceinfo_p.h
index 80fd1472..ba527b22 100644
--- a/src/bluetooth/qbluetoothdeviceinfo_p.h
+++ b/src/bluetooth/qbluetoothdeviceinfo_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QBLUETOOTHDEVICEINFO_P_H
#define QBLUETOOTHDEVICEINFO_P_H
@@ -57,6 +21,7 @@
#include <QString>
#include <QtCore/qhash.h>
+#include <QtCore/private/qglobal_p.h>
QT_BEGIN_NAMESPACE
@@ -65,24 +30,21 @@ class QBluetoothDeviceInfoPrivate
public:
QBluetoothDeviceInfoPrivate();
- bool valid;
- bool cached;
+ bool valid = false;
+ bool cached = false;
+ qint16 rssi = 1;
+ quint8 minorDeviceClass = 0;
QBluetoothAddress address;
QString name;
+ QBluetoothDeviceInfo::MajorDeviceClass majorDeviceClass = QBluetoothDeviceInfo::MiscellaneousDevice;
- qint16 rssi;
+ QBluetoothDeviceInfo::ServiceClasses serviceClasses = QBluetoothDeviceInfo::NoService;
- QBluetoothDeviceInfo::ServiceClasses serviceClasses;
- QBluetoothDeviceInfo::MajorDeviceClass majorDeviceClass;
- quint8 minorDeviceClass;
-
-#if QT_DEPRECATED_SINCE(5, 13)
- QBluetoothDeviceInfo::DataCompleteness serviceUuidsCompleteness;
-#endif
- QVector<QBluetoothUuid> serviceUuids;
- QHash<quint16, QByteArray> manufacturerData;
- QBluetoothDeviceInfo::CoreConfigurations deviceCoreConfiguration;
+ QList<QBluetoothUuid> serviceUuids;
+ QMultiHash<quint16, QByteArray> manufacturerData;
+ QMultiHash<QBluetoothUuid, QByteArray> serviceData;
+ QBluetoothDeviceInfo::CoreConfigurations deviceCoreConfiguration = QBluetoothDeviceInfo::UnknownCoreConfiguration;
QBluetoothUuid deviceUuid;
};
diff --git a/src/bluetooth/qbluetoothdevicewatcher_winrt.cpp b/src/bluetooth/qbluetoothdevicewatcher_winrt.cpp
new file mode 100644
index 00000000..fd69ee77
--- /dev/null
+++ b/src/bluetooth/qbluetoothdevicewatcher_winrt.cpp
@@ -0,0 +1,105 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qbluetoothdevicewatcher_winrt_p.h"
+
+#include <winrt/Windows.Foundation.Collections.h>
+
+using namespace winrt::Windows::Foundation;
+using namespace winrt::Windows::Devices::Enumeration;
+
+QT_BEGIN_NAMESPACE
+
+QBluetoothDeviceWatcherWinRT::QBluetoothDeviceWatcherWinRT(int id, winrt::hstring selector)
+ : m_id(id),
+ m_watcher(DeviceInformation::CreateWatcher(selector))
+{
+ qRegisterMetaType<winrt::hstring>("winrt::hstring");
+}
+
+QBluetoothDeviceWatcherWinRT::QBluetoothDeviceWatcherWinRT(int id, winrt::hstring selector,
+ winrt::Windows::Devices::Enumeration::DeviceInformationKind kind)
+ : m_id(id)
+{
+ qRegisterMetaType<winrt::hstring>("winrt::hstring");
+ const winrt::param::iterable<winrt::hstring> extra {};
+ m_watcher = DeviceInformation::CreateWatcher(selector, extra, kind);
+}
+
+QBluetoothDeviceWatcherWinRT::~QBluetoothDeviceWatcherWinRT()
+{
+ stop();
+}
+
+bool QBluetoothDeviceWatcherWinRT::init()
+{
+ if (!m_watcher) {
+ qWarning("Windows failed to create an instance of DeviceWatcher. "
+ "Detection of Bluetooth devices might not work correctly.");
+ return false;
+ }
+ return true;
+}
+
+void QBluetoothDeviceWatcherWinRT::start()
+{
+ if (m_watcher) {
+ subscribeToEvents();
+ m_watcher.Start();
+ }
+}
+
+void QBluetoothDeviceWatcherWinRT::stop()
+{
+ if (m_watcher && canStop()) {
+ unsubscribeFromEvents();
+ m_watcher.Stop();
+ }
+}
+
+void QBluetoothDeviceWatcherWinRT::subscribeToEvents()
+{
+ Q_ASSERT(m_watcher.Status() == DeviceWatcherStatus::Created);
+ // The callbacks are triggered from separate threads. So we capture
+ // thisPtr to make sure that the object is valid.
+ auto thisPtr = shared_from_this();
+ m_addedToken = m_watcher.Added([thisPtr](DeviceWatcher, const DeviceInformation &info) {
+ emit thisPtr->deviceAdded(info.Id(), thisPtr->m_id);
+ });
+ m_removedToken =
+ m_watcher.Removed([thisPtr](DeviceWatcher, const DeviceInformationUpdate &upd) {
+ emit thisPtr->deviceRemoved(upd.Id(), thisPtr->m_id);
+ });
+ m_updatedToken =
+ m_watcher.Updated([thisPtr](DeviceWatcher, const DeviceInformationUpdate &upd) {
+ emit thisPtr->deviceUpdated(upd.Id(), thisPtr->m_id);
+ });
+ // because of ambiguous declaration
+ using WinRtInspectable = winrt::Windows::Foundation::IInspectable;
+ m_enumerationToken =
+ m_watcher.EnumerationCompleted([thisPtr](DeviceWatcher, const WinRtInspectable &) {
+ emit thisPtr->enumerationCompleted(thisPtr->m_id);
+ });
+ m_stoppedToken = m_watcher.Stopped([thisPtr](DeviceWatcher, const WinRtInspectable &) {
+ emit thisPtr->watcherStopped(thisPtr->m_id);
+ });
+}
+
+void QBluetoothDeviceWatcherWinRT::unsubscribeFromEvents()
+{
+ m_watcher.Added(m_addedToken);
+ m_watcher.Removed(m_removedToken);
+ m_watcher.Updated(m_updatedToken);
+ m_watcher.EnumerationCompleted(m_enumerationToken);
+ m_watcher.Stopped(m_stoppedToken);
+}
+
+bool QBluetoothDeviceWatcherWinRT::canStop() const
+{
+ const auto status = m_watcher.Status();
+ // Also 'Aborted', but calling Stop() there is a no-op
+ return status == DeviceWatcherStatus::Started
+ || status == DeviceWatcherStatus::EnumerationCompleted;
+}
+
+QT_END_NAMESPACE
diff --git a/src/bluetooth/qbluetoothdevicewatcher_winrt_p.h b/src/bluetooth/qbluetoothdevicewatcher_winrt_p.h
new file mode 100644
index 00000000..74f56357
--- /dev/null
+++ b/src/bluetooth/qbluetoothdevicewatcher_winrt_p.h
@@ -0,0 +1,69 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QBLUETOOTHDEVICEWATCHER_WINRT_P_H
+#define QBLUETOOTHDEVICEWATCHER_WINRT_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/private/qglobal_p.h>
+#include <QtCore/QObject>
+
+#include <private/qbluetoothutils_winrt_p.h>
+
+#include <winrt/base.h>
+#include <QtCore/private/qfactorycacheregistration_p.h>
+#include <winrt/Windows.Devices.Enumeration.h>
+
+QT_BEGIN_NAMESPACE
+
+class QBluetoothDeviceWatcherWinRT : public QObject,
+ public std::enable_shared_from_this<QBluetoothDeviceWatcherWinRT>
+{
+ Q_OBJECT
+public:
+ QBluetoothDeviceWatcherWinRT(int id, winrt::hstring selector);
+ QBluetoothDeviceWatcherWinRT(int id, winrt::hstring selector,
+ winrt::Windows::Devices::Enumeration::DeviceInformationKind kind);
+ ~QBluetoothDeviceWatcherWinRT();
+
+ bool init();
+ void start();
+ void stop();
+
+signals:
+ // The signals will be emitted from a separate thread,
+ // so we need to use Qt::QueuedConnection
+ void deviceAdded(winrt::hstring deviceId, int id);
+ void deviceRemoved(winrt::hstring deviceId, int id);
+ void deviceUpdated(winrt::hstring deviceId, int id);
+ void enumerationCompleted(int id);
+ void watcherStopped(int id);
+
+private:
+ void subscribeToEvents();
+ void unsubscribeFromEvents();
+ bool canStop() const;
+
+ const int m_id; // used to uniquely identify the wrapper
+ winrt::Windows::Devices::Enumeration::DeviceWatcher m_watcher = nullptr;
+
+ winrt::event_token m_addedToken;
+ winrt::event_token m_removedToken;
+ winrt::event_token m_updatedToken;
+ winrt::event_token m_enumerationToken;
+ winrt::event_token m_stoppedToken;
+};
+
+QT_END_NAMESPACE
+
+#endif // QBLUETOOTHDEVICEWATCHER_WINRT_P_H
diff --git a/src/bluetooth/qbluetoothhostinfo.cpp b/src/bluetooth/qbluetoothhostinfo.cpp
index ca48fd23..a720a0fb 100644
--- a/src/bluetooth/qbluetoothhostinfo.cpp
+++ b/src/bluetooth/qbluetoothhostinfo.cpp
@@ -1,47 +1,13 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qbluetoothhostinfo.h"
#include "qbluetoothhostinfo_p.h"
QT_BEGIN_NAMESPACE
+QT_IMPL_METATYPE_EXTERN(QBluetoothHostInfo)
+
/*!
\class QBluetoothHostInfo
\inmodule QtBluetooth
@@ -95,26 +61,27 @@ QBluetoothHostInfo &QBluetoothHostInfo::operator=(const QBluetoothHostInfo &othe
}
/*!
- \since 5.5
-
- Returns true if \a other is equal to this QBluetoothHostInfo, otherwise false.
+ \fn bool QBluetoothHostInfo::operator==(const QBluetoothHostInfo &a,
+ const QBluetoothHostInfo &b)
+ \brief Returns \c true if \a a and \a b are equal, otherwise \c false.
*/
-bool QBluetoothHostInfo::operator==(const QBluetoothHostInfo &other) const
-{
- if (d_ptr == other.d_ptr)
- return true;
-
- return d_ptr->m_address == other.d_ptr->m_address && d_ptr->m_name == other.d_ptr->m_name;
-}
/*!
- \since 5.5
+ \fn bool QBluetoothHostInfo::operator!=(const QBluetoothHostInfo &a,
+ const QBluetoothHostInfo &b)
+ \brief Returns \c true if \a a and \a b are not equal, otherwise \c false.
+*/
- Returns true if \a other is not equal to this QBluetoothHostInfo, otherwise false.
+/*!
+ \brief Returns \c true if \a a and \a b are equal, otherwise \c false.
+ \internal
*/
-bool QBluetoothHostInfo::operator!=(const QBluetoothHostInfo &other) const
+bool QBluetoothHostInfo::equals(const QBluetoothHostInfo &a, const QBluetoothHostInfo &b)
{
- return !operator==(other);
+ if (a.d_ptr == b.d_ptr)
+ return true;
+
+ return a.d_ptr->m_address == b.d_ptr->m_address && a.d_ptr->m_name == b.d_ptr->m_name;
}
/*!
diff --git a/src/bluetooth/qbluetoothhostinfo.h b/src/bluetooth/qbluetoothhostinfo.h
index 42dfcaab..7090cedb 100644
--- a/src/bluetooth/qbluetoothhostinfo.h
+++ b/src/bluetooth/qbluetoothhostinfo.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QBLUETOOTHHOSTINFO_H
#define QBLUETOOTHHOSTINFO_H
@@ -54,9 +18,14 @@ public:
~QBluetoothHostInfo();
QBluetoothHostInfo &operator=(const QBluetoothHostInfo &other);
-
- bool operator==(const QBluetoothHostInfo &other) const;
- bool operator!=(const QBluetoothHostInfo &other) const;
+ friend bool operator==(const QBluetoothHostInfo &a, const QBluetoothHostInfo &b)
+ {
+ return equals(a, b);
+ }
+ friend bool operator!=(const QBluetoothHostInfo &a, const QBluetoothHostInfo &b)
+ {
+ return !equals(a, b);
+ }
QBluetoothAddress address() const;
void setAddress(const QBluetoothAddress &address);
@@ -65,12 +34,13 @@ public:
void setName(const QString &name);
private:
+ static bool equals(const QBluetoothHostInfo &a, const QBluetoothHostInfo &b);
Q_DECLARE_PRIVATE(QBluetoothHostInfo)
QBluetoothHostInfoPrivate *d_ptr;
};
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(QBluetoothHostInfo)
+QT_DECL_METATYPE_EXTERN(QBluetoothHostInfo, Q_BLUETOOTH_EXPORT)
#endif
diff --git a/src/bluetooth/qbluetoothhostinfo_p.h b/src/bluetooth/qbluetoothhostinfo_p.h
index 677fb552..8e957138 100644
--- a/src/bluetooth/qbluetoothhostinfo_p.h
+++ b/src/bluetooth/qbluetoothhostinfo_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QBLUETOOTHHOSTINFO_P_H
#define QBLUETOOTHHOSTINFO_P_H
@@ -52,6 +16,7 @@
//
#include "qbluetoothhostinfo.h"
+#include "private/qglobal_p.h"
QT_BEGIN_NAMESPACE
diff --git a/src/bluetooth/qbluetoothlocaldevice.cpp b/src/bluetooth/qbluetoothlocaldevice.cpp
index 38dd56f4..a94b80eb 100644
--- a/src/bluetooth/qbluetoothlocaldevice.cpp
+++ b/src/bluetooth/qbluetoothlocaldevice.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qbluetoothlocaldevice.h"
#include "qbluetoothlocaldevice_p.h"
@@ -45,6 +9,10 @@
QT_BEGIN_NAMESPACE
+QT_IMPL_METATYPE_EXTERN_TAGGED(QBluetoothLocalDevice::Pairing, QBluetoothLocalDevice__Pairing)
+QT_IMPL_METATYPE_EXTERN_TAGGED(QBluetoothLocalDevice::HostMode, QBluetoothLocalDevice__HostMode)
+QT_IMPL_METATYPE_EXTERN_TAGGED(QBluetoothLocalDevice::Error, QBluetoothLocalDevice__Error)
+
/*!
\class QBluetoothLocalDevice
\inmodule QtBluetooth
@@ -56,7 +24,7 @@ QT_BEGIN_NAMESPACE
QBluetoothLocalDevice provides functions for getting and setting the state of local Bluetooth
devices.
- On iOS and Windows, this class cannot be used because the platform does not expose
+ On iOS, this class cannot be used because the platform does not expose
any data or API which may provide information on the local Bluetooth device.
*/
@@ -81,6 +49,9 @@ QT_BEGIN_NAMESPACE
\value NoError No known error
\value PairingError Error in pairing
+ \value [since 6.4] MissingPermissionsError The operating system requests
+ permissions which were not
+ granted by the user.
\value UnknownError Unknown error
*/
@@ -102,7 +73,23 @@ QT_BEGIN_NAMESPACE
only made discoverable for a limited period of time. This can speed up discovery between gaming devices,
as service discovery can be skipped on devices not in LimitedInquiry mode. In this mode, the device will
be connectable and powered on, if required. This mode is is not supported on Android.
- On \macos, it is not possible to set the \l hostMode() to HostConnectable or HostPoweredOff.
+
+ \note On \macos, it is not possible to set the \l hostMode() to
+ HostConnectable or HostPoweredOff.
+
+ \note On Windows, it is not possible to set the \l hostMode() to
+ HostDiscoverable or HostDiscoverableLimitedInquiry. Using these modes is
+ equivalent to HostConnectable.
+
+ \note Starting from Android 13 (API level 33) the HostPoweredOff state relies on
+ non-public Android API as the public one has been deprecated, see
+ (\l {https://developer.android.com/reference/android/bluetooth/BluetoothAdapter#disable()}
+ {disable()}). This may change in a future version of Android.
+
+ \note At least on Android 12 the device's Bluetooth visibility setting may dictate the result
+ of setting either HostDiscoverable or HostConnectable. For example if the visibility is set
+ \e off, it may not be possible to enter the HostDiscoverable mode, but HostConnectable will be
+ used instead. This may change in future version of Android.
*/
@@ -137,6 +124,13 @@ QBluetoothLocalDevice::~QBluetoothLocalDevice()
remains invalid even if the same Bluetooth adapter is returned to
the system.
+//! [android-permissions-valid]
+ \note Starting from Android 12 (API level 31), the construction of this class requires
+ \l {https://developer.android.com/guide/topics/connectivity/bluetooth/permissions}
+ {bluetooth runtime permissions} (\e BLUETOOTH_SCAN and \e BLUETOOTH_CONNECT). If the
+ permissions are not granted, the device will not be valid.
+//! [android-permissions-valid]
+
\sa allDevices()
*/
bool QBluetoothLocalDevice::isValid() const
@@ -153,11 +147,18 @@ bool QBluetoothLocalDevice::isValid() const
Sets the host mode of this local Bluetooth device to \a mode.
+ Some transitions such as turning the device on or off may take some time. Therefore
+ subsequent calls should only be made once the \l hostModeStateChanged() signal
+ has concluded the previous request. If this is ignored the result of such a series
+ of calls is not well defined.
+
\note Due to varying security policies on the supported platforms, this method may have
differing behaviors on the various platforms. For example the system may ask the user for
confirmation before turning Bluetooth on or off and not all host modes may be supported.
On \macos, it is not possbile to programmatically change the \l hostMode().
A user can only switch Bluetooth on/off in the System Preferences.
+ On Windows this method \e must be called from the UI thread because it might
+ require user confirmation.
Please refer to the platform specific Bluetooth documentation for details.
*/
@@ -206,6 +207,9 @@ bool QBluetoothLocalDevice::isValid() const
/*!
\fn QBluetoothLocalDevice::QBluetoothLocalDevice(QObject *parent)
Constructs a QBluetoothLocalDevice with \a parent.
+
+ \include qbluetoothlocaldevice.cpp android-permissions-valid
+ \sa isValid()
*/
/*!
@@ -256,47 +260,12 @@ bool QBluetoothLocalDevice::isValid() const
*/
/*!
- \fn QBluetoothLocalDevice::pairingDisplayConfirmation(const QBluetoothAddress &address, QString pin)
-
- Signal by some platforms to display a pairing confirmation dialog for \a address. The user
- is asked to confirm the \a pin is the same on both devices. The \l pairingConfirmation() function
- must be called to indicate if the user accepts or rejects the displayed pin.
-
- This signal is only emitted for pairing requests issues by calling \l requestPairing().
- On \macos, this method never gets called - there is a callback with a PIN (IOBluetooth),
- but it expects immediate reply yes/no - and there is no time to show any dialog or compare PINs.
-
- \sa pairingConfirmation()
-*/
-
-/*!
- \fn QBluetoothLocalDevice::pairingConfirmation(bool confirmation)
-
- To be called after getting a pairingDisplayConfirmation(). The \a confirmation parameter either
- accepts the pairing or rejects it.
-
- Accepting a pairing always refers to the last pairing request issued via \l requestPairing().
-
- \note This function requires BLUETOOTH_PRIVILEGED permission on Android which is generally not
- obtainable for 3rdparty. Android's default handler for pairing requests will do this on behalf
- of the user and the application can ignore this call. Nevertheless the proper Android calls are made
- in case the application does have the required permissions.
-*/
-
-/*!
- \fn QBluetoothLocalDevice::pairingDisplayPinCode(const QBluetoothAddress &address, QString pin)
-
- Signal by some platforms to display the \a pin to the user for \a address. The pin is automatically
- generated, and does not need to be confirmed.
-
- This signal is only emitted for pairing requests issues by calling \l requestPairing().
-*/
-
-/*!
\fn QBluetoothLocalDevice::requestPairing(const QBluetoothAddress &address, Pairing pairing)
Set the \a pairing status with \a address. The results are returned by the signal, pairingFinished().
+
On Android and \macos, AuthorizedPaired is not possible and will have the same behavior as Paired.
+ On Windows the exact pairing mode decision is up to the operating system.
On \macos, it is not possible to unpair a device. If Unpaired is requested, \l pairingFinished()
is immediately emitted although the device remains paired. It is possible to request the pairing
@@ -306,17 +275,21 @@ bool QBluetoothLocalDevice::isValid() const
*/
/*!
- \fn QBluetoothLocalDevice::pairingFinished(const QBluetoothAddress &address, QBluetoothLocalDevice::Pairing pairing)
+ \fn QBluetoothLocalDevice::pairingFinished(const QBluetoothAddress &address,
+ QBluetoothLocalDevice::Pairing pairing)
Pairing or unpairing has completed with \a address. Current pairing status is in \a pairing.
- If the pairing request was not successful, this signal will not be emitted. The error() signal
- is emitted if the pairing request failed. The signal is only ever emitted for pairing requests
- which have previously requested by calling \l requestPairing() of the current object instance.
+ If the pairing request was not successful, this signal will not be emitted. The errorOccurred()
+ signal is emitted if the pairing request failed. The signal is only ever emitted for pairing
+ requests which have previously requested by calling \l requestPairing() of the current object
+ instance.
*/
/*!
- \fn QBluetoothLocalDevice::error(QBluetoothLocalDevice::Error error)
+ \fn QBluetoothLocalDevice::errorOccurred(QBluetoothLocalDevice::Error error)
Signal emitted if there's an exceptional \a error while pairing.
+
+ \since 6.2
*/
/*!
@@ -324,6 +297,9 @@ bool QBluetoothLocalDevice::isValid() const
Construct new QBluetoothLocalDevice for \a address. If \a address is default constructed
the resulting local device selects the local default device.
+
+ \include qbluetoothlocaldevice.cpp android-permissions-valid
+ \sa isValid()
*/
QT_END_NAMESPACE
diff --git a/src/bluetooth/qbluetoothlocaldevice.h b/src/bluetooth/qbluetoothlocaldevice.h
index 9f6d1e1b..298df950 100644
--- a/src/bluetooth/qbluetoothlocaldevice.h
+++ b/src/bluetooth/qbluetoothlocaldevice.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QBLUETOOTHLOCALDEVICE_H
#define QBLUETOOTHLOCALDEVICE_H
@@ -75,6 +39,7 @@ public:
enum Error {
NoError,
PairingError,
+ MissingPermissionsError,
UnknownError = 100
};
Q_ENUM(Error)
@@ -99,18 +64,13 @@ public:
static QList<QBluetoothHostInfo> allDevices();
-public Q_SLOTS:
- void pairingConfirmation(bool confirmation);
-
Q_SIGNALS:
void hostModeStateChanged(QBluetoothLocalDevice::HostMode state);
void deviceConnected(const QBluetoothAddress &address);
void deviceDisconnected(const QBluetoothAddress &address);
void pairingFinished(const QBluetoothAddress &address, QBluetoothLocalDevice::Pairing pairing);
- void pairingDisplayPinCode(const QBluetoothAddress &address, QString pin);
- void pairingDisplayConfirmation(const QBluetoothAddress &address, QString pin);
- void error(QBluetoothLocalDevice::Error error);
+ void errorOccurred(QBluetoothLocalDevice::Error error);
private:
Q_DECLARE_PRIVATE(QBluetoothLocalDevice)
@@ -119,8 +79,11 @@ private:
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(QBluetoothLocalDevice::Pairing)
-Q_DECLARE_METATYPE(QBluetoothLocalDevice::HostMode)
-Q_DECLARE_METATYPE(QBluetoothLocalDevice::Error)
+QT_DECL_METATYPE_EXTERN_TAGGED(QBluetoothLocalDevice::Pairing, QBluetoothLocalDevice__Pairing,
+ Q_BLUETOOTH_EXPORT)
+QT_DECL_METATYPE_EXTERN_TAGGED(QBluetoothLocalDevice::HostMode, QBluetoothLocalDevice__HostMode,
+ Q_BLUETOOTH_EXPORT)
+QT_DECL_METATYPE_EXTERN_TAGGED(QBluetoothLocalDevice::Error, QBluetoothLocalDevice__Error,
+ Q_BLUETOOTH_EXPORT)
#endif // QBLUETOOTHLOCALDEVICE_H
diff --git a/src/bluetooth/qbluetoothlocaldevice_android.cpp b/src/bluetooth/qbluetoothlocaldevice_android.cpp
index 2995d368..9dffeb8e 100644
--- a/src/bluetooth/qbluetoothlocaldevice_android.cpp
+++ b/src/bluetooth/qbluetoothlocaldevice_android.cpp
@@ -1,53 +1,18 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Lauri Laanmets (Proekspert AS) <lauri.laanmets@eesti.ee>
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 Lauri Laanmets (Proekspert AS) <lauri.laanmets@eesti.ee>
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+#include "qbluetoothlocaldevice_p.h"
+#include "android/localdevicebroadcastreceiver_p.h"
+#include "android/androidutils_p.h"
+#include "android/jni_android_p.h"
+#include <QCoreApplication>
#include <QtCore/QLoggingCategory>
-#include <QtCore/private/qjnihelpers_p.h>
-#include <QtAndroidExtras/QAndroidJniEnvironment>
-#include <QtAndroidExtras/QAndroidJniObject>
+#include <QtCore/QJniEnvironment>
+#include <QtCore/QJniObject>
#include <QtBluetooth/QBluetoothLocalDevice>
#include <QtBluetooth/QBluetoothAddress>
-#include "qbluetoothlocaldevice_p.h"
-#include "android/localdevicebroadcastreceiver_p.h"
-
QT_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(QT_BT_ANDROID)
@@ -67,8 +32,6 @@ QBluetoothLocalDevicePrivate::QBluetoothLocalDevicePrivate(
this, &QBluetoothLocalDevicePrivate::processPairingStateChanged);
connect(receiver, &LocalDeviceBroadcastReceiver::connectDeviceChanges,
this, &QBluetoothLocalDevicePrivate::processConnectDeviceChanges);
- connect(receiver, &LocalDeviceBroadcastReceiver::pairingDisplayConfirmation,
- this, &QBluetoothLocalDevicePrivate::processDisplayConfirmation);
}
QBluetoothLocalDevicePrivate::~QBluetoothLocalDevicePrivate()
@@ -78,42 +41,28 @@ QBluetoothLocalDevicePrivate::~QBluetoothLocalDevicePrivate()
delete obj;
}
-QAndroidJniObject *QBluetoothLocalDevicePrivate::adapter()
+QJniObject *QBluetoothLocalDevicePrivate::adapter()
{
return obj;
}
-static QAndroidJniObject getDefaultAdapter()
-{
- QAndroidJniObject adapter = QAndroidJniObject::callStaticObjectMethod(
- "android/bluetooth/BluetoothAdapter", "getDefaultAdapter",
- "()Landroid/bluetooth/BluetoothAdapter;");
- QAndroidJniExceptionCleaner exCleaner{QAndroidJniExceptionCleaner::OutputMode::Verbose};
- if (!adapter.isValid()) {
- exCleaner.clean();
-
- // workaround stupid bt implementations where first call of BluetoothAdapter.getDefaultAdapter() always fails
- adapter = QAndroidJniObject::callStaticObjectMethod(
- "android/bluetooth/BluetoothAdapter", "getDefaultAdapter",
- "()Landroid/bluetooth/BluetoothAdapter;");
- if (!adapter.isValid())
- exCleaner.clean();
- }
- return adapter;
-}
-
void QBluetoothLocalDevicePrivate::initialize(const QBluetoothAddress &address)
{
- QAndroidJniObject adapter = getDefaultAdapter();
+ QJniObject adapter = getDefaultBluetoothAdapter();
+
if (!adapter.isValid()) {
qCWarning(QT_BT_ANDROID) << "Device does not support Bluetooth";
return;
}
- obj = new QAndroidJniObject(adapter);
+ if (!ensureAndroidPermission(QBluetoothPermission::Access)) {
+ qCWarning(QT_BT_ANDROID) << "Local device initialize() failed due to missing permissions";
+ return;
+ }
+
+ obj = new QJniObject(adapter);
if (!address.isNull()) {
- const QString localAddress
- = obj->callObjectMethod("getAddress", "()Ljava/lang/String;").toString();
+ const QString localAddress = obj->callMethod<jstring>("getAddress").toString();
if (localAddress != address.toString()) {
// passed address not local one -> invalid
delete obj;
@@ -129,26 +78,33 @@ bool QBluetoothLocalDevicePrivate::isValid() const
void QBluetoothLocalDevicePrivate::processHostModeChange(QBluetoothLocalDevice::HostMode newMode)
{
- if (!pendingHostModeTransition) {
- // if not in transition -> pass data on
+ qCDebug(QT_BT_ANDROID) << "Processing host mode change:" << newMode
+ << ", pending transition:" << pendingConnectableHostModeTransition;
+ if (!pendingConnectableHostModeTransition) {
+ // If host mode is not in transition -> pass data on
emit q_ptr->hostModeStateChanged(newMode);
return;
}
+ // Host mode is in transition: check if the new mode is 'off' in which state
+ // we can enter the targeted 'Connectable' state
if (isValid() && newMode == QBluetoothLocalDevice::HostPoweredOff) {
- bool success = (bool)obj->callMethod<jboolean>("enable", "()Z");
- if (!success)
- emit q_ptr->error(QBluetoothLocalDevice::UnknownError);
+ const bool success = (bool)QJniObject::callStaticMethod<jboolean>(
+ QtJniTypes::Traits<QtJniTypes::QtBtBroadcastReceiver>::className(),
+ "setEnabled");
+ if (!success) {
+ qCWarning(QT_BT_ANDROID) << "Transitioning Bluetooth from OFF to ON failed";
+ emit q_ptr->errorOccurred(QBluetoothLocalDevice::UnknownError);
+ }
}
-
- pendingHostModeTransition = false;
+ pendingConnectableHostModeTransition = false;
}
// Return -1 if address is not part of a pending pairing request
// Otherwise it returns the index of address in pendingPairings
int QBluetoothLocalDevicePrivate::pendingPairing(const QBluetoothAddress &address)
{
- for (int i = 0; i < pendingPairings.count(); i++) {
+ for (qsizetype i = 0; i < pendingPairings.size(); ++i) {
if (pendingPairings.at(i).first == address)
return i;
}
@@ -169,23 +125,15 @@ void QBluetoothLocalDevicePrivate::processPairingStateChanged(
|| (!entry.second && pairing == QBluetoothLocalDevice::Unpaired)) {
emit q_ptr->pairingFinished(address, pairing);
} else {
- emit q_ptr->error(QBluetoothLocalDevice::PairingError);
+ emit q_ptr->errorOccurred(QBluetoothLocalDevice::PairingError);
}
}
void QBluetoothLocalDevicePrivate::processConnectDeviceChanges(const QBluetoothAddress &address,
bool isConnectEvent)
{
- int index = -1;
- for (int i = 0; i < connectedDevices.count(); i++) {
- if (connectedDevices.at(i) == address) {
- index = i;
- break;
- }
- }
-
if (isConnectEvent) { // connect event
- if (index >= 0)
+ if (connectedDevices.contains(address))
return;
connectedDevices.append(address);
emit q_ptr->deviceConnected(address);
@@ -195,18 +143,6 @@ void QBluetoothLocalDevicePrivate::processConnectDeviceChanges(const QBluetoothA
}
}
-void QBluetoothLocalDevicePrivate::processDisplayConfirmation(const QBluetoothAddress &address,
- const QString &pin)
-{
- // only send pairing notification for pairing requests issued by
- // this QBluetoothLocalDevice instance
- if (pendingPairing(address) == -1)
- return;
-
- emit q_ptr->pairingDisplayConfirmation(address, pin);
- emit q_ptr->pairingDisplayPinCode(address, pin);
-}
-
QBluetoothLocalDevice::QBluetoothLocalDevice(QObject *parent) :
QObject(parent),
d_ptr(new QBluetoothLocalDevicePrivate(this, QBluetoothAddress()))
@@ -222,7 +158,7 @@ QBluetoothLocalDevice::QBluetoothLocalDevice(const QBluetoothAddress &address, Q
QString QBluetoothLocalDevice::name() const
{
if (d_ptr->adapter())
- return d_ptr->adapter()->callObjectMethod("getName", "()Ljava/lang/String;").toString();
+ return d_ptr->adapter()->callMethod<jstring>("getName").toString();
return QString();
}
@@ -230,10 +166,8 @@ QString QBluetoothLocalDevice::name() const
QBluetoothAddress QBluetoothLocalDevice::address() const
{
QString result;
- if (d_ptr->adapter()) {
- result
- = d_ptr->adapter()->callObjectMethod("getAddress", "()Ljava/lang/String;").toString();
- }
+ if (d_ptr->adapter())
+ result = d_ptr->adapter()->callMethod<jstring>("getAddress").toString();
QBluetoothAddress address(result);
return address;
@@ -245,44 +179,88 @@ void QBluetoothLocalDevice::powerOn()
return;
if (d_ptr->adapter()) {
- bool ret = (bool)d_ptr->adapter()->callMethod<jboolean>("enable", "()Z");
- if (!ret)
- emit error(QBluetoothLocalDevice::UnknownError);
+ bool success(false);
+ if (QNativeInterface::QAndroidApplication::sdkVersion() >= 31) {
+ success = (bool)QJniObject::callStaticMethod<jboolean>(
+ QtJniTypes::Traits<QtJniTypes::QtBtBroadcastReceiver>::className(),
+ "setEnabled");
+ } else {
+ success = (bool)d_ptr->adapter()->callMethod<jboolean>("enable");
+ }
+ if (!success) {
+ qCWarning(QT_BT_ANDROID) << "Enabling bluetooth failed";
+ emit errorOccurred(QBluetoothLocalDevice::UnknownError);
+ }
}
}
void QBluetoothLocalDevice::setHostMode(QBluetoothLocalDevice::HostMode requestedMode)
{
- QBluetoothLocalDevice::HostMode mode = requestedMode;
+ QBluetoothLocalDevice::HostMode nextMode = requestedMode;
if (requestedMode == HostDiscoverableLimitedInquiry)
- mode = HostDiscoverable;
+ nextMode = HostDiscoverable;
- if (mode == hostMode())
+ if (nextMode == hostMode())
return;
- if (mode == QBluetoothLocalDevice::HostPoweredOff) {
+ switch (nextMode) {
+
+ case QBluetoothLocalDevice::HostPoweredOff: {
bool success = false;
- if (d_ptr->adapter())
- success = (bool)d_ptr->adapter()->callMethod<jboolean>("disable", "()Z");
+ if (d_ptr->adapter()) {
+ if (QNativeInterface::QAndroidApplication::sdkVersion() >= 31) {
+ success = (bool)QJniObject::callStaticMethod<jboolean>(
+ QtJniTypes::Traits<QtJniTypes::QtBtBroadcastReceiver>::className(),
+ "setDisabled");
+ } else {
+ success = (bool)d_ptr->adapter()->callMethod<jboolean>("disable");
+ }
+ }
+ if (!success) {
+ qCWarning(QT_BT_ANDROID) << "Unable to power off the adapter";
+ emit errorOccurred(QBluetoothLocalDevice::UnknownError);
+ }
+ break;
+ }
- if (!success)
- emit error(QBluetoothLocalDevice::UnknownError);
- } else if (mode == QBluetoothLocalDevice::HostConnectable) {
+ case QBluetoothLocalDevice::HostConnectable: {
if (hostMode() == QBluetoothLocalDevice::HostDiscoverable) {
- // cannot directly go from Discoverable to Connectable
- // we need to go to disabled mode and enable once disabling came through
-
+ // On Android 'Discoverable' is actually 'CONNECTABLE_DISCOVERABLE', and
+ // it seems we cannot go directly from "Discoverable" to "Connectable". Instead
+ // we need to go to disabled mode first and then to the 'Connectable' mode
setHostMode(QBluetoothLocalDevice::HostPoweredOff);
- d_ptr->pendingHostModeTransition = true;
+ d_ptr->pendingConnectableHostModeTransition = true;
} else {
- QAndroidJniObject::callStaticMethod<void>(
- "org/qtproject/qt5/android/bluetooth/QtBluetoothBroadcastReceiver",
- "setConnectable");
+ const bool success = (bool)QJniObject::callStaticMethod<jboolean>(
+ QtJniTypes::Traits<QtJniTypes::QtBtBroadcastReceiver>::className(),
+ "setEnabled");
+ if (!success) {
+ qCWarning(QT_BT_ANDROID) << "Unable to enable the Bluetooth";
+ emit errorOccurred(QBluetoothLocalDevice::UnknownError);
+ }
}
- } else if (mode == QBluetoothLocalDevice::HostDiscoverable
- || mode == QBluetoothLocalDevice::HostDiscoverableLimitedInquiry) {
- QAndroidJniObject::callStaticMethod<void>(
- "org/qtproject/qt5/android/bluetooth/QtBluetoothBroadcastReceiver", "setDiscoverable");
+ break;
+ }
+
+ case QBluetoothLocalDevice::HostDiscoverable: {
+ if (!ensureAndroidPermission(QBluetoothPermission::Advertise)) {
+ qCWarning(QT_BT_ANDROID) << "Local device setHostMode() failed due to "
+ "missing permissions";
+ emit errorOccurred(QBluetoothLocalDevice::MissingPermissionsError);
+ return;
+ }
+ const bool success = (bool)QJniObject::callStaticMethod<jboolean>(
+ QtJniTypes::Traits<QtJniTypes::QtBtBroadcastReceiver>::className(),
+ "setDiscoverable");
+ if (!success) {
+ qCWarning(QT_BT_ANDROID) << "Unable to set Bluetooth as discoverable";
+ emit errorOccurred(QBluetoothLocalDevice::UnknownError);
+ }
+ break;
+ }
+ default:
+ qCWarning(QT_BT_ANDROID) << "setHostMode() unsupported host mode:" << nextMode;
+ break;
}
}
@@ -308,15 +286,20 @@ QBluetoothLocalDevice::HostMode QBluetoothLocalDevice::hostMode() const
QList<QBluetoothHostInfo> QBluetoothLocalDevice::allDevices()
{
+ // As a static class function we need to ensure permissions here (in addition to initialize())
+ if (!ensureAndroidPermission(QBluetoothPermission::Access)) {
+ qCWarning(QT_BT_ANDROID) << "Local device allDevices() failed due to "
+ "missing permissions";
+ return {};
+ }
// Android only supports max of one device (so far)
QList<QBluetoothHostInfo> localDevices;
- QAndroidJniObject o = getDefaultAdapter();
+ QJniObject o = getDefaultBluetoothAdapter();
if (o.isValid()) {
QBluetoothHostInfo info;
- info.setName(o.callObjectMethod("getName", "()Ljava/lang/String;").toString());
- info.setAddress(QBluetoothAddress(o.callObjectMethod("getAddress",
- "()Ljava/lang/String;").toString()));
+ info.setName(o.callMethod<jstring>("getName").toString());
+ info.setAddress(QBluetoothAddress(o.callMethod<jstring>("getAddress").toString()));
localDevices.append(info);
}
return localDevices;
@@ -325,7 +308,7 @@ QList<QBluetoothHostInfo> QBluetoothLocalDevice::allDevices()
void QBluetoothLocalDevice::requestPairing(const QBluetoothAddress &address, Pairing pairing)
{
if (address.isNull()) {
- QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection,
+ QMetaObject::invokeMethod(this, "errorOccurred", Qt::QueuedConnection,
Q_ARG(QBluetoothLocalDevice::Error,
QBluetoothLocalDevice::PairingError));
return;
@@ -339,29 +322,27 @@ void QBluetoothLocalDevice::requestPairing(const QBluetoothAddress &address, Pai
if (previousPairing == newPairing) {
QMetaObject::invokeMethod(this, "pairingFinished", Qt::QueuedConnection,
Q_ARG(QBluetoothAddress, address),
- Q_ARG(QBluetoothLocalDevice::Pairing, pairing));
+ Q_ARG(QBluetoothLocalDevice::Pairing, newPairing));
return;
}
- // BluetoothDevice::createBond() requires Android API 15
- if (QtAndroidPrivate::androidSdkVersion() < 15 || !d_ptr->adapter()) {
- qCWarning(QT_BT_ANDROID) << "Unable to pair: requires Android API 15+";
- QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection,
+ if (!d_ptr->adapter()) {
+ qCWarning(QT_BT_ANDROID) << "Unable to pair, invalid adapter";
+ QMetaObject::invokeMethod(this, "errorOccurred", Qt::QueuedConnection,
Q_ARG(QBluetoothLocalDevice::Error,
QBluetoothLocalDevice::PairingError));
return;
}
- QAndroidJniObject inputString = QAndroidJniObject::fromString(address.toString());
- jboolean success = QAndroidJniObject::callStaticMethod<jboolean>(
- "org/qtproject/qt5/android/bluetooth/QtBluetoothBroadcastReceiver",
+ QJniObject inputString = QJniObject::fromString(address.toString());
+ jboolean success = QJniObject::callStaticMethod<jboolean>(
+ QtJniTypes::Traits<QtJniTypes::QtBtBroadcastReceiver>::className(),
"setPairingMode",
- "(Ljava/lang/String;Z)Z",
inputString.object<jstring>(),
- newPairing == Paired ? JNI_TRUE : JNI_FALSE);
+ jboolean(newPairing == Paired ? JNI_TRUE : JNI_FALSE));
if (!success) {
- QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection,
+ QMetaObject::invokeMethod(this, "errorOccurred", Qt::QueuedConnection,
Q_ARG(QBluetoothLocalDevice::Error,
QBluetoothLocalDevice::PairingError));
} else {
@@ -375,16 +356,13 @@ QBluetoothLocalDevice::Pairing QBluetoothLocalDevice::pairingStatus(
if (address.isNull() || !d_ptr->adapter())
return Unpaired;
- QAndroidJniObject inputString = QAndroidJniObject::fromString(address.toString());
- QAndroidJniObject remoteDevice
- = d_ptr->adapter()->callObjectMethod("getRemoteDevice",
- "(Ljava/lang/String;)Landroid/bluetooth/BluetoothDevice;",
- inputString.object<jstring>());
- QAndroidJniEnvironment env;
- if (env->ExceptionCheck()) {
- env->ExceptionClear();
+ QJniObject inputString = QJniObject::fromString(address.toString());
+ QJniObject remoteDevice
+ = d_ptr->adapter()->callMethod<QtJniTypes::BluetoothDevice>("getRemoteDevice",
+ inputString.object<jstring>());
+
+ if (!remoteDevice.isValid())
return Unpaired;
- }
jint bondState = remoteDevice.callMethod<jint>("getBondState");
switch (bondState) {
@@ -397,16 +375,6 @@ QBluetoothLocalDevice::Pairing QBluetoothLocalDevice::pairingStatus(
return Unpaired;
}
-void QBluetoothLocalDevice::pairingConfirmation(bool confirmation)
-{
- if (!d_ptr->adapter())
- return;
-
- bool success = d_ptr->receiver->pairingConfirmation(confirmation);
- if (!success)
- emit error(PairingError);
-}
-
QList<QBluetoothAddress> QBluetoothLocalDevice::connectedDevices() const
{
/*
@@ -420,10 +388,8 @@ QList<QBluetoothAddress> QBluetoothLocalDevice::connectedDevices() const
* returns a few connections of common profiles. The returned list is not complete either
* but at least it can complement our already detected connections.
*/
- QAndroidJniObject connectedDevices = QAndroidJniObject::callStaticObjectMethod(
- "org/qtproject/qt5/android/bluetooth/QtBluetoothBroadcastReceiver",
- "getConnectedDevices",
- "()[Ljava/lang/String;");
+ QJniObject connectedDevices = QJniObject::callStaticMethod<QtJniTypes::StringArray>(
+ QtJniTypes::Traits<QtJniTypes::QtBtBroadcastReceiver>::className(), "getConnectedDevices");
if (!connectedDevices.isValid())
return d_ptr->connectedDevices;
@@ -432,9 +398,9 @@ QList<QBluetoothAddress> QBluetoothLocalDevice::connectedDevices() const
if (!connectedDevicesArray)
return d_ptr->connectedDevices;
- QAndroidJniEnvironment env;
+ QJniEnvironment env;
QList<QBluetoothAddress> knownAddresses = d_ptr->connectedDevices;
- QAndroidJniObject p;
+ QJniObject p;
jint size = env->GetArrayLength(connectedDevicesArray);
for (int i = 0; i < size; i++) {
diff --git a/src/bluetooth/qbluetoothlocaldevice_bluez.cpp b/src/bluetooth/qbluetoothlocaldevice_bluez.cpp
index f48717a6..7bac1de8 100644
--- a/src/bluetooth/qbluetoothlocaldevice_bluez.cpp
+++ b/src/bluetooth/qbluetoothlocaldevice_bluez.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtCore/QLoggingCategory>
#include <QtCore/QRandomGenerator>
@@ -45,10 +9,6 @@
#include "qbluetoothaddress.h"
#include "qbluetoothlocaldevice_p.h"
-#include "bluez/manager_p.h"
-#include "bluez/adapter_p.h"
-#include "bluez/agent_p.h"
-#include "bluez/device_p.h"
#include "bluez/bluez5_helper_p.h"
#include "bluez/objectmanager_p.h"
#include "bluez/properties_p.h"
@@ -59,53 +19,32 @@ QT_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(QT_BT_BLUEZ)
-static const QLatin1String agentPath("/qt/agent");
-
-inline uint qHash(const QBluetoothAddress &address)
-{
- return ::qHash(address.toUInt64());
-}
-
QBluetoothLocalDevice::QBluetoothLocalDevice(QObject *parent) :
QObject(parent),
d_ptr(new QBluetoothLocalDevicePrivate(this))
{
+ d_ptr->currentMode = hostMode();
}
QBluetoothLocalDevice::QBluetoothLocalDevice(const QBluetoothAddress &address, QObject *parent) :
QObject(parent),
d_ptr(new QBluetoothLocalDevicePrivate(this, address))
{
+ d_ptr->currentMode = hostMode();
}
QString QBluetoothLocalDevice::name() const
{
- if (d_ptr->adapter) {
- QDBusPendingReply<QVariantMap> reply = d_ptr->adapter->GetProperties();
- reply.waitForFinished();
- if (reply.isError())
- return QString();
-
- return reply.value().value(QStringLiteral("Name")).toString();
- } else if (d_ptr->adapterBluez5) {
- return d_ptr->adapterBluez5->alias();
- }
+ if (d_ptr->adapter)
+ return d_ptr->adapter->alias();
return QString();
}
QBluetoothAddress QBluetoothLocalDevice::address() const
{
- if (d_ptr->adapter) {
- QDBusPendingReply<QVariantMap> reply = d_ptr->adapter->GetProperties();
- reply.waitForFinished();
- if (reply.isError())
- return QBluetoothAddress();
-
- return QBluetoothAddress(reply.value().value(QStringLiteral("Address")).toString());
- } else if (d_ptr->adapterBluez5) {
- return QBluetoothAddress(d_ptr->adapterBluez5->address());
- }
+ if (d_ptr->adapter)
+ return QBluetoothAddress(d_ptr->adapter->address());
return QBluetoothAddress();
}
@@ -113,9 +52,7 @@ QBluetoothAddress QBluetoothLocalDevice::address() const
void QBluetoothLocalDevice::powerOn()
{
if (d_ptr->adapter)
- d_ptr->adapter->SetProperty(QStringLiteral("Powered"), QDBusVariant(QVariant::fromValue(true)));
- else if (d_ptr->adapterBluez5)
- d_ptr->adapterBluez5->setPowered(true);
+ d_ptr->adapter->setPowered(true);
}
void QBluetoothLocalDevice::setHostMode(QBluetoothLocalDevice::HostMode mode)
@@ -125,6 +62,11 @@ void QBluetoothLocalDevice::setHostMode(QBluetoothLocalDevice::HostMode mode)
Q_D(QBluetoothLocalDevice);
+ if (d->pendingHostModeChange != -1) {
+ qCWarning(QT_BT_BLUEZ) << "setHostMode() ignored due to already pending mode change";
+ return;
+ }
+
switch (mode) {
case HostDiscoverableLimitedInquiry:
case HostDiscoverable:
@@ -132,46 +74,21 @@ void QBluetoothLocalDevice::setHostMode(QBluetoothLocalDevice::HostMode mode)
// We first have to wait for BT to be powered on,
// then we can set the host mode correctly
d->pendingHostModeChange = static_cast<int>(HostDiscoverable);
- if (d->adapter) {
- d->adapter->SetProperty(QStringLiteral("Powered"),
- QDBusVariant(QVariant::fromValue(true)));
- } else {
- d->adapterBluez5->setPowered(true);
- }
+ d->adapter->setPowered(true);
} else {
- if (d->adapter) {
- d->adapter->SetProperty(QStringLiteral("Discoverable"),
- QDBusVariant(QVariant::fromValue(true)));
- } else {
- d->adapterBluez5->setDiscoverable(true);
- }
+ d->adapter->setDiscoverable(true);
}
break;
case HostConnectable:
if (hostMode() == HostPoweredOff) {
d->pendingHostModeChange = static_cast<int>(HostConnectable);
- if (d->adapter) {
- d->adapter->SetProperty(QStringLiteral("Powered"),
- QDBusVariant(QVariant::fromValue(true)));
- } else {
- d->adapterBluez5->setPowered(true);
- }
+ d->adapter->setPowered(true);
} else {
- if (d->adapter) {
- d->adapter->SetProperty(QStringLiteral("Discoverable"),
- QDBusVariant(QVariant::fromValue(false)));
- } else {
- d->adapterBluez5->setDiscoverable(false);
- }
+ d->adapter->setDiscoverable(false);
}
break;
case HostPoweredOff:
- if (d->adapter) {
- d->adapter->SetProperty(QStringLiteral("Powered"),
- QDBusVariant(QVariant::fromValue(false)));
- } else {
- d->adapterBluez5->setPowered(false);
- }
+ d->adapter->setPowered(false);
break;
}
}
@@ -179,23 +96,11 @@ void QBluetoothLocalDevice::setHostMode(QBluetoothLocalDevice::HostMode mode)
QBluetoothLocalDevice::HostMode QBluetoothLocalDevice::hostMode() const
{
if (d_ptr->adapter) {
- QDBusPendingReply<QVariantMap> reply = d_ptr->adapter->GetProperties();
- reply.waitForFinished();
- if (reply.isError())
+ if (!d_ptr->adapter->powered())
return HostPoweredOff;
-
- if (!reply.value().value(QStringLiteral("Powered")).toBool())
- return HostPoweredOff;
- else if (reply.value().value(QStringLiteral("Discoverable")).toBool())
- return HostDiscoverable;
- else if (reply.value().value(QStringLiteral("Powered")).toBool())
- return HostConnectable;
- } else if (d_ptr->adapterBluez5) {
- if (!d_ptr->adapterBluez5->powered())
- return HostPoweredOff;
- else if (d_ptr->adapterBluez5->discoverable())
+ else if (d_ptr->adapter->discoverable())
return HostDiscoverable;
- else if (d_ptr->adapterBluez5->powered())
+ else if (d_ptr->adapter->powered())
return HostConnectable;
}
@@ -211,88 +116,43 @@ QList<QBluetoothHostInfo> QBluetoothLocalDevice::allDevices()
{
QList<QBluetoothHostInfo> localDevices;
- if (isBluez5()) {
- OrgFreedesktopDBusObjectManagerInterface manager(QStringLiteral("org.bluez"),
- QStringLiteral("/"),
- QDBusConnection::systemBus());
- QDBusPendingReply<ManagedObjectList> reply = manager.GetManagedObjects();
- reply.waitForFinished();
- if (reply.isError())
- return localDevices;
+ initializeBluez5();
+ OrgFreedesktopDBusObjectManagerInterface manager(
+ QStringLiteral("org.bluez"), QStringLiteral("/"), QDBusConnection::systemBus());
+ QDBusPendingReply<ManagedObjectList> reply = manager.GetManagedObjects();
+ reply.waitForFinished();
+ if (reply.isError())
+ return localDevices;
- ManagedObjectList managedObjectList = reply.value();
- for (ManagedObjectList::const_iterator it = managedObjectList.constBegin(); it != managedObjectList.constEnd(); ++it) {
- const InterfaceList &ifaceList = it.value();
+ ManagedObjectList managedObjectList = reply.value();
+ for (ManagedObjectList::const_iterator it = managedObjectList.constBegin();
+ it != managedObjectList.constEnd(); ++it) {
+ const InterfaceList &ifaceList = it.value();
- for (InterfaceList::const_iterator jt = ifaceList.constBegin(); jt != ifaceList.constEnd(); ++jt) {
- const QString &iface = jt.key();
- const QVariantMap &ifaceValues = jt.value();
+ for (InterfaceList::const_iterator jt = ifaceList.constBegin(); jt != ifaceList.constEnd();
+ ++jt) {
+ const QString &iface = jt.key();
+ const QVariantMap &ifaceValues = jt.value();
- if (iface == QStringLiteral("org.bluez.Adapter1")) {
- QBluetoothHostInfo hostInfo;
- const QString temp = ifaceValues.value(QStringLiteral("Address")).toString();
+ if (iface == QStringLiteral("org.bluez.Adapter1")) {
+ QBluetoothHostInfo hostInfo;
+ const QString temp = ifaceValues.value(QStringLiteral("Address")).toString();
- hostInfo.setAddress(QBluetoothAddress(temp));
- if (hostInfo.address().isNull())
- continue;
- hostInfo.setName(ifaceValues.value(QStringLiteral("Name")).toString());
- localDevices.append(hostInfo);
- }
+ hostInfo.setAddress(QBluetoothAddress(temp));
+ if (hostInfo.address().isNull())
+ continue;
+ hostInfo.setName(ifaceValues.value(QStringLiteral("Name")).toString());
+ localDevices.append(hostInfo);
}
}
- } else {
- OrgBluezManagerInterface manager(QStringLiteral("org.bluez"), QStringLiteral("/"),
- QDBusConnection::systemBus());
-
- QDBusPendingReply<QList<QDBusObjectPath> > reply = manager.ListAdapters();
- reply.waitForFinished();
- if (reply.isError())
- return localDevices;
-
- const QList<QDBusObjectPath> paths = reply.value();
- for (const QDBusObjectPath &path : paths) {
- QBluetoothHostInfo hostinfo;
- OrgBluezAdapterInterface adapter(QStringLiteral("org.bluez"), path.path(),
- QDBusConnection::systemBus());
-
- QDBusPendingReply<QVariantMap> reply = adapter.GetProperties();
- reply.waitForFinished();
- if (reply.isError())
- continue;
-
- hostinfo.setAddress(QBluetoothAddress(
- reply.value().value(QStringLiteral("Address")).toString()));
- hostinfo.setName(reply.value().value(QStringLiteral("Name")).toString());
-
- localDevices.append(hostinfo);
- }
}
-
return localDevices;
}
-static inline OrgBluezDeviceInterface *getDevice(const QBluetoothAddress &address,
- QBluetoothLocalDevicePrivate *d_ptr)
-{
- if (!d_ptr || !d_ptr->adapter)
- return nullptr;
- QDBusPendingReply<QDBusObjectPath> reply = d_ptr->adapter->FindDevice(address.toString());
- reply.waitForFinished();
- if (reply.isError()) {
- qCWarning(QT_BT_BLUEZ) << Q_FUNC_INFO << "reply failed" << reply.error();
- return nullptr;
- }
-
- QDBusObjectPath path = reply.value();
-
- return new OrgBluezDeviceInterface(QStringLiteral("org.bluez"), path.path(),
- QDBusConnection::systemBus());
-}
-
void QBluetoothLocalDevice::requestPairing(const QBluetoothAddress &address, Pairing pairing)
{
if (!isValid() || address.isNull()) {
- QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection,
+ QMetaObject::invokeMethod(this, "errorOccurred", Qt::QueuedConnection,
Q_ARG(QBluetoothLocalDevice::Error,
QBluetoothLocalDevice::PairingError));
return;
@@ -300,7 +160,7 @@ void QBluetoothLocalDevice::requestPairing(const QBluetoothAddress &address, Pai
const Pairing current_pairing = pairingStatus(address);
if (current_pairing == pairing) {
- if (d_ptr->adapterBluez5) {
+ if (d_ptr->adapter) {
// A possibly running discovery or pending pairing request should be canceled
if (d_ptr->pairingDiscoveryTimer && d_ptr->pairingDiscoveryTimer->isActive()) {
d_ptr->pairingDiscoveryTimer->stop();
@@ -309,11 +169,11 @@ void QBluetoothLocalDevice::requestPairing(const QBluetoothAddress &address, Pai
if (d_ptr->pairingTarget) {
qCDebug(QT_BT_BLUEZ) << "Cancelling pending pairing request to" << d_ptr->pairingTarget->address();
QDBusPendingReply<> cancelReply = d_ptr->pairingTarget->CancelPairing();
+ d_ptr->pairingRequestCanceled = true;
cancelReply.waitForFinished();
delete d_ptr->pairingTarget;
d_ptr->pairingTarget = nullptr;
}
-
}
QMetaObject::invokeMethod(this, "pairingFinished", Qt::QueuedConnection,
Q_ARG(QBluetoothAddress, address),
@@ -321,127 +181,19 @@ void QBluetoothLocalDevice::requestPairing(const QBluetoothAddress &address, Pai
return;
}
- if (d_ptr->adapterBluez5) {
- d_ptr->requestPairingBluez5(address, pairing);
- return;
- }
-
- if (pairing == Paired || pairing == AuthorizedPaired) {
- d_ptr->address = address;
- d_ptr->pairing = pairing;
-
- if (!d_ptr->agent) {
- d_ptr->agent = new OrgBluezAgentAdaptor(d_ptr);
- bool res = QDBusConnection::systemBus().registerObject(d_ptr->agent_path, d_ptr);
- if (!res) {
- QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection,
- Q_ARG(QBluetoothLocalDevice::Error,
- QBluetoothLocalDevice::PairingError));
- qCWarning(QT_BT_BLUEZ) << "Failed to register agent";
- return;
- }
- }
-
- if (current_pairing == Paired && pairing == AuthorizedPaired) {
- OrgBluezDeviceInterface *device = getDevice(address, d_ptr);
- if (!device) {
- QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection,
- Q_ARG(QBluetoothLocalDevice::Error,
- QBluetoothLocalDevice::PairingError));
- return;
- }
- QDBusPendingReply<> deviceReply
- = device->SetProperty(QStringLiteral("Trusted"), QDBusVariant(true));
- deviceReply.waitForFinished();
- if (deviceReply.isError()) {
- qCWarning(QT_BT_BLUEZ) << Q_FUNC_INFO << "reply failed" << deviceReply.error();
- QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection,
- Q_ARG(QBluetoothLocalDevice::Error,
- QBluetoothLocalDevice::PairingError));
- delete device;
- return;
- }
- delete device;
- QMetaObject::invokeMethod(this, "pairingFinished", Qt::QueuedConnection,
- Q_ARG(QBluetoothAddress, address),
- Q_ARG(QBluetoothLocalDevice::Pairing,
- QBluetoothLocalDevice::AuthorizedPaired));
- } else if (current_pairing == AuthorizedPaired && pairing == Paired) {
- OrgBluezDeviceInterface *device = getDevice(address, d_ptr);
- if (!device) {
- QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection,
- Q_ARG(QBluetoothLocalDevice::Error,
- QBluetoothLocalDevice::PairingError));
- return;
- }
- QDBusPendingReply<> deviceReply
- = device->SetProperty(QStringLiteral("Trusted"), QDBusVariant(false));
- deviceReply.waitForFinished();
- if (deviceReply.isError()) {
- qCWarning(QT_BT_BLUEZ) << Q_FUNC_INFO << "reply failed" << deviceReply.error();
- QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection,
- Q_ARG(QBluetoothLocalDevice::Error,
- QBluetoothLocalDevice::PairingError));
- delete device;
- return;
- }
- delete device;
- QMetaObject::invokeMethod(this, "pairingFinished", Qt::QueuedConnection,
- Q_ARG(QBluetoothAddress, address),
- Q_ARG(QBluetoothLocalDevice::Pairing,
- QBluetoothLocalDevice::Paired));
- } else {
- QDBusPendingReply<QDBusObjectPath> reply
- = d_ptr->adapter->CreatePairedDevice(address.toString(),
- QDBusObjectPath(d_ptr->agent_path),
- QStringLiteral("NoInputNoOutput"));
-
- QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this);
- connect(watcher, &QDBusPendingCallWatcher::finished,
- d_ptr, &QBluetoothLocalDevicePrivate::pairingCompleted);
-
- if (reply.isError())
- qCWarning(QT_BT_BLUEZ) << Q_FUNC_INFO << reply.error() << d_ptr->agent_path;
- }
- } else if (pairing == Unpaired) {
- QDBusPendingReply<QDBusObjectPath> reply = this->d_ptr->adapter->FindDevice(
- address.toString());
- reply.waitForFinished();
- if (reply.isError()) {
- qCWarning(QT_BT_BLUEZ) << Q_FUNC_INFO << "failed to find device" << reply.error();
- QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection,
- Q_ARG(QBluetoothLocalDevice::Error,
- QBluetoothLocalDevice::PairingError));
- return;
- }
- QDBusPendingReply<> removeReply = this->d_ptr->adapter->RemoveDevice(reply.value());
- removeReply.waitForFinished();
- if (removeReply.isError()) {
- qCWarning(QT_BT_BLUEZ) << Q_FUNC_INFO << "failed to remove device"
- << removeReply.error();
- QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection,
- Q_ARG(QBluetoothLocalDevice::Error,
- QBluetoothLocalDevice::PairingError));
- } else {
- QMetaObject::invokeMethod(this, "pairingFinished", Qt::QueuedConnection,
- Q_ARG(QBluetoothAddress, address),
- Q_ARG(QBluetoothLocalDevice::Pairing,
- QBluetoothLocalDevice::Unpaired));
- }
- }
+ d_ptr->requestPairing(address, pairing);
}
-void QBluetoothLocalDevicePrivate::requestPairingBluez5(const QBluetoothAddress &targetAddress,
- QBluetoothLocalDevice::Pairing targetPairing)
+void QBluetoothLocalDevicePrivate::requestPairing(const QBluetoothAddress &targetAddress,
+ QBluetoothLocalDevice::Pairing targetPairing)
{
- if (!managerBluez5)
+ if (!isValid())
return;
//are we already discovering something? -> abort those attempts
if (pairingDiscoveryTimer && pairingDiscoveryTimer->isActive()) {
pairingDiscoveryTimer->stop();
- QtBluezDiscoveryManager::instance()->unregisterDiscoveryInterest(
- adapterBluez5->path());
+ QtBluezDiscoveryManager::instance()->unregisterDiscoveryInterest(adapter->path());
}
if (pairingTarget) {
@@ -453,10 +205,10 @@ void QBluetoothLocalDevicePrivate::requestPairingBluez5(const QBluetoothAddress
// if we cannot find it we may have to turn on Discovery mode for a limited amount of time
// check device doesn't already exist
- QDBusPendingReply<ManagedObjectList> reply = managerBluez5->GetManagedObjects();
+ QDBusPendingReply<ManagedObjectList> reply = manager->GetManagedObjects();
reply.waitForFinished();
if (reply.isError()) {
- emit q_ptr->error(QBluetoothLocalDevice::PairingError);
+ emit q_ptr->errorOccurred(QBluetoothLocalDevice::PairingError);
return;
}
@@ -476,7 +228,7 @@ void QBluetoothLocalDevicePrivate::requestPairingBluez5(const QBluetoothAddress
if (targetAddress == QBluetoothAddress(device.address())) {
qCDebug(QT_BT_BLUEZ) << "Initiating direct pair to" << targetAddress.toString();
//device exist -> directly work with it
- processPairingBluez5(path.path(), targetPairing);
+ processPairing(path.path(), targetPairing);
return;
}
}
@@ -484,7 +236,7 @@ void QBluetoothLocalDevicePrivate::requestPairingBluez5(const QBluetoothAddress
}
//no device matching -> turn on discovery
- QtBluezDiscoveryManager::instance()->registerDiscoveryInterest(adapterBluez5->path());
+ QtBluezDiscoveryManager::instance()->registerDiscoveryInterest(adapter->path());
address = targetAddress;
pairing = targetPairing;
@@ -507,8 +259,8 @@ void QBluetoothLocalDevicePrivate::requestPairingBluez5(const QBluetoothAddress
* If it has to be paired then we need another roundtrip through the event loop
* while we wait for the user to accept the pairing dialogs.
*/
-void QBluetoothLocalDevicePrivate::processPairingBluez5(const QString &objectPath,
- QBluetoothLocalDevice::Pairing target)
+void QBluetoothLocalDevicePrivate::processPairing(const QString &objectPath,
+ QBluetoothLocalDevice::Pairing target)
{
if (pairingTarget)
delete pairingTarget;
@@ -517,8 +269,7 @@ void QBluetoothLocalDevicePrivate::processPairingBluez5(const QString &objectPat
if (pairingDiscoveryTimer && pairingDiscoveryTimer->isActive()) {
pairingDiscoveryTimer->stop();
- QtBluezDiscoveryManager::instance()->unregisterDiscoveryInterest(
- adapterBluez5->path());
+ QtBluezDiscoveryManager::instance()->unregisterDiscoveryInterest(adapter->path());
}
pairingTarget = new OrgBluezDevice1Interface(QStringLiteral("org.bluez"), objectPath,
@@ -532,13 +283,13 @@ void QBluetoothLocalDevicePrivate::processPairingBluez5(const QString &objectPat
delete pairingTarget;
pairingTarget = nullptr;
- QDBusPendingReply<> removeReply = adapterBluez5->RemoveDevice(QDBusObjectPath(objectPath));
+ QDBusPendingReply<> removeReply = adapter->RemoveDevice(QDBusObjectPath(objectPath));
auto watcher = new QDBusPendingCallWatcher(removeReply, this);
connect(watcher, &QDBusPendingCallWatcher::finished,
this, [q, targetAddress](QDBusPendingCallWatcher* watcher){
QDBusPendingReply<> reply = *watcher;
if (reply.isError())
- emit q->error(QBluetoothLocalDevice::PairingError);
+ emit q->errorOccurred(QBluetoothLocalDevice::PairingError);
else
emit q->pairingFinished(targetAddress, QBluetoothLocalDevice::Unpaired);
@@ -581,10 +332,9 @@ void QBluetoothLocalDevicePrivate::pairingDiscoveryTimedOut()
{
qCWarning(QT_BT_BLUEZ) << "Discovery for pairing purposes failed. Cannot find parable device.";
- QtBluezDiscoveryManager::instance()->unregisterDiscoveryInterest(
- adapterBluez5->path());
+ QtBluezDiscoveryManager::instance()->unregisterDiscoveryInterest(adapter->path());
- emit q_ptr->error(QBluetoothLocalDevice::PairingError);
+ emit q_ptr->errorOccurred(QBluetoothLocalDevice::PairingError);
}
QBluetoothLocalDevice::Pairing QBluetoothLocalDevice::pairingStatus(
@@ -593,32 +343,9 @@ QBluetoothLocalDevice::Pairing QBluetoothLocalDevice::pairingStatus(
if (address.isNull())
return Unpaired;
- if (d_ptr->adapter) {
- OrgBluezDeviceInterface *device = getDevice(address, d_ptr);
-
- if (!device)
- return Unpaired;
-
- QDBusPendingReply<QVariantMap> deviceReply = device->GetProperties();
- deviceReply.waitForFinished();
- if (deviceReply.isError()) {
- delete device;
- return Unpaired;
- }
-
- QVariantMap map = deviceReply.value();
-
- if (map.value(QStringLiteral("Trusted")).toBool() && map.value(QStringLiteral("Paired")).toBool()) {
- delete device;
- return AuthorizedPaired;
- } else if (map.value(QStringLiteral("Paired")).toBool()) {
- delete device;
- return Paired;
- }
- delete device;
- } else if (d_ptr->adapterBluez5) {
-
- QDBusPendingReply<ManagedObjectList> reply = d_ptr->managerBluez5->GetManagedObjects();
+ if (isValid())
+ {
+ QDBusPendingReply<ManagedObjectList> reply = d_ptr->manager->GetManagedObjects();
reply.waitForFinished();
if (reply.isError())
return Unpaired;
@@ -660,11 +387,8 @@ QBluetoothLocalDevicePrivate::QBluetoothLocalDevicePrivate(QBluetoothLocalDevice
q_ptr(q)
{
registerQBluetoothLocalDeviceMetaType();
-
- if (isBluez5())
- initializeAdapterBluez5();
- else
- initializeAdapter();
+ initializeBluez5();
+ initializeAdapter();
connectDeviceChanges();
}
@@ -676,17 +400,9 @@ bool objectPathIsForThisDevice(const QString &adapterPath, const QString &object
void QBluetoothLocalDevicePrivate::connectDeviceChanges()
{
- if (adapter) { // invalid QBluetoothLocalDevice due to wrong local adapter address
- createCache();
- connect(adapter, &OrgBluezAdapterInterface::PropertyChanged,
- this, &QBluetoothLocalDevicePrivate::PropertyChanged);
- connect(adapter, &OrgBluezAdapterInterface::DeviceCreated,
- this, &QBluetoothLocalDevicePrivate::_q_deviceCreated);
- connect(adapter, &OrgBluezAdapterInterface::DeviceRemoved,
- this, &QBluetoothLocalDevicePrivate::_q_deviceRemoved);
- } else if (adapterBluez5 && managerBluez5) {
+ if (isValid()) {
//setup property change notifications for all existing devices
- QDBusPendingReply<ManagedObjectList> reply = managerBluez5->GetManagedObjects();
+ QDBusPendingReply<ManagedObjectList> reply = manager->GetManagedObjects();
reply.waitForFinished();
if (reply.isError())
return;
@@ -726,16 +442,11 @@ void QBluetoothLocalDevicePrivate::connectDeviceChanges()
QBluetoothLocalDevicePrivate::~QBluetoothLocalDevicePrivate()
{
- delete msgConnection;
delete adapter;
- delete adapterBluez5;
delete adapterProperties;
- delete managerBluez5;
- delete agent;
- delete pairingTarget;
delete manager;
+ delete pairingTarget;
- qDeleteAll(devices);
qDeleteAll(deviceChangeMonitors);
}
@@ -744,78 +455,16 @@ void QBluetoothLocalDevicePrivate::initializeAdapter()
if (adapter)
return;
- QScopedPointer<OrgBluezManagerInterface> man(new OrgBluezManagerInterface(
- QStringLiteral("org.bluez"), QStringLiteral("/"),
- QDBusConnection::systemBus()));
-
- if (localAddress == QBluetoothAddress()) {
- QDBusPendingReply<QDBusObjectPath> reply = man->DefaultAdapter();
- reply.waitForFinished();
- if (reply.isError())
- return;
-
- adapter = new OrgBluezAdapterInterface(QStringLiteral("org.bluez"),
- reply.value().path(), QDBusConnection::systemBus());
- } else {
- QDBusPendingReply<QList<QDBusObjectPath> > reply = man->ListAdapters();
- reply.waitForFinished();
- if (reply.isError())
- return;
-
- const QList<QDBusObjectPath> paths = reply.value();
- for (const QDBusObjectPath &path : paths) {
- OrgBluezAdapterInterface *tmpAdapter
- = new OrgBluezAdapterInterface(QStringLiteral("org.bluez"),
- path.path(), QDBusConnection::systemBus());
-
- QDBusPendingReply<QVariantMap> reply = tmpAdapter->GetProperties();
- reply.waitForFinished();
- if (reply.isError()) {
- delete tmpAdapter;
- continue;
- }
-
- QBluetoothAddress path_address(reply.value().value(QStringLiteral("Address")).toString());
-
- if (path_address == localAddress) {
- adapter = tmpAdapter;
- break;
- } else {
- delete tmpAdapter;
- }
- }
- }
-
- // monitor case when local adapter is removed
- manager = man.take();
- connect(manager, &OrgBluezManagerInterface::AdapterRemoved,
- this, &QBluetoothLocalDevicePrivate::adapterRemoved);
-
- currentMode = static_cast<QBluetoothLocalDevice::HostMode>(-1);
- if (adapter) {
- connect(adapter, &OrgBluezAdapterInterface::PropertyChanged,
- this, &QBluetoothLocalDevicePrivate::PropertyChanged);
-
- agent_path = agentPath;
- agent_path.append(QString::fromLatin1("/%1").arg(QRandomGenerator::global()->generate()));
- }
-}
-
-void QBluetoothLocalDevicePrivate::initializeAdapterBluez5()
-{
- if (adapterBluez5)
- return;
-
//get all local adapters
- if (!managerBluez5)
- managerBluez5 = new OrgFreedesktopDBusObjectManagerInterface(
+ if (!manager)
+ manager = new OrgFreedesktopDBusObjectManagerInterface(
QStringLiteral("org.bluez"),
QStringLiteral("/"),
QDBusConnection::systemBus(), this);
- connect(managerBluez5, &OrgFreedesktopDBusObjectManagerInterface::InterfacesAdded,
+ connect(manager, &OrgFreedesktopDBusObjectManagerInterface::InterfacesAdded,
this, &QBluetoothLocalDevicePrivate::InterfacesAdded);
- connect(managerBluez5, &OrgFreedesktopDBusObjectManagerInterface::InterfacesRemoved,
+ connect(manager, &OrgFreedesktopDBusObjectManagerInterface::InterfacesRemoved,
this, &QBluetoothLocalDevicePrivate::InterfacesRemoved);
bool ok = true;
@@ -824,26 +473,23 @@ void QBluetoothLocalDevicePrivate::initializeAdapterBluez5()
return;
deviceAdapterPath = adapterPath;
- adapterBluez5 = new OrgBluezAdapter1Interface(QStringLiteral("org.bluez"),
- adapterPath,
- QDBusConnection::systemBus(), this);
+ adapter = new OrgBluezAdapter1Interface(QStringLiteral("org.bluez"), adapterPath,
+ QDBusConnection::systemBus(), this);
- if (adapterBluez5) {
+ if (adapter) {
//hook up propertiesChanged for current adapter
adapterProperties = new OrgFreedesktopDBusPropertiesInterface(
- QStringLiteral("org.bluez"), adapterBluez5->path(),
- QDBusConnection::systemBus(), this);
+ QStringLiteral("org.bluez"), adapter->path(),
+ QDBusConnection::systemBus(), this);
connect(adapterProperties, &OrgFreedesktopDBusPropertiesInterface::PropertiesChanged,
this, &QBluetoothLocalDevicePrivate::PropertiesChanged);
}
-
- currentMode = static_cast<QBluetoothLocalDevice::HostMode>(-1);
}
-// Bluez 5
void QBluetoothLocalDevicePrivate::PropertiesChanged(const QString &interface,
const QVariantMap &changed_properties,
- const QStringList &/*invalidated_properties*/)
+ const QStringList &/*invalidated_properties*/,
+ const QDBusMessage &)
{
//qDebug() << "Change" << interface << changed_properties;
if (interface == QStringLiteral("org.bluez.Adapter1")) {
@@ -853,10 +499,10 @@ void QBluetoothLocalDevicePrivate::PropertiesChanged(const QString &interface,
QBluetoothLocalDevice::HostMode mode;
- if (!adapterBluez5->powered()) {
+ if (!adapter->powered()) {
mode = QBluetoothLocalDevice::HostPoweredOff;
} else {
- if (adapterBluez5->discoverable())
+ if (adapter->discoverable())
mode = QBluetoothLocalDevice::HostDiscoverable;
else
mode = QBluetoothLocalDevice::HostConnectable;
@@ -864,9 +510,9 @@ void QBluetoothLocalDevicePrivate::PropertiesChanged(const QString &interface,
if (pendingHostModeChange != -1) {
if (static_cast<int>(mode) != pendingHostModeChange) {
- adapterBluez5->setDiscoverable(
- pendingHostModeChange
- == static_cast<int>(QBluetoothLocalDevice::HostDiscoverable));
+ adapter->setDiscoverable(
+ pendingHostModeChange
+ == static_cast<int>(QBluetoothLocalDevice::HostDiscoverable));
pendingHostModeChange = -1;
return;
}
@@ -933,7 +579,7 @@ void QBluetoothLocalDevicePrivate::InterfacesAdded(const QDBusObjectPath &object
OrgBluezDevice1Interface device(QStringLiteral("org.bluez"),
object_path.path(), QDBusConnection::systemBus());
if (!address.isNull() && address == QBluetoothAddress(device.address()))
- processPairingBluez5(object_path.path(), pairing);
+ processPairing(object_path.path(), pairing);
}
}
@@ -958,15 +604,14 @@ void QBluetoothLocalDevicePrivate::InterfacesRemoved(const QDBusObjectPath &obje
}
}
- if (adapterBluez5
- && object_path.path() == adapterBluez5->path()
- && interfaces.contains(QLatin1String("org.bluez.Adapter1"))) {
- qCDebug(QT_BT_BLUEZ) << "Adapter" << adapterBluez5->path() << "was removed";
+ if (adapter && object_path.path() == adapter->path()
+ && interfaces.contains(QLatin1String("org.bluez.Adapter1"))) {
+ qCDebug(QT_BT_BLUEZ) << "Adapter" << adapter->path() << "was removed";
// current adapter was removed -> invalidate the instance
- delete adapterBluez5;
- adapterBluez5 = nullptr;
- managerBluez5->deleteLater();
- managerBluez5 = nullptr;
+ delete adapter;
+ adapter = nullptr;
+ manager->deleteLater();
+ manager = nullptr;
delete adapterProperties;
adapterProperties = nullptr;
@@ -982,153 +627,7 @@ void QBluetoothLocalDevicePrivate::InterfacesRemoved(const QDBusObjectPath &obje
bool QBluetoothLocalDevicePrivate::isValid() const
{
- return adapter || adapterBluez5;
-}
-
-// Bluez 4
-void QBluetoothLocalDevicePrivate::adapterRemoved(const QDBusObjectPath &devicePath)
-{
- if (!adapter )
- return;
-
- if (adapter->path() != devicePath.path())
- return;
-
- qCDebug(QT_BT_BLUEZ) << "Adapter" << devicePath.path()
- << "was removed. Invalidating object.";
- // the current adapter was removed
- delete adapter;
- adapter = nullptr;
- manager->deleteLater();
- manager = nullptr;
-
- // stop all pairing related activities
- if (agent) {
- QDBusConnection::systemBus().unregisterObject(agent_path);
- delete agent;
- agent = nullptr;
- }
-
- delete msgConnection;
- msgConnection = nullptr;
-
- // stop all connectivity monitoring
- qDeleteAll(devices);
- devices.clear();
- connectedDevicesSet.clear();
-}
-
-void QBluetoothLocalDevicePrivate::RequestConfirmation(const QDBusObjectPath &in0, uint in1)
-{
- Q_UNUSED(in0);
- Q_Q(QBluetoothLocalDevice);
- setDelayedReply(true);
- msgConfirmation = message();
- msgConnection = new QDBusConnection(connection());
- emit q->pairingDisplayConfirmation(address, QString::fromLatin1("%1").arg(in1));
-}
-
-void QBluetoothLocalDevicePrivate::_q_deviceCreated(const QDBusObjectPath &device)
-{
- OrgBluezDeviceInterface *deviceInterface
- = new OrgBluezDeviceInterface(QStringLiteral("org.bluez"),
- device.path(),
- QDBusConnection::systemBus(), this);
- connect(deviceInterface, &OrgBluezDeviceInterface::PropertyChanged,
- this, &QBluetoothLocalDevicePrivate::_q_devicePropertyChanged);
- devices << deviceInterface;
- QDBusPendingReply<QVariantMap> properties
- = deviceInterface->asyncCall(QStringLiteral("GetProperties"));
-
- properties.waitForFinished();
- if (!properties.isValid()) {
- qCritical() << "Unable to get device properties from: " << device.path();
- return;
- }
- const QBluetoothAddress address
- = QBluetoothAddress(properties.value().value(QStringLiteral("Address")).toString());
- const bool connected = properties.value().value(QStringLiteral("Connected")).toBool();
-
- if (connected) {
- connectedDevicesSet.insert(address);
- emit q_ptr->deviceConnected(address);
- } else {
- connectedDevicesSet.remove(address);
- emit q_ptr->deviceDisconnected(address);
- }
-}
-
-void QBluetoothLocalDevicePrivate::_q_deviceRemoved(const QDBusObjectPath &device)
-{
- for (OrgBluezDeviceInterface *deviceInterface : qAsConst(devices)) {
- if (deviceInterface->path() == device.path()) {
- devices.remove(deviceInterface);
- delete deviceInterface; // deviceDisconnected is already emitted by _q_devicePropertyChanged
- break;
- }
- }
-}
-
-void QBluetoothLocalDevicePrivate::_q_devicePropertyChanged(const QString &property,
- const QDBusVariant &value)
-{
- OrgBluezDeviceInterface *deviceInterface = qobject_cast<OrgBluezDeviceInterface *>(sender());
- if (deviceInterface && property == QLatin1String("Connected")) {
- QDBusPendingReply<QVariantMap> propertiesReply = deviceInterface->GetProperties();
- propertiesReply.waitForFinished();
- if (propertiesReply.isError()) {
- qCWarning(QT_BT_BLUEZ) << propertiesReply.error().message();
- return;
- }
- const QVariantMap properties = propertiesReply.value();
- const QBluetoothAddress address
- = QBluetoothAddress(properties.value(QStringLiteral("Address")).toString());
- const bool connected = value.variant().toBool();
-
- if (connected) {
- connectedDevicesSet.insert(address);
- emit q_ptr->deviceConnected(address);
- } else {
- connectedDevicesSet.remove(address);
- emit q_ptr->deviceDisconnected(address);
- }
- }
-}
-
-void QBluetoothLocalDevicePrivate::createCache()
-{
- if (!adapter)
- return;
-
- QDBusPendingReply<QList<QDBusObjectPath> > reply = adapter->ListDevices();
- reply.waitForFinished();
- if (reply.isError()) {
- qCWarning(QT_BT_BLUEZ) << reply.error().message();
- return;
- }
- const QList<QDBusObjectPath> knownDevices = reply.value();
- for (const QDBusObjectPath &device : knownDevices) {
- OrgBluezDeviceInterface *deviceInterface =
- new OrgBluezDeviceInterface(QStringLiteral("org.bluez"),
- device.path(),
- QDBusConnection::systemBus(), this);
- connect(deviceInterface, &OrgBluezDeviceInterface::PropertyChanged,
- this, &QBluetoothLocalDevicePrivate::_q_devicePropertyChanged);
- devices << deviceInterface;
-
- QDBusPendingReply<QVariantMap> properties
- = deviceInterface->asyncCall(QStringLiteral("GetProperties"));
- properties.waitForFinished();
- if (!properties.isValid()) {
- qCWarning(QT_BT_BLUEZ) << "Unable to get properties for device " << device.path();
- return;
- }
-
- if (properties.value().value(QStringLiteral("Connected")).toBool()) {
- connectedDevicesSet.insert(
- QBluetoothAddress(properties.value().value(QStringLiteral("Address")).toString()));
- }
- }
+ return adapter && manager;
}
QList<QBluetoothAddress> QBluetoothLocalDevicePrivate::connectedDevices() const
@@ -1136,39 +635,6 @@ QList<QBluetoothAddress> QBluetoothLocalDevicePrivate::connectedDevices() const
return connectedDevicesSet.values();
}
-void QBluetoothLocalDevice::pairingConfirmation(bool confirmation)
-{
- if (!d_ptr
- || !d_ptr->msgConfirmation.isReplyRequired()
- || !d_ptr->msgConnection)
- return;
-
- if (confirmation) {
- QDBusMessage msg = d_ptr->msgConfirmation.createReply(QVariant(true));
- d_ptr->msgConnection->send(msg);
- } else {
- QDBusMessage error
- = d_ptr->msgConfirmation.createErrorReply(QDBusError::AccessDenied,
- QStringLiteral("Pairing rejected"));
- d_ptr->msgConnection->send(error);
- }
- delete d_ptr->msgConnection;
- d_ptr->msgConnection = nullptr;
-}
-
-QString QBluetoothLocalDevicePrivate::RequestPinCode(const QDBusObjectPath &in0)
-{
- Q_UNUSED(in0)
- Q_Q(QBluetoothLocalDevice);
- qCDebug(QT_BT_BLUEZ) << Q_FUNC_INFO << in0.path();
- // seeded in constructor, 6 digit pin
- QString pin = QString::fromLatin1("%1").arg(QRandomGenerator::global()->bounded(1000000));
- pin = QString::fromLatin1("%1").arg(pin, 6, QLatin1Char('0'));
-
- emit q->pairingDisplayPinCode(address, pin);
- return pin;
-}
-
void QBluetoothLocalDevicePrivate::pairingCompleted(QDBusPendingCallWatcher *watcher)
{
Q_Q(QBluetoothLocalDevice);
@@ -1176,44 +642,30 @@ void QBluetoothLocalDevicePrivate::pairingCompleted(QDBusPendingCallWatcher *wat
if (reply.isError()) {
qCWarning(QT_BT_BLUEZ) << "Failed to create pairing" << reply.error().name();
- if (reply.error().name() != QStringLiteral("org.bluez.Error.AuthenticationCanceled"))
- emit q->error(QBluetoothLocalDevice::PairingError);
+ const bool canceledByUs =
+ (reply.error().name() == QStringLiteral("org.bluez.Error.AuthenticationCanceled"))
+ && pairingRequestCanceled;
+ if (!canceledByUs)
+ emit q->errorOccurred(QBluetoothLocalDevice::PairingError);
+
+ pairingRequestCanceled = false;
watcher->deleteLater();
return;
}
- if (adapter) {
- QDBusPendingReply<QDBusObjectPath> findReply = adapter->FindDevice(address.toString());
- findReply.waitForFinished();
- if (findReply.isError()) {
- qCWarning(QT_BT_BLUEZ) << Q_FUNC_INFO << "failed to find device" << findReply.error();
- emit q->error(QBluetoothLocalDevice::PairingError);
- watcher->deleteLater();
- return;
- }
-
- OrgBluezDeviceInterface device(QStringLiteral("org.bluez"), findReply.value().path(),
- QDBusConnection::systemBus());
+ pairingRequestCanceled = false;
- if (pairing == QBluetoothLocalDevice::AuthorizedPaired) {
- device.SetProperty(QStringLiteral("Trusted"), QDBusVariant(QVariant(true)));
- emit q->pairingFinished(address, QBluetoothLocalDevice::AuthorizedPaired);
- }
- else {
- device.SetProperty(QStringLiteral("Trusted"), QDBusVariant(QVariant(false)));
- emit q->pairingFinished(address, QBluetoothLocalDevice::Paired);
- }
- } else if (adapterBluez5) {
+ if (adapter) {
if (!pairingTarget) {
qCWarning(QT_BT_BLUEZ) << "Pairing target expected but found null pointer.";
- emit q->error(QBluetoothLocalDevice::PairingError);
+ emit q->errorOccurred(QBluetoothLocalDevice::PairingError);
watcher->deleteLater();
return;
}
if (!pairingTarget->paired()) {
qCWarning(QT_BT_BLUEZ) << "Device was not paired as requested";
- emit q->error(QBluetoothLocalDevice::PairingError);
+ emit q->errorOccurred(QBluetoothLocalDevice::PairingError);
watcher->deleteLater();
return;
}
@@ -1234,101 +686,6 @@ void QBluetoothLocalDevicePrivate::pairingCompleted(QDBusPendingCallWatcher *wat
watcher->deleteLater();
}
-void QBluetoothLocalDevicePrivate::Authorize(const QDBusObjectPath &in0, const QString &in1)
-{
- Q_UNUSED(in0)
- Q_UNUSED(in1)
- // TODO implement this
- qCDebug(QT_BT_BLUEZ) << "Got authorize for" << in0.path() << in1;
-}
-
-void QBluetoothLocalDevicePrivate::Cancel()
-{
- // TODO implement this
- qCDebug(QT_BT_BLUEZ) << Q_FUNC_INFO;
-}
-
-void QBluetoothLocalDevicePrivate::Release()
-{
- // TODO implement this
- qCDebug(QT_BT_BLUEZ) << Q_FUNC_INFO;
-}
-
-void QBluetoothLocalDevicePrivate::ConfirmModeChange(const QString &in0)
-{
- Q_UNUSED(in0)
- // TODO implement this
- qCDebug(QT_BT_BLUEZ) << Q_FUNC_INFO << in0;
-}
-
-void QBluetoothLocalDevicePrivate::DisplayPasskey(const QDBusObjectPath &in0, uint in1, uchar in2)
-{
- Q_UNUSED(in0)
- Q_UNUSED(in1)
- Q_UNUSED(in2)
- // TODO implement this
- qCDebug(QT_BT_BLUEZ) << Q_FUNC_INFO << in0.path() << in1 << in2;
-}
-
-uint QBluetoothLocalDevicePrivate::RequestPasskey(const QDBusObjectPath &in0)
-{
- Q_UNUSED(in0);
- qCDebug(QT_BT_BLUEZ) << Q_FUNC_INFO;
- return (QRandomGenerator::global()->bounded(1000000));
-}
-
-// Bluez 4
-void QBluetoothLocalDevicePrivate::PropertyChanged(QString property, QDBusVariant value)
-{
- Q_UNUSED(value);
-
- if (property != QLatin1String("Powered")
- && property != QLatin1String("Discoverable"))
- return;
-
- Q_Q(QBluetoothLocalDevice);
- QBluetoothLocalDevice::HostMode mode;
-
- QDBusPendingReply<QVariantMap> reply = adapter->GetProperties();
- reply.waitForFinished();
- if (reply.isError()) {
- qCWarning(QT_BT_BLUEZ) << "Failed to get bluetooth properties for mode change";
- return;
- }
-
- QVariantMap map = reply.value();
-
- if (!map.value(QStringLiteral("Powered")).toBool()) {
- mode = QBluetoothLocalDevice::HostPoweredOff;
- } else {
- if (map.value(QStringLiteral("Discoverable")).toBool())
- mode = QBluetoothLocalDevice::HostDiscoverable;
- else
- mode = QBluetoothLocalDevice::HostConnectable;
-
- if (pendingHostModeChange != -1) {
- if ((int)mode != pendingHostModeChange) {
- if (property == QStringLiteral("Powered"))
- return;
- if (pendingHostModeChange == (int)QBluetoothLocalDevice::HostDiscoverable) {
- adapter->SetProperty(QStringLiteral("Discoverable"),
- QDBusVariant(QVariant::fromValue(true)));
- } else {
- adapter->SetProperty(QStringLiteral("Discoverable"),
- QDBusVariant(QVariant::fromValue(false)));
- }
- pendingHostModeChange = -1;
- return;
- }
- }
- }
-
- if (mode != currentMode)
- emit q->hostModeStateChanged(mode);
-
- currentMode = mode;
-}
+QT_END_NAMESPACE
#include "moc_qbluetoothlocaldevice_p.cpp"
-
-QT_END_NAMESPACE
diff --git a/src/bluetooth/qbluetoothlocaldevice_macos.mm b/src/bluetooth/qbluetoothlocaldevice_macos.mm
index ec2accce..3d1da5ea 100644
--- a/src/bluetooth/qbluetoothlocaldevice_macos.mm
+++ b/src/bluetooth/qbluetoothlocaldevice_macos.mm
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "darwin/btconnectionmonitor_p.h"
#include "qbluetoothlocaldevice_p.h"
@@ -68,6 +32,7 @@ public:
QBluetoothLocalDevicePrivate(QBluetoothLocalDevice *, const QBluetoothAddress & =
QBluetoothAddress());
+ ~QBluetoothLocalDevicePrivate();
bool isValid() const;
void requestPairing(const QBluetoothAddress &address, Pairing pairing);
@@ -99,13 +64,11 @@ private:
using HostController = DarwinBluetooth::ObjCScopedPointer<IOBluetoothHostController>;
HostController hostController;
- using ObjCPairingRequest = QT_MANGLE_NAMESPACE(DarwinBTClassicPairing);
- using PairingRequest = DarwinBluetooth::ObjCStrongReference<ObjCPairingRequest>;
+ using PairingRequest = DarwinBluetooth::ObjCStrongReference<DarwinBTClassicPairing>;
using RequestMap = QMap<QBluetoothAddress, PairingRequest>;
RequestMap pairingRequests;
- using ObjCConnectionMonitor = QT_MANGLE_NAMESPACE(DarwinBTConnectionMonitor);
- DarwinBluetooth::ObjCScopedPointer<ObjCConnectionMonitor> connectionMonitor;
+ DarwinBluetooth::ObjCScopedPointer<DarwinBTConnectionMonitor> connectionMonitor;
QList<QBluetoothAddress> discoveredDevices;
};
@@ -114,7 +77,6 @@ QBluetoothLocalDevicePrivate::QBluetoothLocalDevicePrivate(QBluetoothLocalDevice
q_ptr(q)
{
registerQBluetoothLocalDeviceMetaType();
-
Q_ASSERT_X(q, Q_FUNC_INFO, "invalid q_ptr (null)");
QT_BT_MAC_AUTORELEASEPOOL;
@@ -149,10 +111,16 @@ QBluetoothLocalDevicePrivate::QBluetoothLocalDevicePrivate(QBluetoothLocalDevice
defaultController.swap(hostController);
// This one is optional, if it fails to initialize, we do not care at all.
- connectionMonitor.reset([[ObjCConnectionMonitor alloc] initWithMonitor:this],
+ connectionMonitor.reset([[DarwinBTConnectionMonitor alloc] initWithMonitor:this],
DarwinBluetooth::RetainPolicy::noInitialRetain);
}
+QBluetoothLocalDevicePrivate::~QBluetoothLocalDevicePrivate()
+{
+
+ [connectionMonitor stopMonitoring];
+}
+
bool QBluetoothLocalDevicePrivate::isValid() const
{
return hostController;
@@ -195,7 +163,7 @@ void QBluetoothLocalDevicePrivate::requestPairing(const QBluetoothAddress &addre
// That's a totally new request ('Paired', since we are here).
// Even if this device is paired (not by our local device), I still create a pairing request,
// it'll just finish with success (skipping any intermediate steps).
- PairingRequest newRequest([[ObjCPairingRequest alloc] initWithTarget:address delegate:this],
+ PairingRequest newRequest([[DarwinBTClassicPairing alloc] initWithTarget:address delegate:this],
RetainPolicy::noInitialRetain);
if (!newRequest) {
qCCritical(QT_BT_DARWIN) << "failed to allocate a new pairing request";
@@ -241,40 +209,40 @@ QBluetoothLocalDevice::Pairing QBluetoothLocalDevicePrivate::pairingStatus(const
void QBluetoothLocalDevicePrivate::connecting(void *pair)
{
// TODO: why unused and if cannot be used - remove?
- Q_UNUSED(pair)
+ Q_UNUSED(pair);
}
void QBluetoothLocalDevicePrivate::requestPIN(void *pair)
{
// TODO: why unused and if cannot be used - remove?
- Q_UNUSED(pair)
+ Q_UNUSED(pair);
}
void QBluetoothLocalDevicePrivate::requestUserConfirmation(void *pair, BluetoothNumericValue intPin)
{
// TODO: why unused and if cannot be used - remove?
- Q_UNUSED(pair)
- Q_UNUSED(intPin)
+ Q_UNUSED(pair);
+ Q_UNUSED(intPin);
}
void QBluetoothLocalDevicePrivate::passkeyNotification(void *pair, BluetoothPasskey passkey)
{
// TODO: why unused and if cannot be used - remove?
- Q_UNUSED(pair)
- Q_UNUSED(passkey)
+ Q_UNUSED(pair);
+ Q_UNUSED(passkey);
}
void QBluetoothLocalDevicePrivate::error(void *pair, IOReturn errorCode)
{
- Q_UNUSED(pair)
- Q_UNUSED(errorCode)
+ Q_UNUSED(pair);
+ Q_UNUSED(errorCode);
emitError(QBluetoothLocalDevice::PairingError, false);
}
void QBluetoothLocalDevicePrivate::pairingFinished(void *generic)
{
- auto pair = static_cast<ObjCPairingRequest *>(generic);
+ auto pair = static_cast<DarwinBTClassicPairing *>(generic);
Q_ASSERT_X(pair, Q_FUNC_INFO, "invalid pairing request (nil)");
const QBluetoothAddress &deviceAddress = [pair targetAddress];
@@ -309,10 +277,10 @@ void QBluetoothLocalDevicePrivate::deviceDisconnected(const QBluetoothAddress &d
void QBluetoothLocalDevicePrivate::emitError(QBluetoothLocalDevice::Error error, bool queued)
{
if (queued) {
- QMetaObject::invokeMethod(q_ptr, "error", Qt::QueuedConnection,
+ QMetaObject::invokeMethod(q_ptr, "errorOccurred", Qt::QueuedConnection,
Q_ARG(QBluetoothLocalDevice::Error, error));
} else {
- emit q_ptr->error(QBluetoothLocalDevice::PairingError);
+ emit q_ptr->errorOccurred(QBluetoothLocalDevice::PairingError);
}
}
@@ -399,7 +367,7 @@ void QBluetoothLocalDevice::powerOn()
void QBluetoothLocalDevice::setHostMode(QBluetoothLocalDevice::HostMode mode)
{
- Q_UNUSED(mode)
+ Q_UNUSED(mode);
if (!isValid())
qCWarning(QT_BT_DARWIN) << Q_FUNC_INFO << "invalid local device";
@@ -447,7 +415,7 @@ QList<QBluetoothHostInfo> QBluetoothLocalDevice::allDevices()
QBluetoothLocalDevice defaultAdapter;
if (!defaultAdapter.isValid() || defaultAdapter.address().isNull()) {
- qCCritical(QT_BT_DARWIN) << Q_FUNC_INFO <<"no valid device found";
+ qCWarning(QT_BT_DARWIN) << Q_FUNC_INFO <<"no valid device found";
return localDevices;
}
@@ -460,12 +428,6 @@ QList<QBluetoothHostInfo> QBluetoothLocalDevice::allDevices()
return localDevices;
}
-void QBluetoothLocalDevice::pairingConfirmation(bool confirmation)
-{
- Q_UNUSED(confirmation)
-}
-
-
void QBluetoothLocalDevice::requestPairing(const QBluetoothAddress &address, Pairing pairing)
{
if (!isValid())
diff --git a/src/bluetooth/qbluetoothlocaldevice_p.cpp b/src/bluetooth/qbluetoothlocaldevice_p.cpp
index fa4a509e..189da707 100644
--- a/src/bluetooth/qbluetoothlocaldevice_p.cpp
+++ b/src/bluetooth/qbluetoothlocaldevice_p.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qbluetoothlocaldevice.h"
#include "qbluetoothaddress.h"
@@ -103,7 +67,7 @@ void QBluetoothLocalDevice::requestPairing(const QBluetoothAddress &address, Pai
{
Q_UNUSED(address);
Q_UNUSED(pairing);
- QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection,
+ QMetaObject::invokeMethod(this, "errorOccurred", Qt::QueuedConnection,
Q_ARG(QBluetoothLocalDevice::Error,
QBluetoothLocalDevice::PairingError));
}
@@ -115,9 +79,4 @@ QBluetoothLocalDevice::Pairing QBluetoothLocalDevice::pairingStatus(
return Unpaired;
}
-void QBluetoothLocalDevice::pairingConfirmation(bool confirmation)
-{
- Q_UNUSED(confirmation);
-}
-
QT_END_NAMESPACE
diff --git a/src/bluetooth/qbluetoothlocaldevice_p.h b/src/bluetooth/qbluetoothlocaldevice_p.h
index d86ab22f..d0dad8d7 100644
--- a/src/bluetooth/qbluetoothlocaldevice_p.h
+++ b/src/bluetooth/qbluetoothlocaldevice_p.h
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2014 Denis Shienkov <denis.shienkov@gmail.com>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2014 Denis Shienkov <denis.shienkov@gmail.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QBLUETOOTHLOCALDEVICE_P_H
#define QBLUETOOTHLOCALDEVICE_P_H
@@ -58,48 +22,36 @@
#if QT_CONFIG(bluez)
#include <QObject>
-#include <QDBusContext>
#include <QDBusObjectPath>
#include <QDBusMessage>
#include <QSet>
#include "bluez/bluez5_helper_p.h"
-class OrgBluezAdapterInterface;
class OrgBluezAdapter1Interface;
class OrgFreedesktopDBusPropertiesInterface;
class OrgFreedesktopDBusObjectManagerInterface;
-class OrgBluezAgentAdaptor;
-class OrgBluezDeviceInterface;
class OrgBluezDevice1Interface;
-class OrgBluezManagerInterface;
QT_BEGIN_NAMESPACE
class QDBusPendingCallWatcher;
QT_END_NAMESPACE
#endif
+#ifdef QT_WINRT_BLUETOOTH
+#include "qbluetoothutils_winrt_p.h"
+#include <winrt/Windows.Devices.Bluetooth.h>
+QT_BEGIN_NAMESPACE
+struct PairingWorker;
+QT_END_NAMESPACE
+#endif
+
#ifdef QT_ANDROID_BLUETOOTH
#include <jni.h>
-#include <QtAndroidExtras/QAndroidJniEnvironment>
-#include <QtAndroidExtras/QAndroidJniObject>
+#include <QtCore/QJniEnvironment>
+#include <QtCore/QJniObject>
#include <QtCore/QPair>
#endif
-#ifdef QT_WINRT_BLUETOOTH
-#include <wrl.h>
-
-namespace ABI {
- namespace Windows {
- namespace Devices {
- namespace Bluetooth {
- struct IBluetoothDeviceStatics;
- struct IBluetoothLEDeviceStatics;
- }
- }
- }
-}
-#endif
-
QT_BEGIN_NAMESPACE
extern void registerQBluetoothLocalDeviceMetaType();
@@ -116,7 +68,7 @@ public:
QBluetoothLocalDevice *q, const QBluetoothAddress &address = QBluetoothAddress());
~QBluetoothLocalDevicePrivate();
- QAndroidJniObject *adapter();
+ QJniObject *adapter();
void initialize(const QBluetoothAddress &address);
static bool startDiscovery();
static bool cancelDiscovery();
@@ -128,24 +80,23 @@ private slots:
void processPairingStateChanged(const QBluetoothAddress &address,
QBluetoothLocalDevice::Pairing pairing);
void processConnectDeviceChanges(const QBluetoothAddress &address, bool isConnectEvent);
- void processDisplayConfirmation(const QBluetoothAddress &address, const QString &pin);
private:
QBluetoothLocalDevice *q_ptr;
- QAndroidJniObject *obj = nullptr;
+ QJniObject *obj = nullptr;
int pendingPairing(const QBluetoothAddress &address);
public:
LocalDeviceBroadcastReceiver *receiver;
- bool pendingHostModeTransition = false;
+ bool pendingConnectableHostModeTransition = false;
QList<QPair<QBluetoothAddress, bool> > pendingPairings;
QList<QBluetoothAddress> connectedDevices;
};
#elif QT_CONFIG(bluez)
-class QBluetoothLocalDevicePrivate : public QObject, protected QDBusContext
+class QBluetoothLocalDevicePrivate : public QObject
{
Q_OBJECT
Q_DECLARE_PUBLIC(QBluetoothLocalDevice)
@@ -154,19 +105,14 @@ public:
QBluetoothAddress localAddress = QBluetoothAddress());
~QBluetoothLocalDevicePrivate();
- QSet<OrgBluezDeviceInterface *> devices;
QSet<QBluetoothAddress> connectedDevicesSet;
- OrgBluezAdapterInterface *adapter = nullptr; //Bluez 4
- OrgBluezAdapter1Interface *adapterBluez5 = nullptr; //Bluez 5
- OrgFreedesktopDBusPropertiesInterface *adapterProperties = nullptr; //Bluez 5
- OrgFreedesktopDBusObjectManagerInterface *managerBluez5 = nullptr; //Bluez 5
- QMap<QString, OrgFreedesktopDBusPropertiesInterface *> deviceChangeMonitors; //Bluez 5
- OrgBluezAgentAdaptor *agent = nullptr;
- OrgBluezManagerInterface *manager = nullptr;
+ OrgBluezAdapter1Interface *adapter = nullptr;
+ OrgFreedesktopDBusPropertiesInterface *adapterProperties = nullptr;
+ OrgFreedesktopDBusObjectManagerInterface *manager = nullptr;
+ QMap<QString, OrgFreedesktopDBusPropertiesInterface *> deviceChangeMonitors;
QList<QBluetoothAddress> connectedDevices() const;
- QString agent_path;
QBluetoothAddress localAddress;
QBluetoothAddress address;
QBluetoothLocalDevice::Pairing pairing;
@@ -174,81 +120,42 @@ public:
QTimer *pairingDiscoveryTimer = nullptr;
QBluetoothLocalDevice::HostMode currentMode;
int pendingHostModeChange;
+ bool pairingRequestCanceled = false;
public slots:
- void Authorize(const QDBusObjectPath &in0, const QString &in1);
- void Cancel();
- void ConfirmModeChange(const QString &in0);
- void DisplayPasskey(const QDBusObjectPath &in0, uint in1, uchar in2);
- void Release();
- uint RequestPasskey(const QDBusObjectPath &in0);
-
- void RequestConfirmation(const QDBusObjectPath &in0, uint in1);
- QString RequestPinCode(const QDBusObjectPath &in0);
-
void pairingCompleted(QDBusPendingCallWatcher *);
- void PropertyChanged(QString, QDBusVariant);
- void _q_deviceCreated(const QDBusObjectPath &device);
- void _q_deviceRemoved(const QDBusObjectPath &device);
- void _q_devicePropertyChanged(const QString &property, const QDBusVariant &value);
bool isValid() const;
- void adapterRemoved(const QDBusObjectPath &device);
- void requestPairingBluez5(const QBluetoothAddress &address,
- QBluetoothLocalDevice::Pairing targetPairing);
+ void requestPairing(const QBluetoothAddress &address,
+ QBluetoothLocalDevice::Pairing targetPairing);
private Q_SLOTS:
void PropertiesChanged(const QString &interface,
const QVariantMap &changed_properties,
- const QStringList &invalidated_properties);
+ const QStringList &invalidated_properties,
+ const QDBusMessage &signal);
void InterfacesAdded(const QDBusObjectPath &object_path,
InterfaceList interfaces_and_properties);
void InterfacesRemoved(const QDBusObjectPath &object_path,
const QStringList &interfaces);
- void processPairingBluez5(const QString &objectPath,
- QBluetoothLocalDevice::Pairing target);
+ void processPairing(const QString &objectPath, QBluetoothLocalDevice::Pairing target);
void pairingDiscoveryTimedOut();
private:
- void createCache();
void connectDeviceChanges();
- QDBusMessage msgConfirmation;
- QDBusConnection *msgConnection = nullptr;
QString deviceAdapterPath;
QBluetoothLocalDevice *q_ptr;
void initializeAdapter();
- void initializeAdapterBluez5();
};
-#elif defined(QT_WIN_BLUETOOTH)
-
-class QBluetoothLocalDevicePrivate : public QObject
-{
- Q_OBJECT
- Q_DECLARE_PUBLIC(QBluetoothLocalDevice)
-public:
- QBluetoothLocalDevicePrivate(QBluetoothLocalDevice *q,
- const QBluetoothAddress &address = QBluetoothAddress());
-
- ~QBluetoothLocalDevicePrivate();
- bool isValid() const;
- void initialize(const QBluetoothAddress &address);
-
- static QList<QBluetoothHostInfo> localAdapters();
-
- QBluetoothAddress deviceAddress;
- QString deviceName;
- bool deviceValid;
-private:
- QBluetoothLocalDevice *q_ptr;
-};
#elif defined(QT_WINRT_BLUETOOTH)
class QBluetoothLocalDevicePrivate : public QObject
{
+ Q_OBJECT
Q_DECLARE_PUBLIC(QBluetoothLocalDevice)
public:
QBluetoothLocalDevicePrivate(QBluetoothLocalDevice *q,
@@ -257,10 +164,23 @@ public:
bool isValid() const;
-private:
+ void updateAdapterState(QBluetoothLocalDevice::HostMode mode);
+ Q_SLOT void onAdapterRemoved(winrt::hstring id);
+ Q_SLOT void onAdapterAdded(winrt::hstring id);
+ Q_SLOT void radioModeChanged(winrt::hstring id, QBluetoothLocalDevice::HostMode mode);
+ Q_SLOT void onDeviceAdded(const QBluetoothAddress &address);
+ Q_SLOT void onDeviceRemoved(const QBluetoothAddress &address);
+
QBluetoothLocalDevice *q_ptr;
- Microsoft::WRL::ComPtr<ABI::Windows::Devices::Bluetooth::IBluetoothDeviceStatics> mStatics;
- Microsoft::WRL::ComPtr<ABI::Windows::Devices::Bluetooth::IBluetoothLEDeviceStatics> mLEStatics;
+ winrt::com_ptr<PairingWorker> mPairingWorker;
+ winrt::Windows::Devices::Bluetooth::BluetoothAdapter mAdapter;
+ winrt::hstring mDeviceId;
+ QString mAdapterName;
+ QBluetoothLocalDevice::HostMode mMode;
+ winrt::event_token mModeChangeToken;
+
+signals:
+ void updateMode(winrt::hstring id, QBluetoothLocalDevice::HostMode mode);
};
#elif !defined(QT_OSX_BLUETOOTH) // dummy backend
class QBluetoothLocalDevicePrivate : public QObject
diff --git a/src/bluetooth/qbluetoothlocaldevice_win.cpp b/src/bluetooth/qbluetoothlocaldevice_win.cpp
deleted file mode 100644
index cf17cad1..00000000
--- a/src/bluetooth/qbluetoothlocaldevice_win.cpp
+++ /dev/null
@@ -1,260 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Copyright (C) 2014 Denis Shienkov <denis.shienkov@gmail.com>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qbluetoothlocaldevice.h"
-#include "qbluetoothaddress.h"
-
-#include "qbluetoothlocaldevice_p.h"
-
-#include <QtCore/QLoggingCategory>
-
-#include <qt_windows.h>
-#include <bluetoothapis.h>
-
-QT_BEGIN_NAMESPACE
-
-Q_DECLARE_LOGGING_CATEGORY(QT_BT_WINDOWS)
-
-QBluetoothLocalDevice::QBluetoothLocalDevice(QObject *parent) :
- QObject(parent),
- d_ptr(new QBluetoothLocalDevicePrivate(this))
-{
-}
-
-QBluetoothLocalDevice::QBluetoothLocalDevice(
- const QBluetoothAddress &address, QObject *parent) :
- QObject(parent),
- d_ptr(new QBluetoothLocalDevicePrivate(this, address))
-{
-}
-
-QString QBluetoothLocalDevice::name() const
-{
- Q_D(const QBluetoothLocalDevice);
- return d->deviceName;
-}
-
-QBluetoothAddress QBluetoothLocalDevice::address() const
-{
- Q_D(const QBluetoothLocalDevice);
- return d->deviceAddress;
-}
-
-void QBluetoothLocalDevice::powerOn()
-{
- if (hostMode() != HostPoweredOff)
- return;
-
- setHostMode(HostConnectable);
-}
-
-void QBluetoothLocalDevice::setHostMode(
- QBluetoothLocalDevice::HostMode requestedMode)
-{
- if (!isValid()) {
- qCWarning(QT_BT_WINDOWS) << "The local device is not initialized correctly";
- return;
- }
-
- if (requestedMode == HostDiscoverableLimitedInquiry)
- requestedMode = HostDiscoverable;
-
- if (requestedMode == hostMode())
- return;
-
- if (requestedMode == QBluetoothLocalDevice::HostPoweredOff) {
- if (::BluetoothIsDiscoverable(nullptr)
- && !::BluetoothEnableDiscovery(nullptr, FALSE)) {
- qCWarning(QT_BT_WINDOWS) << "Unable to disable the discoverable mode";
- emit error(QBluetoothLocalDevice::UnknownError);
- return;
- }
- if (::BluetoothIsConnectable(nullptr)
- && !::BluetoothEnableIncomingConnections(nullptr, FALSE)) {
- qCWarning(QT_BT_WINDOWS) << "Unable to disable the connectable mode";
- emit error(QBluetoothLocalDevice::UnknownError);
- return;
- }
- } else if (requestedMode == QBluetoothLocalDevice::HostConnectable) {
- if (!::BluetoothIsConnectable(nullptr)
- && !::BluetoothEnableIncomingConnections(nullptr, TRUE)) {
- qCWarning(QT_BT_WINDOWS) << "Unable to enable the connectable mode";
- emit error(QBluetoothLocalDevice::UnknownError);
- return;
- }
- } else if (requestedMode == QBluetoothLocalDevice::HostDiscoverable
- || requestedMode == QBluetoothLocalDevice::HostDiscoverableLimitedInquiry) {
- if (!::BluetoothIsConnectable(nullptr)
- && !::BluetoothEnableIncomingConnections(nullptr, TRUE)) {
- qCWarning(QT_BT_WINDOWS) << "Unable to enable the connectable mode";
- emit error(QBluetoothLocalDevice::UnknownError);
- return;
- }
- if (!::BluetoothEnableDiscovery(nullptr, TRUE)) {
- qCWarning(QT_BT_WINDOWS) << "Unable to enable the discoverable mode";
- emit error(QBluetoothLocalDevice::UnknownError);
- return;
- }
- }
-
- emit hostModeStateChanged(requestedMode);
-}
-
-QBluetoothLocalDevice::HostMode QBluetoothLocalDevice::hostMode() const
-{
- if (!isValid()) {
- qCWarning(QT_BT_WINDOWS) << "The local device is not initialized correctly";
- return HostPoweredOff;
- }
-
- if (::BluetoothIsDiscoverable(nullptr))
- return HostDiscoverable;
- if (::BluetoothIsConnectable(nullptr))
- return HostConnectable;
- return HostPoweredOff;
-}
-
-QList<QBluetoothAddress> QBluetoothLocalDevice::connectedDevices() const
-{
- return QList<QBluetoothAddress>();
-}
-
-QList<QBluetoothHostInfo> QBluetoothLocalDevice::allDevices()
-{
- return QBluetoothLocalDevicePrivate::localAdapters();
-}
-
-void QBluetoothLocalDevice::requestPairing(const QBluetoothAddress &address, Pairing pairing)
-{
- Q_UNUSED(address);
- Q_UNUSED(pairing);
- Q_UNIMPLEMENTED();
-}
-
-QBluetoothLocalDevice::Pairing QBluetoothLocalDevice::pairingStatus(
- const QBluetoothAddress &address) const
-{
- Q_UNUSED(address);
- Q_UNIMPLEMENTED();
- return Unpaired;
-}
-
-void QBluetoothLocalDevice::pairingConfirmation(bool confirmation)
-{
- Q_UNUSED(confirmation);
- Q_UNIMPLEMENTED();
-}
-
-QBluetoothLocalDevicePrivate::QBluetoothLocalDevicePrivate(
- QBluetoothLocalDevice *q, const QBluetoothAddress &address)
- : deviceValid(false)
- , q_ptr(q)
-{
- initialize(address);
-}
-
-QBluetoothLocalDevicePrivate::~QBluetoothLocalDevicePrivate()
-{
-}
-
-bool QBluetoothLocalDevicePrivate::isValid() const
-{
- return deviceValid;
-}
-
-void QBluetoothLocalDevicePrivate::initialize(const QBluetoothAddress &address)
-{
- Q_Q(QBluetoothLocalDevice);
-
- const QList<QBluetoothHostInfo> adapterInfos = QBluetoothLocalDevicePrivate::localAdapters();
- for (const QBluetoothHostInfo &adapterInfo : adapterInfos) {
- if (address == QBluetoothAddress()
- || address == adapterInfo.address()) {
- deviceAddress = adapterInfo.address();
- deviceName = adapterInfo.name();
- deviceValid = true;
- return;
- }
- }
-
- qCWarning(QT_BT_WINDOWS) << "Unable to find classic local radio: " << address;
- QMetaObject::invokeMethod(q, "error", Qt::QueuedConnection,
- Q_ARG(QBluetoothLocalDevice::Error,
- QBluetoothLocalDevice::UnknownError));
-}
-
-QList<QBluetoothHostInfo> QBluetoothLocalDevicePrivate::localAdapters()
-{
- BLUETOOTH_FIND_RADIO_PARAMS params;
- ::ZeroMemory(&params, sizeof(params));
- params.dwSize = sizeof(params);
-
- QList<QBluetoothHostInfo> foundAdapters;
-
- HANDLE hRadio = nullptr;
- if (const HBLUETOOTH_RADIO_FIND hSearch = ::BluetoothFindFirstRadio(&params, &hRadio)) {
- for (;;) {
- BLUETOOTH_RADIO_INFO radio;
- ::ZeroMemory(&radio, sizeof(radio));
- radio.dwSize = sizeof(radio);
-
- const DWORD retval = ::BluetoothGetRadioInfo(hRadio, &radio);
- ::CloseHandle(hRadio);
-
- if (retval != ERROR_SUCCESS)
- break;
-
- QBluetoothHostInfo adapterInfo;
- adapterInfo.setAddress(QBluetoothAddress(radio.address.ullLong));
- adapterInfo.setName(QString::fromWCharArray(radio.szName));
-
- foundAdapters << adapterInfo;
-
- if (!::BluetoothFindNextRadio(hSearch, &hRadio))
- break;
- }
-
- ::BluetoothFindRadioClose(hSearch);
- }
-
- return foundAdapters;
-}
-
-QT_END_NAMESPACE
diff --git a/src/bluetooth/qbluetoothlocaldevice_winrt.cpp b/src/bluetooth/qbluetoothlocaldevice_winrt.cpp
index 6e8b1966..ec0787dd 100644
--- a/src/bluetooth/qbluetoothlocaldevice_winrt.cpp
+++ b/src/bluetooth/qbluetoothlocaldevice_winrt.cpp
@@ -1,96 +1,554 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <private/qbluetoothutils_winrt_p.h>
#include "qbluetoothlocaldevice.h"
#include "qbluetoothaddress.h"
+#include "qbluetoothdevicewatcher_winrt_p.h"
#include "qbluetoothlocaldevice_p.h"
+#include "qbluetoothutils_winrt_p.h"
-#ifdef CLASSIC_APP_BUILD
-#define Q_OS_WINRT
-#endif
-#include <QtCore/qfunctions_winrt.h>
+#include <winrt/Windows.Foundation.h>
+#include <winrt/Windows.Foundation.Collections.h>
+#include <winrt/Windows.Devices.Enumeration.h>
+#include <winrt/Windows.Devices.Bluetooth.h>
+#include <winrt/Windows.Devices.Radios.h>
-#include <robuffer.h>
-#include <windows.devices.bluetooth.h>
-#include <wrl.h>
+#include <QtCore/QCoreApplication>
+#include <QtCore/QElapsedTimer>
+#include <QtCore/QLoggingCategory>
+#include <QtCore/QMutex>
+#include <QtCore/QPointer>
+#include <QtCore/QTimer>
-using namespace ABI::Windows::Foundation;
-using namespace ABI::Windows::Devices::Bluetooth;
-using namespace ABI::Windows::Devices::Enumeration;
-using namespace Microsoft::WRL;
-using namespace Microsoft::WRL::Wrappers;
+using namespace winrt::Windows::Foundation;
+using namespace winrt::Windows::Foundation::Collections;
+using namespace winrt::Windows::Devices::Enumeration;
+using namespace winrt::Windows::Devices::Bluetooth;
+using namespace winrt::Windows::Devices::Radios;
QT_BEGIN_NAMESPACE
-template <class DeviceStatics, class OpResult, class Device, class Device2>
-ComPtr<IDeviceInformationPairing> getPairingInfo(ComPtr<DeviceStatics> deviceStatics,
- const QBluetoothAddress &address)
-{
- ComPtr<IAsyncOperation<OpResult *>> op;
- if (!deviceStatics)
- return nullptr;
- HRESULT hr = deviceStatics->FromBluetoothAddressAsync(address.toUInt64(), &op);
- RETURN_IF_FAILED("Could not obtain device from address", return nullptr);
- ComPtr<Device> device;
- hr = QWinRTFunctions::await(op, device.GetAddressOf(),
- QWinRTFunctions::ProcessMainThreadEvents, 5000);
- if (FAILED(hr) || !device) {
- qErrnoWarning("Could not obtain device from address");
- return nullptr;
- }
- ComPtr<Device2> device2;
- hr = device.As(&device2);
- RETURN_IF_FAILED("Could not cast device", return nullptr);
- ComPtr<IDeviceInformation> deviceInfo;
- hr = device2->get_DeviceInformation(&deviceInfo);
- if (FAILED(hr) || !deviceInfo) {
- qErrnoWarning("Could not obtain device information");
- return nullptr;
- }
- ComPtr<IDeviceInformation2> deviceInfo2;
- hr = deviceInfo.As(&deviceInfo2);
- RETURN_IF_FAILED("Could not cast device information", return nullptr);
- ComPtr<IDeviceInformationPairing> pairingInfo;
- hr = deviceInfo2->get_Pairing(&pairingInfo);
- RETURN_IF_FAILED("Could not obtain pairing information", return nullptr);
- return pairingInfo;
+Q_DECLARE_LOGGING_CATEGORY(QT_BT_WINDOWS)
+
+template <typename T>
+static bool await(IAsyncOperation<T> &&asyncInfo, T &result, uint timeout = 0)
+{
+ using WinRtAsyncStatus = winrt::Windows::Foundation::AsyncStatus;
+ WinRtAsyncStatus status;
+ QElapsedTimer timer;
+ if (timeout)
+ timer.start();
+ do {
+ QCoreApplication::processEvents();
+ status = asyncInfo.Status();
+ } while (status == WinRtAsyncStatus::Started && (!timeout || !timer.hasExpired(timeout)));
+ if (status == WinRtAsyncStatus::Completed) {
+ result = asyncInfo.GetResults();
+ return true;
+ } else {
+ return false;
+ }
+}
+
+static QBluetoothLocalDevice::HostMode adjustHostMode(QBluetoothLocalDevice::HostMode mode)
+{
+ // Windows APIs do not seem to support HostDiscoverable and
+ // HostDiscoverableLimitedInquiry, so we just treat them as HostConnectable
+ return (mode == QBluetoothLocalDevice::HostPoweredOff)
+ ? mode : QBluetoothLocalDevice::HostConnectable;
+}
+
+static QBluetoothLocalDevice::HostMode modeFromWindowsBluetoothState(RadioState state)
+{
+ return (state == RadioState::On) ? QBluetoothLocalDevice::HostConnectable
+ : QBluetoothLocalDevice::HostPoweredOff;
+}
+
+static RadioState windowsStateFromMode(QBluetoothLocalDevice::HostMode mode)
+{
+ return (mode == QBluetoothLocalDevice::HostPoweredOff) ? RadioState::Off : RadioState::On;
+}
+
+class AdapterManager;
+
+class WatcherWrapper
+{
+public:
+ // we do not really care about unique ids here
+ WatcherWrapper(winrt::hstring selector) :
+ mWatcher(std::make_shared<QBluetoothDeviceWatcherWinRT>(0, selector))
+ {
+ }
+
+ template<typename AddedSlot, typename RemovedSlot>
+ void init(AdapterManager *manager, AddedSlot onAdded, RemovedSlot onRemoved)
+ {
+ if (!mWatcher) {
+ qWarning("QBluetoothLocalDevice: failed to create device watcher!");
+ return;
+ }
+
+ QObject::connect(mWatcher.get(), &QBluetoothDeviceWatcherWinRT::deviceAdded,
+ manager, onAdded, Qt::QueuedConnection);
+ QObject::connect(mWatcher.get(), &QBluetoothDeviceWatcherWinRT::deviceRemoved,
+ manager, onRemoved, Qt::QueuedConnection);
+
+ // This will also print a warning on failure.
+ if (mWatcher->init())
+ mWatcher->start();
+ }
+
+private:
+ std::shared_ptr<QBluetoothDeviceWatcherWinRT> mWatcher = nullptr;
+};
+
+/*
+ This class is supposed to manage winrt::Windows::Devices::Radios::Radio
+ instances. It looks like Windows behaves incorrectly when there are multiple
+ instances representing the same physical device. So this class will be a
+ single point for keeping track of all used Radios.
+ At the same time this class takes care of monitoring adapter connections
+ and disconnections.
+ Note that access to internal structs should be protected, because all
+ Windows callbacks come in separate threads. We also can't use
+ Qt::QueuedConnection to "forward" the execution to the right thread, because
+ Windows' IUnknown-based classes have a deleted operator new(), and so can't
+ be used in QMetaType.
+ However, we will still mostly use signals/slots to communicate with actual
+ QBluetoothLocalDevice instances, so we do not need any protection on that
+ side.
+*/
+class AdapterManager : public QObject
+{
+ Q_OBJECT
+public:
+ AdapterManager();
+ ~AdapterManager();
+
+ QList<QBluetoothAddress> connectedDevices();
+
+public slots:
+ QBluetoothLocalDevice::HostMode addClient(QBluetoothLocalDevicePrivate *client);
+ void removeClient(winrt::hstring adapterId);
+ void updateMode(winrt::hstring adapterId, QBluetoothLocalDevice::HostMode mode);
+
+signals:
+ void adapterAdded(winrt::hstring id);
+ void adapterRemoved(winrt::hstring id);
+ void modeChanged(winrt::hstring id, QBluetoothLocalDevice::HostMode mode);
+ void deviceAdded(const QBluetoothAddress &address);
+ void deviceRemoved(const QBluetoothAddress &address);
+
+private:
+ struct RadioInfo {
+ Radio radio = nullptr;
+ winrt::event_token stateToken;
+ int numClients = 0;
+ RadioState currentState = RadioState::Unknown;
+ };
+
+ Radio getRadioFromAdapterId(winrt::hstring id);
+ Q_SLOT void onAdapterAdded(winrt::hstring id);
+ Q_SLOT void onAdapterRemoved(winrt::hstring id);
+ void subscribeToStateChanges(RadioInfo &info);
+ void unsubscribeFromStateChanges(RadioInfo &info);
+ void onStateChange(Radio radio);
+ Q_SLOT void tryResubscribeToStateChanges(winrt::hstring id, int numAttempts);
+
+ Q_SLOT void onDeviceAdded(winrt::hstring id);
+ Q_SLOT void onDeviceRemoved(winrt::hstring id);
+
+ std::unique_ptr<WatcherWrapper> mAdapterWatcher = nullptr;
+ std::unique_ptr<WatcherWrapper> mLeDevicesWatcher = nullptr;
+ std::unique_ptr<WatcherWrapper> mClassicDevicesWatcher = nullptr;
+ QMutex mMutex;
+ // Key for this map is BluetoothAdapter Id, *not* Radio Id.
+ QMap<winrt::hstring, RadioInfo> mRadios;
+ QList<QBluetoothAddress> mConnectedDevices;
+};
+
+AdapterManager::AdapterManager() : QObject()
+{
+ const auto adapterSelector = BluetoothAdapter::GetDeviceSelector();
+ mAdapterWatcher = std::make_unique<WatcherWrapper>(adapterSelector);
+ mAdapterWatcher->init(this, &AdapterManager::onAdapterAdded, &AdapterManager::onAdapterRemoved);
+
+ // Once created, device watchers will also populate the initial list of
+ // connected devices.
+
+ const auto leSelector = BluetoothLEDevice::GetDeviceSelectorFromConnectionStatus(
+ BluetoothConnectionStatus::Connected);
+ mLeDevicesWatcher = std::make_unique<WatcherWrapper>(leSelector);
+ mLeDevicesWatcher->init(this, &AdapterManager::onDeviceAdded, &AdapterManager::onDeviceRemoved);
+
+ const auto classicSelector = BluetoothDevice::GetDeviceSelectorFromConnectionStatus(
+ BluetoothConnectionStatus::Connected);
+ mClassicDevicesWatcher = std::make_unique<WatcherWrapper>(classicSelector);
+ mClassicDevicesWatcher->init(this, &AdapterManager::onDeviceAdded,
+ &AdapterManager::onDeviceRemoved);
+}
+
+AdapterManager::~AdapterManager()
+{
+}
+
+QList<QBluetoothAddress> AdapterManager::connectedDevices()
+{
+ QMutexLocker locker(&mMutex);
+ return mConnectedDevices;
+}
+
+QBluetoothLocalDevice::HostMode AdapterManager::addClient(QBluetoothLocalDevicePrivate *client)
+{
+ connect(this, &AdapterManager::modeChanged, client,
+ &QBluetoothLocalDevicePrivate::radioModeChanged, Qt::QueuedConnection);
+ connect(client, &QBluetoothLocalDevicePrivate::updateMode, this, &AdapterManager::updateMode,
+ Qt::QueuedConnection);
+ connect(this, &AdapterManager::adapterAdded, client,
+ &QBluetoothLocalDevicePrivate::onAdapterAdded, Qt::QueuedConnection);
+ connect(this, &AdapterManager::adapterRemoved, client,
+ &QBluetoothLocalDevicePrivate::onAdapterRemoved, Qt::QueuedConnection);
+ connect(this, &AdapterManager::deviceAdded, client,
+ &QBluetoothLocalDevicePrivate::onDeviceAdded, Qt::QueuedConnection);
+ connect(this, &AdapterManager::deviceRemoved, client,
+ &QBluetoothLocalDevicePrivate::onDeviceRemoved, Qt::QueuedConnection);
+
+ QMutexLocker locker(&mMutex);
+ const auto adapterId = client->mDeviceId;
+ if (mRadios.contains(adapterId)) {
+ auto &radioInfo = mRadios[adapterId];
+ radioInfo.numClients++;
+ return modeFromWindowsBluetoothState(radioInfo.radio.State());
+ } else {
+ // Note that when we use await(), we need to unlock the mutex, because
+ // it calls processEvents(), so other methods that demand the mutex can
+ // be invoked.
+ locker.unlock();
+ Radio r = getRadioFromAdapterId(adapterId);
+ if (r) {
+ locker.relock();
+ RadioInfo info;
+ info.radio = r;
+ info.numClients = 1;
+ info.currentState = r.State();
+ subscribeToStateChanges(info);
+ mRadios.insert(adapterId, info);
+ return modeFromWindowsBluetoothState(info.currentState);
+ }
+ }
+ qCWarning(QT_BT_WINDOWS, "Failed to subscribe to adapter state changes");
+ return QBluetoothLocalDevice::HostPoweredOff;
+}
+
+void AdapterManager::removeClient(winrt::hstring adapterId)
+{
+ QMutexLocker locker(&mMutex);
+ if (mRadios.contains(adapterId)) {
+ auto &radioInfo = mRadios[adapterId];
+ if (--radioInfo.numClients == 0) {
+ unsubscribeFromStateChanges(radioInfo);
+ mRadios.remove(adapterId);
+ }
+ } else {
+ qCWarning(QT_BT_WINDOWS) << "Removing client for an unknown adapter id"
+ << QString::fromStdString(winrt::to_string(adapterId));
+ }
+}
+
+void AdapterManager::updateMode(winrt::hstring adapterId, QBluetoothLocalDevice::HostMode mode)
+{
+ QMutexLocker locker(&mMutex);
+ if (mRadios.contains(adapterId)) {
+ RadioAccessStatus status = RadioAccessStatus::Unspecified;
+ auto radio = mRadios[adapterId].radio; // can be nullptr
+ locker.unlock();
+ if (radio) {
+ const bool res = await(radio.SetStateAsync(windowsStateFromMode(mode)), status);
+ // If operation succeeds, we will update the state in the event handler.
+ if (!res || status != RadioAccessStatus::Allowed) {
+ qCWarning(QT_BT_WINDOWS, "Failed to update adapter state: SetStateAsync() failed!");
+ if (status == RadioAccessStatus::DeniedBySystem) {
+ qCWarning(QT_BT_WINDOWS) << "Check that the user has permissions to manipulate"
+ " the selected Bluetooth device";
+ }
+ }
+ }
+ }
+}
+
+Radio AdapterManager::getRadioFromAdapterId(winrt::hstring id)
+{
+ BluetoothAdapter a(nullptr);
+ bool res = await(BluetoothAdapter::FromIdAsync(id), a);
+ if (res && a) {
+ Radio r(nullptr);
+ res = await(a.GetRadioAsync(), r);
+ if (res && r)
+ return r;
+ }
+ return nullptr;
+}
+
+void AdapterManager::onStateChange(Radio radio)
+{
+ QMutexLocker locker(&mMutex);
+ for (const auto &key : mRadios.keys()) {
+ auto &info = mRadios[key];
+ if (info.radio == radio) {
+ if (info.currentState != radio.State()) {
+ info.currentState = radio.State();
+ emit modeChanged(key, modeFromWindowsBluetoothState(info.currentState));
+ }
+ break;
+ }
+ }
+}
+
+static const int kMaximumAttempts = 5;
+
+// In practice when the adapter is reconnected, the Radio object can't be
+// retrieved immediately. I'm not sure if such behavior is normal, or specific
+// to my machine only. I also do not know what is the proper time to wait before
+// the Radio instance can be retrieved. So we introduce a helper method, which
+// tries to resubscribe several times with a 100ms interval between retries.
+void AdapterManager::tryResubscribeToStateChanges(winrt::hstring id, int numAttempts)
+{
+ QMutexLocker locker(&mMutex);
+ if (mRadios.contains(id)) {
+ // The Added event can come when we first create and use adapter. Such
+ // event should not be handled.
+ if (mRadios[id].radio != nullptr)
+ return;
+ locker.unlock();
+ Radio r = getRadioFromAdapterId(id);
+ if (r) {
+ locker.relock();
+ // We have to check once again because the record could be deleted
+ // while we were await'ing in getRadioFromAdapterId().
+ if (mRadios.contains(id)) {
+ auto &info = mRadios[id];
+ info.radio = r;
+ info.currentState = r.State();
+ subscribeToStateChanges(info);
+ emit modeChanged(id, modeFromWindowsBluetoothState(info.currentState));
+ }
+ } else {
+ if (++numAttempts < kMaximumAttempts) {
+ qCDebug(QT_BT_WINDOWS, "Trying to resubscribe for the state changes");
+ QPointer<AdapterManager> thisPtr(this);
+ QTimer::singleShot(100, [thisPtr, id, numAttempts]() {
+ if (thisPtr)
+ thisPtr->tryResubscribeToStateChanges(id, numAttempts);
+ });
+ } else {
+ qCWarning(QT_BT_WINDOWS,
+ "Failed to resubscribe to the state changes after %d attempts!",
+ numAttempts);
+ }
+ }
+ }
+}
+
+struct BluetoothInfo
+{
+ QBluetoothAddress address;
+ bool isConnected;
+};
+
+static BluetoothInfo getBluetoothInfo(winrt::hstring id)
+{
+ // We do not know if it's a BT classic or BTLE device, so we try both.
+ BluetoothDevice device(nullptr);
+ bool res = await(BluetoothDevice::FromIdAsync(id), device, 5000);
+ if (res && device) {
+ return { QBluetoothAddress(device.BluetoothAddress()),
+ device.ConnectionStatus() == BluetoothConnectionStatus::Connected };
+ }
+
+ BluetoothLEDevice leDevice(nullptr);
+ res = await(BluetoothLEDevice::FromIdAsync(id), leDevice, 5000);
+ if (res && leDevice) {
+ return { QBluetoothAddress(leDevice.BluetoothAddress()),
+ leDevice.ConnectionStatus() == BluetoothConnectionStatus::Connected };
+ }
+
+ return {};
+}
+
+void AdapterManager::onDeviceAdded(winrt::hstring id)
+{
+ const BluetoothInfo &info = getBluetoothInfo(id);
+ // In practice this callback might come even for disconnected device.
+ // So check status explicitly.
+ if (!info.address.isNull() && info.isConnected) {
+ bool found = false;
+ {
+ // A scope is needed, because we need to emit a signal when mutex is already unlocked
+ QMutexLocker locker(&mMutex);
+ found = mConnectedDevices.contains(info.address);
+ if (!found) {
+ mConnectedDevices.push_back(info.address);
+ }
+ }
+ if (!found)
+ emit deviceAdded(info.address);
+ }
+}
+
+void AdapterManager::onDeviceRemoved(winrt::hstring id)
+{
+ const BluetoothInfo &info = getBluetoothInfo(id);
+ if (!info.address.isNull() && !info.isConnected) {
+ bool found = false;
+ {
+ QMutexLocker locker(&mMutex);
+ found = mConnectedDevices.removeOne(info.address);
+ }
+ if (found)
+ emit deviceRemoved(info.address);
+ }
+}
+
+void AdapterManager::onAdapterAdded(winrt::hstring id)
+{
+ emit adapterAdded(id);
+ // We need to invoke the method from a Qt thread, so that we could start a
+ // timer there.
+ QMetaObject::invokeMethod(this, "tryResubscribeToStateChanges", Qt::QueuedConnection,
+ Q_ARG(winrt::hstring, id), Q_ARG(int, 0));
+}
+
+void AdapterManager::onAdapterRemoved(winrt::hstring id)
+{
+ emit adapterRemoved(id);
+ QMutexLocker locker(&mMutex);
+ if (mRadios.contains(id)) {
+ // here we can't simply remove the record from the map, because the
+ // same adapter can later be reconnected, and we need to keep track of
+ // the created clients.
+ mRadios[id].radio = nullptr;
+ }
+}
+
+void AdapterManager::subscribeToStateChanges(AdapterManager::RadioInfo &info)
+{
+ QPointer<AdapterManager> thisPtr(this);
+ info.stateToken = info.radio.StateChanged([thisPtr](Radio r, const auto &) {
+ // This callback fires twice. Looks like an MS bug.
+ // This callback comes in a separate thread
+ if (thisPtr) {
+ thisPtr->onStateChange(r);
+ }
+ });
+}
+
+void AdapterManager::unsubscribeFromStateChanges(AdapterManager::RadioInfo &info)
+{
+ // This method can be called after the radio is disconnected
+ if (info.radio)
+ info.radio.StateChanged(info.stateToken);
+}
+
+Q_GLOBAL_STATIC(AdapterManager, adapterManager)
+
+static DeviceInformationCollection getAvailableAdapters()
+{
+ const auto btSelector = BluetoothAdapter::GetDeviceSelector();
+ DeviceInformationCollection deviceInfoCollection(nullptr);
+ await(DeviceInformation::FindAllAsync(btSelector), deviceInfoCollection);
+ return deviceInfoCollection;
+}
+
+DeviceInformationPairing pairingInfoFromAddress(const QBluetoothAddress &address)
+{
+ const quint64 addr64 = address.toUInt64();
+ BluetoothLEDevice leDevice(nullptr);
+ bool res = await(BluetoothLEDevice::FromBluetoothAddressAsync(addr64), leDevice, 5000);
+ if (res && leDevice)
+ return leDevice.DeviceInformation().Pairing();
+
+ BluetoothDevice device(nullptr);
+ res = await(BluetoothDevice::FromBluetoothAddressAsync(addr64), device, 5000);
+ if (res && device)
+ return device.DeviceInformation().Pairing();
+
+ return nullptr;
+}
+
+struct PairingWorker
+ : public winrt::implements<PairingWorker, winrt::Windows::Foundation::IInspectable>
+{
+ PairingWorker(QBluetoothLocalDevice *device): q(device) {}
+ ~PairingWorker() = default;
+
+ void pairAsync(const QBluetoothAddress &addr, QBluetoothLocalDevice::Pairing pairing);
+
+private:
+ QPointer<QBluetoothLocalDevice> q;
+ void onPairingRequested(DeviceInformationCustomPairing const&,
+ DevicePairingRequestedEventArgs args);
+};
+
+void PairingWorker::pairAsync(const QBluetoothAddress &addr, QBluetoothLocalDevice::Pairing pairing)
+{
+ // Note: some of the functions called here use await() in their implementation.
+ // Hence we need to verify that the 'q' is still valid after such calls, as
+ // it may have been destroyed. In that scenario the ComPtr pointing to this
+ // object is destroyed, but to protect this function's possible execution at that time,
+ // the get_strong() call below will ensure we can execute until the end.
+ auto ref = get_strong();
+ DeviceInformationPairing pairingInfo = pairingInfoFromAddress(addr);
+ switch (pairing) {
+ case QBluetoothLocalDevice::Paired:
+ case QBluetoothLocalDevice::AuthorizedPaired:
+ {
+ DeviceInformationCustomPairing customPairing = pairingInfo.Custom();
+ auto token = customPairing.PairingRequested(
+ { get_weak(), &PairingWorker::onPairingRequested });
+ DevicePairingResult result{nullptr};
+ bool res = await(customPairing.PairAsync(DevicePairingKinds::ConfirmOnly), result, 30000);
+ customPairing.PairingRequested(token);
+ if (!res || result.Status() != DevicePairingResultStatus::Paired) {
+ if (q)
+ emit q->errorOccurred(QBluetoothLocalDevice::PairingError);
+ return;
+ }
+
+ // Check the actual protection level used and signal the success
+ if (q) {
+ const auto resultingPairingStatus = q->pairingStatus(addr);
+ // pairingStatus() uses await/spins eventloop => check 'q' validity again
+ if (q)
+ emit q->pairingFinished(addr, resultingPairingStatus);
+ }
+ return;
+ }
+ case QBluetoothLocalDevice::Unpaired:
+ DeviceUnpairingResult unpairingResult{nullptr};
+ bool res = await(pairingInfo.UnpairAsync(), unpairingResult, 10000);
+ if (!res || unpairingResult.Status() != DeviceUnpairingResultStatus::Unpaired) {
+ if (q)
+ emit q->errorOccurred(QBluetoothLocalDevice::PairingError);
+ return;
+ }
+ if (q)
+ emit q->pairingFinished(addr, QBluetoothLocalDevice::Unpaired);
+ return;
+ }
+}
+
+void PairingWorker::onPairingRequested(const DeviceInformationCustomPairing &,
+ DevicePairingRequestedEventArgs args)
+{
+ if (args.PairingKind() != DevicePairingKinds::ConfirmOnly) {
+ Q_ASSERT(false);
+ return;
+ }
+
+ args.Accept();
}
QBluetoothLocalDevice::QBluetoothLocalDevice(QObject *parent) :
@@ -107,98 +565,234 @@ QBluetoothLocalDevice::QBluetoothLocalDevice(const QBluetoothAddress &address, Q
registerQBluetoothLocalDeviceMetaType();
}
-QBluetoothLocalDevicePrivate::QBluetoothLocalDevicePrivate(QBluetoothLocalDevice *q, QBluetoothAddress)
- : q_ptr(q)
+QBluetoothLocalDevicePrivate::QBluetoothLocalDevicePrivate(QBluetoothLocalDevice *q,
+ QBluetoothAddress address)
+ : q_ptr(q),
+ mAdapter(nullptr),
+ mMode(QBluetoothLocalDevice::HostPoweredOff)
{
- GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Devices_Bluetooth_BluetoothLEDevice).Get(), &mLEStatics);
- GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Devices_Bluetooth_BluetoothDevice).Get(), &mStatics);
+ mPairingWorker = winrt::make_self<PairingWorker>(q);
+ if (address.isNull()) {
+ // use default adapter
+ bool res = await(BluetoothAdapter::GetDefaultAsync(), mAdapter);
+ if (res && mAdapter) {
+ // get adapter name
+ mDeviceId = mAdapter.DeviceId();
+ DeviceInformation devInfo(nullptr);
+ res = await(DeviceInformation::CreateFromIdAsync(mDeviceId), devInfo);
+ if (res && devInfo)
+ mAdapterName = QString::fromStdString(winrt::to_string(devInfo.Name()));
+ }
+ } else {
+ // try to select a proper device
+ const auto deviceInfoCollection = getAvailableAdapters();
+ for (const auto &devInfo : deviceInfoCollection) {
+ BluetoothAdapter adapter(nullptr);
+ const bool res = await(BluetoothAdapter::FromIdAsync(devInfo.Id()), adapter);
+ if (res && adapter) {
+ QBluetoothAddress adapterAddress(adapter.BluetoothAddress());
+ if (adapterAddress == address) {
+ mAdapter = adapter;
+ mDeviceId = adapter.DeviceId();
+ mAdapterName = QString::fromStdString(winrt::to_string(devInfo.Name()));
+ break;
+ }
+ }
+ }
+ }
+ if (mAdapter) {
+ mMode = adapterManager->addClient(this);
+ } else {
+ if (address.isNull()) {
+ qCWarning(QT_BT_WINDOWS, "Failed to create QBluetoothLocalDevice - no adapter found");
+ } else {
+ qCWarning(QT_BT_WINDOWS) << "Failed to create QBluetoothLocalDevice for address"
+ << address;
+ }
+ }
}
-QBluetoothLocalDevicePrivate::~QBluetoothLocalDevicePrivate() = default;
+QBluetoothLocalDevicePrivate::~QBluetoothLocalDevicePrivate()
+{
+ adapterManager->removeClient(mDeviceId);
+ mAdapter = nullptr;
+}
bool QBluetoothLocalDevicePrivate::isValid() const
{
- return (mStatics != nullptr && mLEStatics != nullptr);
+ return mAdapter != nullptr;
+}
+
+void QBluetoothLocalDevicePrivate::updateAdapterState(QBluetoothLocalDevice::HostMode mode)
+{
+ if (!mAdapter) {
+ qCWarning(QT_BT_WINDOWS, "Trying to update state for an uninitialized adapter");
+ return;
+ }
+ const auto desiredMode = adjustHostMode(mode);
+ if (desiredMode != mMode) {
+ // From the MS docs: Note that your code should call RequestAccessAsync
+ // at least once, from the UI thread, before trying to call
+ // SetStateAsync. This is because in some regions, with some user
+ // settings choices, attempting to change radio state requires user
+ // permission.
+ RadioAccessStatus status = RadioAccessStatus::Unspecified;
+ bool res = await(Radio::RequestAccessAsync(), status);
+ if (res && status == RadioAccessStatus::Allowed) {
+ // Now send a signal to the AdapterWatcher. That class will manage
+ // the actual state change.
+ emit updateMode(mDeviceId, desiredMode);
+ } else {
+ qCWarning(QT_BT_WINDOWS, "Failed to update adapter state: operation denied!");
+ }
+ }
+}
+
+void QBluetoothLocalDevicePrivate::onAdapterRemoved(winrt::hstring id)
+{
+ if (id == mDeviceId) {
+ qCDebug(QT_BT_WINDOWS, "Current adapter is removed");
+ mAdapter = nullptr;
+ if (mMode != QBluetoothLocalDevice::HostPoweredOff) {
+ mMode = QBluetoothLocalDevice::HostPoweredOff;
+ emit q_ptr->hostModeStateChanged(mMode);
+ }
+ }
+}
+
+void QBluetoothLocalDevicePrivate::onAdapterAdded(winrt::hstring id)
+{
+ if (id == mDeviceId && !mAdapter) {
+ // adapter was reconnected - try to recreate the internals
+ qCDebug(QT_BT_WINDOWS, "Adapter reconnected - trying to restore QBluetoothLocalDevice");
+ const bool res = await(BluetoothAdapter::FromIdAsync(mDeviceId), mAdapter);
+ if (!res || !mAdapter)
+ qCWarning(QT_BT_WINDOWS, "Failed to restore adapter");
+ }
+}
+
+void QBluetoothLocalDevicePrivate::radioModeChanged(winrt::hstring id, QBluetoothLocalDevice::HostMode mode)
+{
+ if (id == mDeviceId && mAdapter) {
+ if (mode != mMode) {
+ mMode = mode;
+ emit q_ptr->hostModeStateChanged(mMode);
+ }
+ }
+}
+
+void QBluetoothLocalDevicePrivate::onDeviceAdded(const QBluetoothAddress &address)
+{
+ if (isValid())
+ emit q_ptr->deviceConnected(address);
+}
+
+void QBluetoothLocalDevicePrivate::onDeviceRemoved(const QBluetoothAddress &address)
+{
+ if (isValid())
+ emit q_ptr->deviceDisconnected(address);
}
void QBluetoothLocalDevice::requestPairing(const QBluetoothAddress &address, Pairing pairing)
{
- Q_UNUSED(address);
- Q_UNUSED(pairing);
- QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection,
- Q_ARG(QBluetoothLocalDevice::Error,
- QBluetoothLocalDevice::PairingError));
+ Q_D(QBluetoothLocalDevice);
+ if (!isValid() || address.isNull()) {
+ QMetaObject::invokeMethod(this, "errorOccurred", Qt::QueuedConnection,
+ Q_ARG(QBluetoothLocalDevice::Error,
+ QBluetoothLocalDevice::PairingError));
+ return;
+ }
+
+ // Check current pairing status and determine if there is a need to do anything
+ const Pairing currentPairingStatus = pairingStatus(address);
+ if ((currentPairingStatus == Unpaired && pairing == Unpaired)
+ || (currentPairingStatus != Unpaired && pairing != Unpaired)) {
+ qCDebug(QT_BT_WINDOWS) << "requestPairing() no change needed to pairing" << address;
+ QMetaObject::invokeMethod(this, "pairingFinished", Qt::QueuedConnection,
+ Q_ARG(QBluetoothAddress, address),
+ Q_ARG(QBluetoothLocalDevice::Pairing,
+ currentPairingStatus));
+ return;
+ }
+
+ qCDebug(QT_BT_WINDOWS) << "requestPairing() initiating (un)pairing" << address << pairing;
+ d->mPairingWorker->pairAsync(address, pairing);
}
QBluetoothLocalDevice::Pairing QBluetoothLocalDevice::pairingStatus(
const QBluetoothAddress &address) const
{
if (!isValid() || address.isNull())
- return QBluetoothLocalDevice::Unpaired;
-
- ComPtr<IDeviceInformationPairing> pairingInfo = getPairingInfo<IBluetoothLEDeviceStatics,
- BluetoothLEDevice, IBluetoothLEDevice, IBluetoothLEDevice2>(d_ptr->mLEStatics, address);
- if (!pairingInfo)
- pairingInfo = getPairingInfo<IBluetoothDeviceStatics, BluetoothDevice,
- IBluetoothDevice, IBluetoothDevice2>(d_ptr->mStatics, address);
- if (!pairingInfo)
- return QBluetoothLocalDevice::Unpaired;
- boolean isPaired;
- HRESULT hr = pairingInfo->get_IsPaired(&isPaired);
- RETURN_IF_FAILED("Could not obtain device pairing", return QBluetoothLocalDevice::Unpaired);
- if (!isPaired)
- return QBluetoothLocalDevice::Unpaired;
-
- ComPtr<IDeviceInformationPairing2> pairingInfo2;
- hr = pairingInfo.As(&pairingInfo2);
- RETURN_IF_FAILED("Could not cast pairing info", return QBluetoothLocalDevice::Paired);
- DevicePairingProtectionLevel protection = DevicePairingProtectionLevel_None;
- hr = pairingInfo2->get_ProtectionLevel(&protection);
- RETURN_IF_FAILED("Could not obtain pairing protection level", return QBluetoothLocalDevice::Paired);
- if (protection == DevicePairingProtectionLevel_Encryption
- || protection == DevicePairingProtectionLevel_EncryptionAndAuthentication)
- return QBluetoothLocalDevice::AuthorizedPaired;
- return QBluetoothLocalDevice::Paired;
-}
-
-void QBluetoothLocalDevice::pairingConfirmation(bool confirmation)
-{
- Q_UNUSED(confirmation);
+ return Unpaired;
+
+ const DeviceInformationPairing pairingInfo = pairingInfoFromAddress(address);
+ if (!pairingInfo || !pairingInfo.IsPaired())
+ return Unpaired;
+
+ const DevicePairingProtectionLevel protection = pairingInfo.ProtectionLevel();
+ if (protection == DevicePairingProtectionLevel::Encryption
+ || protection == DevicePairingProtectionLevel::EncryptionAndAuthentication)
+ return AuthorizedPaired;
+ return Paired;
}
void QBluetoothLocalDevice::setHostMode(QBluetoothLocalDevice::HostMode mode)
{
- Q_UNUSED(mode);
+ Q_D(QBluetoothLocalDevice);
+ d->updateAdapterState(mode);
}
QBluetoothLocalDevice::HostMode QBluetoothLocalDevice::hostMode() const
{
- return HostConnectable;
+ Q_D(const QBluetoothLocalDevice);
+ return d->mMode;
}
QList<QBluetoothAddress> QBluetoothLocalDevice::connectedDevices() const
{
- return QList<QBluetoothAddress>();
+ // On windows we have only one Bluetooth adapter, but generally can create multiple
+ // QBluetoothLocalDevice instances (both valid and invalid). Invalid instances shouldn't return
+ // any connected devices, while all valid instances can use information from a global static.
+ Q_D(const QBluetoothLocalDevice);
+ return d->isValid() ? adapterManager->connectedDevices() : QList<QBluetoothAddress>();
}
void QBluetoothLocalDevice::powerOn()
{
+ setHostMode(HostConnectable);
}
QString QBluetoothLocalDevice::name() const
{
- return QString();
+ Q_D(const QBluetoothLocalDevice);
+ return d->mAdapterName;
}
QBluetoothAddress QBluetoothLocalDevice::address() const
{
- return QBluetoothAddress();
+ Q_D(const QBluetoothLocalDevice);
+ return d->mAdapter ? QBluetoothAddress(d->mAdapter.BluetoothAddress()) : QBluetoothAddress();
}
QList<QBluetoothHostInfo> QBluetoothLocalDevice::allDevices()
{
- QList<QBluetoothHostInfo> localDevices;
- return localDevices;
+ QList<QBluetoothHostInfo> devices;
+ const auto deviceInfoCollection = getAvailableAdapters();
+ if (deviceInfoCollection) {
+ for (const auto &devInfo : deviceInfoCollection) {
+ BluetoothAdapter adapter(nullptr);
+ const bool res = await(BluetoothAdapter::FromIdAsync(devInfo.Id()), adapter);
+ if (res && adapter) {
+ QBluetoothHostInfo info;
+ info.setName(QString::fromStdString(winrt::to_string(devInfo.Name())));
+ info.setAddress(QBluetoothAddress(adapter.BluetoothAddress()));
+ devices.push_back(std::move(info));
+ }
+ }
+ }
+ return devices;
}
QT_END_NAMESPACE
+
+#include "qbluetoothlocaldevice_winrt.moc"
diff --git a/src/bluetooth/qbluetoothserver.cpp b/src/bluetooth/qbluetoothserver.cpp
index daed5dc2..d61c67ae 100644
--- a/src/bluetooth/qbluetoothserver.cpp
+++ b/src/bluetooth/qbluetoothserver.cpp
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2016 BlackBerry Limited. All rights reserved.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2016 BlackBerry Limited. All rights reserved.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qbluetoothserver.h"
#include "qbluetoothserver_p.h"
@@ -84,11 +48,12 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \fn void QBluetoothServer::error(QBluetoothServer::Error error)
+ \fn void QBluetoothServer::errorOccurred(QBluetoothServer::Error error)
This signal is emitted when an \a error occurs.
\sa error(), QBluetoothServer::Error
+ \since 6.2
*/
/*!
@@ -110,6 +75,9 @@ QT_BEGIN_NAMESPACE
\value ServiceAlreadyRegisteredError The service or port was already registered
\value UnsupportedProtocolError The \l {QBluetoothServiceInfo::Protocol}{Protocol} is not
supported on this platform.
+ \value [since 6.4] MissingPermissionsError The operating system requests
+ permissions which were not
+ granted by the user.
*/
/*!
@@ -212,13 +180,13 @@ QBluetoothServiceInfo QBluetoothServer::listen(const QBluetoothUuid &uuid, const
QBluetoothServiceInfo serviceInfo;
serviceInfo.setAttribute(QBluetoothServiceInfo::ServiceName, serviceName);
QBluetoothServiceInfo::Sequence browseSequence;
- browseSequence << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::PublicBrowseGroup));
+ browseSequence << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::ServiceClassUuid::PublicBrowseGroup));
serviceInfo.setAttribute(QBluetoothServiceInfo::BrowseGroupList,
browseSequence);
QBluetoothServiceInfo::Sequence profileSequence;
QBluetoothServiceInfo::Sequence classId;
- classId << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::SerialPort));
+ classId << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::ServiceClassUuid::SerialPort));
classId << QVariant::fromValue(quint16(0x100));
profileSequence.append(QVariant::fromValue(classId));
serviceInfo.setAttribute(QBluetoothServiceInfo::BluetoothProfileDescriptorList,
@@ -227,13 +195,13 @@ QBluetoothServiceInfo QBluetoothServer::listen(const QBluetoothUuid &uuid, const
classId.clear();
//Android requires custom uuid to be set as service class
classId << QVariant::fromValue(uuid);
- classId << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::SerialPort));
+ classId << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::ServiceClassUuid::SerialPort));
serviceInfo.setAttribute(QBluetoothServiceInfo::ServiceClassIds, classId);
serviceInfo.setServiceUuid(uuid);
QBluetoothServiceInfo::Sequence protocolDescriptorList;
QBluetoothServiceInfo::Sequence protocol;
- protocol << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::L2cap));
+ protocol << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::ProtocolUuid::L2cap));
if (d->serverType == QBluetoothServiceInfo::L2capProtocol)
protocol << QVariant::fromValue(serverPort());
protocolDescriptorList.append(QVariant::fromValue(protocol));
@@ -241,7 +209,7 @@ QBluetoothServiceInfo QBluetoothServer::listen(const QBluetoothUuid &uuid, const
//! [listen]
if (d->serverType == QBluetoothServiceInfo::RfcommProtocol) {
//! [listen2]
- protocol << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::Rfcomm))
+ protocol << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::ProtocolUuid::Rfcomm))
<< QVariant::fromValue(quint8(serverPort()));
protocolDescriptorList.append(QVariant::fromValue(protocol));
//! [listen2]
@@ -269,7 +237,7 @@ bool QBluetoothServer::isListening() const
return d->isListening();
#endif
- return d->socket->state() == QBluetoothSocket::ListeningState;
+ return d->socket->state() == QBluetoothSocket::SocketState::ListeningState;
}
/*!
@@ -286,13 +254,14 @@ int QBluetoothServer::maxPendingConnections() const
/*!
\fn QBluetoothServer::setSecurityFlags(QBluetooth::SecurityFlags security)
- Sets the Bluetooth security flags to \a security. This function must be called before calling listen().
- The Bluetooth link will always be encrypted when using Bluetooth 2.1 devices as encryption is
- mandatory.
-
- Android only supports two levels of security (secure and non-secure). If this flag is set to
- \l QBluetooth::NoSecurity the server object will not employ any authentication or encryption.
- Any other security flag combination will trigger a secure Bluetooth connection.
+ Sets the Bluetooth security flags to \a security. This function must be called
+ before calling listen(). The Bluetooth link will always be encrypted when using
+ Bluetooth 2.1 devices as encryption is mandatory.
+
+ Android only supports two levels of security (secure and non-secure). If this flag
+ is set to \l QBluetooth::Security::NoSecurity the server object will not employ
+ any authentication or encryption. Any other security flag combination will
+ trigger a secure Bluetooth connection.
On \macos, security flags are not supported and will be ignored.
*/
diff --git a/src/bluetooth/qbluetoothserver.h b/src/bluetooth/qbluetoothserver.h
index 5e71b58c..ac11c305 100644
--- a/src/bluetooth/qbluetoothserver.h
+++ b/src/bluetooth/qbluetoothserver.h
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2016 BlackBerry Limited. All rights reserved.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2016 BlackBerry Limited. All rights reserved.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QBLUETOOTHSERVER_H
#define QBLUETOOTHSERVER_H
@@ -66,7 +30,8 @@ public:
PoweredOffError,
InputOutputError,
ServiceAlreadyRegisteredError,
- UnsupportedProtocolError
+ UnsupportedProtocolError,
+ MissingPermissionsError
};
Q_ENUM(Error)
@@ -76,7 +41,8 @@ public:
void close();
bool listen(const QBluetoothAddress &address = QBluetoothAddress(), quint16 port = 0);
- QBluetoothServiceInfo listen(const QBluetoothUuid &uuid, const QString &serviceName = QString());
+ [[nodiscard]] QBluetoothServiceInfo listen(const QBluetoothUuid &uuid,
+ const QString &serviceName = QString());
bool isListening() const;
void setMaxPendingConnections(int numConnections);
@@ -97,7 +63,7 @@ public:
Q_SIGNALS:
void newConnection();
- void error(QBluetoothServer::Error error);
+ void errorOccurred(QBluetoothServer::Error error);
protected:
QBluetoothServerPrivate *d_ptr;
diff --git a/src/bluetooth/qbluetoothserver_android.cpp b/src/bluetooth/qbluetoothserver_android.cpp
index eed3a1ea..df26daed 100644
--- a/src/bluetooth/qbluetoothserver_android.cpp
+++ b/src/bluetooth/qbluetoothserver_android.cpp
@@ -1,51 +1,17 @@
-/***************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#include <QtCore/QLoggingCategory>
+#include "android/serveracceptancethread_p.h"
+#include "android/androidutils_p.h"
+#include "android/jni_android_p.h"
#include "qbluetoothserver.h"
#include "qbluetoothserver_p.h"
#include "qbluetoothsocket.h"
#include "qbluetoothsocket_android_p.h"
#include "qbluetoothlocaldevice.h"
-#include "android/serveracceptancethread_p.h"
#include <QCoreApplication>
+#include <QtCore/QLoggingCategory>
QT_BEGIN_NAMESPACE
@@ -55,8 +21,7 @@ QHash<QBluetoothServerPrivate*, int> __fakeServerPorts;
QBluetoothServerPrivate::QBluetoothServerPrivate(QBluetoothServiceInfo::Protocol sType,
QBluetoothServer *parent)
- : socket(0),maxPendingConnections(1), securityFlags(QBluetooth::NoSecurity), serverType(sType),
- m_lastError(QBluetoothServer::NoError), q_ptr(parent)
+ : serverType(sType), q_ptr(parent)
{
thread = new ServerAcceptanceThread();
thread->setMaxPendingConnections(maxPendingConnections);
@@ -129,15 +94,22 @@ bool QBluetoothServer::listen(const QBluetoothAddress &localAdapter, quint16 por
Q_D(QBluetoothServer);
if (serverType() != QBluetoothServiceInfo::RfcommProtocol) {
d->m_lastError = UnsupportedProtocolError;
- emit error(d->m_lastError);
+ emit errorOccurred(d->m_lastError);
+ return false;
+ }
+
+ if (!ensureAndroidPermission(QBluetoothPermission::Access)) {
+ qCWarning(QT_BT_ANDROID) << "Bluetooth server listen() failed due to missing permissions";
+ d->m_lastError = QBluetoothServer::MissingPermissionsError;
+ emit errorOccurred(d->m_lastError);
return false;
}
const QList<QBluetoothHostInfo> localDevices = QBluetoothLocalDevice::allDevices();
- if (!localDevices.count()) {
+ if (localDevices.isEmpty()) {
qCWarning(QT_BT_ANDROID) << "Device does not support Bluetooth";
d->m_lastError = QBluetoothServer::UnknownError;
- emit error(d->m_lastError);
+ emit errorOccurred(d->m_lastError);
return false; //no Bluetooth device
}
@@ -160,21 +132,19 @@ bool QBluetoothServer::listen(const QBluetoothAddress &localAdapter, quint16 por
return false;
//check Bluetooth is available and online
- QAndroidJniObject btAdapter = QAndroidJniObject::callStaticObjectMethod(
- "android/bluetooth/BluetoothAdapter",
- "getDefaultAdapter",
- "()Landroid/bluetooth/BluetoothAdapter;");
+ QJniObject btAdapter = getDefaultBluetoothAdapter();
+
if (!btAdapter.isValid()) {
qCWarning(QT_BT_ANDROID) << "Device does not support Bluetooth";
d->m_lastError = QBluetoothServer::UnknownError;
- emit error(d->m_lastError);
+ emit errorOccurred(d->m_lastError);
return false;
}
const int state = btAdapter.callMethod<jint>("getState");
if (state != 12 ) { //BluetoothAdapter.STATE_ON
d->m_lastError = QBluetoothServer::PoweredOffError;
- emit error(d->m_lastError);
+ emit errorOccurred(d->m_lastError);
qCWarning(QT_BT_ANDROID) << "Bluetooth device is powered off";
return false;
}
@@ -197,14 +167,14 @@ bool QBluetoothServer::listen(const QBluetoothAddress &localAdapter, quint16 por
} else {
qCWarning(QT_BT_ANDROID) << "server with port" << port << "already registered or port invalid";
d->m_lastError = ServiceAlreadyRegisteredError;
- emit error(d->m_lastError);
+ emit errorOccurred(d->m_lastError);
return false;
}
connect(d->thread, SIGNAL(newConnection()),
this, SIGNAL(newConnection()));
- connect(d->thread, SIGNAL(error(QBluetoothServer::Error)),
- this, SIGNAL(error(QBluetoothServer::Error)), Qt::QueuedConnection);
+ connect(d->thread, SIGNAL(errorOccurred(QBluetoothServer::Error)), this,
+ SIGNAL(errorOccurred(QBluetoothServer::Error)), Qt::QueuedConnection);
return true;
}
@@ -220,7 +190,7 @@ QBluetoothAddress QBluetoothServer::serverAddress() const
{
//Android only supports one local adapter
QList<QBluetoothHostInfo> hosts = QBluetoothLocalDevice::allDevices();
- Q_ASSERT(hosts.count() <= 1);
+ Q_ASSERT(hosts.size() <= 1);
if (hosts.isEmpty())
return QBluetoothAddress();
@@ -246,7 +216,7 @@ QBluetoothSocket *QBluetoothServer::nextPendingConnection()
{
Q_D(const QBluetoothServer);
- QAndroidJniObject socket = d->thread->nextPendingConnection();
+ QJniObject socket = d->thread->nextPendingConnection();
if (!socket.isValid())
return 0;
diff --git a/src/bluetooth/qbluetoothserver_bluez.cpp b/src/bluetooth/qbluetoothserver_bluez.cpp
index a98f5398..3181611f 100644
--- a/src/bluetooth/qbluetoothserver_bluez.cpp
+++ b/src/bluetooth/qbluetoothserver_bluez.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qbluetoothserver.h"
#include "qbluetoothserver_p.h"
@@ -68,8 +32,9 @@ QBluetoothSocket *QBluetoothServerPrivate::createSocketForServer(
QBluetoothServerPrivate::QBluetoothServerPrivate(QBluetoothServiceInfo::Protocol sType,
QBluetoothServer *parent)
- : maxPendingConnections(1), securityFlags(QBluetooth::Authorization), serverType(sType),
- m_lastError(QBluetoothServer::NoError), q_ptr(parent)
+ : securityFlags(QBluetooth::Security::Authorization),
+ serverType(sType),
+ q_ptr(parent)
{
if (sType == QBluetoothServiceInfo::RfcommProtocol)
socket = createSocketForServer(QBluetoothServiceInfo::RfcommProtocol);
@@ -95,7 +60,7 @@ void QBluetoothServerPrivate::_q_newConnection()
void QBluetoothServerPrivate::setSocketSecurityLevel(
QBluetooth::SecurityFlags requestedSecLevel, int *errnoCode)
{
- if (requestedSecLevel == QBluetooth::NoSecurity) {
+ if (requestedSecLevel == QBluetooth::SecurityFlags(QBluetooth::Security::NoSecurity)) {
qCWarning(QT_BT_BLUEZ) << "Cannot set NoSecurity on server socket";
return;
}
@@ -103,12 +68,12 @@ void QBluetoothServerPrivate::setSocketSecurityLevel(
struct bt_security security;
memset(&security, 0, sizeof(security));
- // ignore QBluetooth::Authentication -> not used anymore
- if (requestedSecLevel & QBluetooth::Authorization)
+ // ignore QBluetooth::Security::Authentication -> not used anymore
+ if (requestedSecLevel & QBluetooth::Security::Authorization)
security.level = BT_SECURITY_LOW;
- if (requestedSecLevel & QBluetooth::Encryption)
+ if (requestedSecLevel & QBluetooth::Security::Encryption)
security.level = BT_SECURITY_MEDIUM;
- if (requestedSecLevel & QBluetooth::Secure)
+ if (requestedSecLevel & QBluetooth::Security::Secure)
security.level = BT_SECURITY_HIGH;
if (setsockopt(socket->socketDescriptor(), SOL_BLUETOOTH, BT_SECURITY,
@@ -127,19 +92,19 @@ QBluetooth::SecurityFlags QBluetoothServerPrivate::socketSecurityLevel() const
if (getsockopt(socket->socketDescriptor(), SOL_BLUETOOTH, BT_SECURITY,
&security, &length) != 0) {
qCWarning(QT_BT_BLUEZ) << "Failed to get security flags" << qt_error_string(errno);
- return QBluetooth::NoSecurity;
+ return QBluetooth::Security::NoSecurity;
}
switch (security.level) {
case BT_SECURITY_LOW:
- return QBluetooth::Authorization;
+ return QBluetooth::Security::Authorization;
case BT_SECURITY_MEDIUM:
- return QBluetooth::Encryption;
+ return QBluetooth::Security::Encryption;
case BT_SECURITY_HIGH:
- return QBluetooth::Secure;
+ return QBluetooth::Security::Secure;
default:
qCWarning(QT_BT_BLUEZ) << "Unknown server socket security level" << security.level;
- return QBluetooth::NoSecurity;
+ return QBluetooth::Security::NoSecurity;
}
}
@@ -157,7 +122,7 @@ bool QBluetoothServer::listen(const QBluetoothAddress &address, quint16 port)
{
Q_D(QBluetoothServer);
- if (d->socket->state() == QBluetoothSocket::ListeningState) {
+ if (d->socket->state() == QBluetoothSocket::SocketState::ListeningState) {
qCWarning(QT_BT_BLUEZ) << "Socket already in listen mode, close server first";
return false; //already listening, nothing to do
}
@@ -167,14 +132,14 @@ bool QBluetoothServer::listen(const QBluetoothAddress &address, quint16 port)
qCWarning(QT_BT_BLUEZ) << "Device does not support Bluetooth or"
<< address.toString() << "is not a valid local adapter";
d->m_lastError = QBluetoothServer::UnknownError;
- emit error(d->m_lastError);
+ emit errorOccurred(d->m_lastError);
return false;
}
QBluetoothLocalDevice::HostMode hostMode = device.hostMode();
if (hostMode == QBluetoothLocalDevice::HostPoweredOff) {
d->m_lastError = QBluetoothServer::PoweredOffError;
- emit error(d->m_lastError);
+ emit errorOccurred(d->m_lastError);
qCWarning(QT_BT_BLUEZ) << "Bluetooth device is powered off";
return false;
}
@@ -184,7 +149,7 @@ bool QBluetoothServer::listen(const QBluetoothAddress &address, quint16 port)
/* Negative socket descriptor is not always an error case
* Another cause could be a call to close()/abort()
* Check whether we can recover by re-creating the socket
- * we should really call Bluez::QBluetoothSocketPrivate::ensureNativeSocket
+ * we should really call Bluez::QBluetoothSocketPrivateDarwin::ensureNativeSocket
* but a re-creation of the socket will do as well.
*/
@@ -197,7 +162,7 @@ bool QBluetoothServer::listen(const QBluetoothAddress &address, quint16 port)
sock = d->socket->socketDescriptor();
if (sock < 0) {
d->m_lastError = InputOutputError;
- emit error(d->m_lastError);
+ emit errorOccurred(d->m_lastError);
return false;
}
}
@@ -218,7 +183,7 @@ bool QBluetoothServer::listen(const QBluetoothAddress &address, quint16 port)
d->m_lastError = ServiceAlreadyRegisteredError;
else
d->m_lastError = InputOutputError;
- emit error(d->m_lastError);
+ emit errorOccurred(d->m_lastError);
return false;
}
} else {
@@ -235,7 +200,7 @@ bool QBluetoothServer::listen(const QBluetoothAddress &address, quint16 port)
if (::bind(sock, reinterpret_cast<sockaddr *>(&addr), sizeof(sockaddr_l2)) < 0) {
d->m_lastError = InputOutputError;
- emit error(d->m_lastError);
+ emit errorOccurred(d->m_lastError);
return false;
}
}
@@ -244,11 +209,11 @@ bool QBluetoothServer::listen(const QBluetoothAddress &address, quint16 port)
if (::listen(sock, d->maxPendingConnections) < 0) {
d->m_lastError = InputOutputError;
- emit error(d->m_lastError);
+ emit errorOccurred(d->m_lastError);
return false;
}
- d->socket->setSocketState(QBluetoothSocket::ListeningState);
+ d->socket->setSocketState(QBluetoothSocket::SocketState::ListeningState);
if (!d->socketNotifier) {
d->socketNotifier = new QSocketNotifier(d->socket->socketDescriptor(),
@@ -266,7 +231,7 @@ void QBluetoothServer::setMaxPendingConnections(int numConnections)
{
Q_D(QBluetoothServer);
- if (d->socket->state() == QBluetoothSocket::UnconnectedState)
+ if (d->socket->state() == QBluetoothSocket::SocketState::UnconnectedState)
d->maxPendingConnections = numConnections;
}
@@ -336,7 +301,7 @@ void QBluetoothServer::setSecurityFlags(QBluetooth::SecurityFlags security)
{
Q_D(QBluetoothServer);
- if (d->socket->state() == QBluetoothSocket::UnconnectedState) {
+ if (d->socket->state() == QBluetoothSocket::SocketState::UnconnectedState) {
// nothing to set beyond the fact to remember the sec level for the next listen()
d->securityFlags = security;
return;
@@ -348,7 +313,7 @@ void QBluetoothServer::setSecurityFlags(QBluetooth::SecurityFlags security)
qCWarning(QT_BT_BLUEZ) << "Failed to set socket option, closing socket for safety" << errorCode;
qCWarning(QT_BT_BLUEZ) << "Error: " << qt_error_string(errorCode);
d->m_lastError = InputOutputError;
- emit error(d->m_lastError);
+ emit errorOccurred(d->m_lastError);
d->socket->close();
}
}
@@ -357,7 +322,7 @@ QBluetooth::SecurityFlags QBluetoothServer::securityFlags() const
{
Q_D(const QBluetoothServer);
- if (d->socket->state() == QBluetoothSocket::UnconnectedState)
+ if (d->socket->state() == QBluetoothSocket::SocketState::UnconnectedState)
return d->securityFlags;
return d->socketSecurityLevel();
diff --git a/src/bluetooth/qbluetoothserver_macos.mm b/src/bluetooth/qbluetoothserver_macos.mm
index 4c0210c8..079a9c6e 100644
--- a/src/bluetooth/qbluetoothserver_macos.mm
+++ b/src/bluetooth/qbluetoothserver_macos.mm
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "darwin/btsocketlistener_p.h"
#include "qbluetoothserver_p.h"
@@ -52,7 +16,6 @@
#include "qbluetoothsocket.h"
#include <QtCore/qloggingcategory.h>
-#include <QtCore/qscopedpointer.h>
#include <QtCore/qvariant.h>
#include <QtCore/qglobal.h>
#include <QtCore/qmutex.h>
@@ -69,7 +32,6 @@ namespace {
using DarwinBluetooth::RetainPolicy;
using ServiceInfo = QBluetoothServiceInfo;
-using ObjCListener = QT_MANGLE_NAMESPACE(DarwinBTSocketListener);
QMap<quint16, QBluetoothServerPrivate *> &busyPSMs()
{
@@ -87,16 +49,11 @@ typedef QMap<quint16, QBluetoothServerPrivate *>::iterator ServerMapIterator;
} // unnamed namespace
-
QBluetoothServerPrivate::QBluetoothServerPrivate(ServiceInfo::Protocol type,
QBluetoothServer *parent)
- : socket(nullptr),
- maxPendingConnections(1),
- securityFlags(QBluetooth::NoSecurity),
- serverType(type),
- q_ptr(parent),
- m_lastError(QBluetoothServer::NoError),
- port(0)
+ : serverType(type),
+ q_ptr(parent),
+ port(0)
{
if (serverType == ServiceInfo::UnknownProtocol)
qCWarning(QT_BT_DARWIN) << "unknown protocol";
@@ -118,15 +75,15 @@ bool QBluetoothServerPrivate::startListener(quint16 realPort)
}
if (!listener) {
- listener.reset([[ObjCListener alloc] initWithListener:this],
+ listener.reset([[DarwinBTSocketListener alloc] initWithListener:this],
RetainPolicy::noInitialRetain);
}
bool result = false;
if (serverType == ServiceInfo::RfcommProtocol)
- result = [listener.getAs<ObjCListener>() listenRFCOMMConnectionsWithChannelID:realPort];
+ result = [listener.getAs<DarwinBTSocketListener>() listenRFCOMMConnectionsWithChannelID:realPort];
else
- result = [listener.getAs<ObjCListener>() listenL2CAPConnectionsWithPSM:realPort];
+ result = [listener.getAs<DarwinBTSocketListener>() listenL2CAPConnectionsWithPSM:realPort];
if (!result)
listener.reset();
@@ -302,7 +259,7 @@ bool QBluetoothServer::listen(const QBluetoothAddress &address, quint16 port)
<< address.toString()
<< "is not a valid local adapter";
d_ptr->m_lastError = UnknownError;
- emit error(UnknownError);
+ emit errorOccurred(UnknownError);
return false;
}
@@ -310,7 +267,7 @@ bool QBluetoothServer::listen(const QBluetoothAddress &address, quint16 port)
if (hostMode == QBluetoothLocalDevice::HostPoweredOff) {
qCWarning(QT_BT_DARWIN) << "Bluetooth device is powered off";
d_ptr->m_lastError = PoweredOffError;
- emit error(PoweredOffError);
+ emit errorOccurred(PoweredOffError);
return false;
}
@@ -319,7 +276,7 @@ bool QBluetoothServer::listen(const QBluetoothAddress &address, quint16 port)
if (type == ServiceInfo::UnknownProtocol) {
qCWarning(QT_BT_DARWIN) << "invalid protocol";
d_ptr->m_lastError = UnsupportedProtocolError;
- emit error(d_ptr->m_lastError);
+ emit errorOccurred(d_ptr->m_lastError);
return false;
}
@@ -348,14 +305,14 @@ bool QBluetoothServer::listen(const QBluetoothAddress &address, quint16 port)
}
if (d_ptr->m_lastError != QBluetoothServer::NoError) {
- emit error(d_ptr->m_lastError);
+ emit errorOccurred(d_ptr->m_lastError);
return false;
}
if (!port) {
qCWarning(QT_BT_DARWIN) << "all ports are busy";
d_ptr->m_lastError = ServiceAlreadyRegisteredError;
- emit error(d_ptr->m_lastError);
+ emit errorOccurred(d_ptr->m_lastError);
return false;
}
@@ -363,7 +320,7 @@ bool QBluetoothServer::listen(const QBluetoothAddress &address, quint16 port)
// (provided after a service was registered).
d_ptr->port = port;
d_ptr->registerServer(d_ptr, port);
- d_ptr->listener.reset([[ObjCListener alloc] initWithListener:d_ptr],
+ d_ptr->listener.reset([[DarwinBTSocketListener alloc] initWithListener:d_ptr],
RetainPolicy::noInitialRetain);
return true;
@@ -384,21 +341,21 @@ QBluetoothSocket *QBluetoothServer::nextPendingConnection()
if (!d_ptr->pendingConnections.size())
return nullptr;
- QScopedPointer<QBluetoothSocket> newSocket(new QBluetoothSocket);
+ std::unique_ptr<QBluetoothSocket> newSocket = std::make_unique<QBluetoothSocket>();
QBluetoothServerPrivate::PendingConnection channel(d_ptr->pendingConnections.front());
// Remove it even if we have some errors below.
d_ptr->pendingConnections.pop_front();
if (d_ptr->serverType == ServiceInfo::RfcommProtocol) {
- if (!static_cast<QBluetoothSocketPrivate *>(newSocket->d_ptr)->setRFCOMChannel(channel.getAs<IOBluetoothRFCOMMChannel>()))
+ if (!static_cast<QBluetoothSocketPrivateDarwin *>(newSocket->d_ptr)->setRFCOMChannel(channel.getAs<IOBluetoothRFCOMMChannel>()))
return nullptr;
} else {
- if (!static_cast<QBluetoothSocketPrivate *>(newSocket->d_ptr)->setL2CAPChannel(channel.getAs<IOBluetoothL2CAPChannel>()))
+ if (!static_cast<QBluetoothSocketPrivateDarwin *>(newSocket->d_ptr)->setL2CAPChannel(channel.getAs<IOBluetoothL2CAPChannel>()))
return nullptr;
}
- return newSocket.take();
+ return newSocket.release();
}
QBluetoothAddress QBluetoothServer::serverAddress() const
@@ -413,14 +370,14 @@ quint16 QBluetoothServer::serverPort() const
void QBluetoothServer::setSecurityFlags(QBluetooth::SecurityFlags security)
{
- Q_UNUSED(security)
+ Q_UNUSED(security);
Q_UNIMPLEMENTED();
}
QBluetooth::SecurityFlags QBluetoothServer::securityFlags() const
{
Q_UNIMPLEMENTED();
- return QBluetooth::NoSecurity;
+ return QBluetooth::Security::NoSecurity;
}
QT_END_NAMESPACE
diff --git a/src/bluetooth/qbluetoothserver_p.cpp b/src/bluetooth/qbluetoothserver_p.cpp
index 6657e151..8183a2b0 100644
--- a/src/bluetooth/qbluetoothserver_p.cpp
+++ b/src/bluetooth/qbluetoothserver_p.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qbluetoothserver.h"
#include "qbluetoothserver_p.h"
@@ -48,7 +12,7 @@ QT_BEGIN_NAMESPACE
QBluetoothServerPrivate::QBluetoothServerPrivate(QBluetoothServiceInfo::Protocol sType,
QBluetoothServer *parent)
- : maxPendingConnections(1), serverType(sType), m_lastError(QBluetoothServer::NoError),
+ : serverType(sType),
q_ptr(parent)
{
#ifndef QT_IOS_BLUETOOTH
@@ -75,7 +39,7 @@ bool QBluetoothServer::listen(const QBluetoothAddress &address, quint16 port)
Q_UNUSED(port);
Q_D(QBluetoothServer);
d->m_lastError = UnsupportedProtocolError;
- emit error(d->m_lastError);
+ emit errorOccurred(d->m_lastError);
return false;
}
@@ -111,7 +75,7 @@ void QBluetoothServer::setSecurityFlags(QBluetooth::SecurityFlags security)
QBluetooth::SecurityFlags QBluetoothServer::securityFlags() const
{
- return QBluetooth::NoSecurity;
+ return QBluetooth::Security::NoSecurity;
}
QT_END_NAMESPACE
diff --git a/src/bluetooth/qbluetoothserver_p.h b/src/bluetooth/qbluetoothserver_p.h
index a82114ba..09c43354 100644
--- a/src/bluetooth/qbluetoothserver_p.h
+++ b/src/bluetooth/qbluetoothserver_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QBLUETOOTHSERVER_P_H
#define QBLUETOOTHSERVER_P_H
@@ -57,13 +21,13 @@
#include "qbluetoothserver.h"
#include "qbluetooth.h"
-#if QT_CONFIG(bluez) || defined(QT_WIN_BLUETOOTH)
+#if QT_CONFIG(bluez)
QT_FORWARD_DECLARE_CLASS(QSocketNotifier)
#endif
#ifdef QT_ANDROID_BLUETOOTH
-#include <QtAndroidExtras/QAndroidJniEnvironment>
-#include <QtAndroidExtras/QAndroidJniObject>
+#include <QtCore/QJniEnvironment>
+#include <QtCore/QJniObject>
#include <QtBluetooth/QBluetoothUuid>
class ServerAcceptanceThread;
@@ -82,7 +46,7 @@ class ServerAcceptanceThread;
#include "darwin/btdelegates_p.h"
#include "darwin/btraii_p.h"
-#include <QtCore/qvector.h>
+#include <QtCore/QMutex>
#endif // QT_OSX_BLUETOOTH
@@ -110,23 +74,20 @@ public:
static QBluetoothSocket *createSocketForServer(
QBluetoothServiceInfo::Protocol socketType = QBluetoothServiceInfo::RfcommProtocol);
#endif
-#if defined(QT_WIN_BLUETOOTH)
- void _q_newConnection();
-#endif
public:
- QBluetoothSocket *socket;
+ QBluetoothSocket *socket = nullptr;
- int maxPendingConnections;
- QBluetooth::SecurityFlags securityFlags;
+ int maxPendingConnections = 1;
+ QBluetooth::SecurityFlags securityFlags = QBluetooth::Security::NoSecurity;
QBluetoothServiceInfo::Protocol serverType;
protected:
QBluetoothServer *q_ptr;
private:
- QBluetoothServer::Error m_lastError;
-#if QT_CONFIG(bluez) || defined(QT_WIN_BLUETOOTH)
+ QBluetoothServer::Error m_lastError = QBluetoothServer::NoError;
+#if QT_CONFIG(bluez)
QSocketNotifier *socketNotifier = nullptr;
#elif defined(QT_ANDROID_BLUETOOTH)
ServerAcceptanceThread *thread;
@@ -140,7 +101,8 @@ public:
EventRegistrationToken connectionToken {-1};
mutable QMutex pendingConnectionsMutex;
- QVector<Microsoft::WRL::ComPtr<ABI::Windows::Networking::Sockets::IStreamSocket>> pendingConnections;
+ QList<Microsoft::WRL::ComPtr<ABI::Windows::Networking::Sockets::IStreamSocket>>
+ pendingConnections;
Microsoft::WRL::ComPtr<ABI::Windows::Networking::Sockets::IStreamSocketListener> socketListener;
HRESULT handleClientConnection(ABI::Windows::Networking::Sockets::IStreamSocketListener *listener,
@@ -195,7 +157,7 @@ private:
static void unregisterServer(QBluetoothServerPrivate *server);
using PendingConnection = DarwinBluetooth::StrongReference;
- QVector<PendingConnection> pendingConnections;
+ QList<PendingConnection> pendingConnections;
#endif // QT_OSX_BLUETOOTH
};
diff --git a/src/bluetooth/qbluetoothserver_win.cpp b/src/bluetooth/qbluetoothserver_win.cpp
deleted file mode 100644
index 70695112..00000000
--- a/src/bluetooth/qbluetoothserver_win.cpp
+++ /dev/null
@@ -1,240 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qbluetoothserver.h"
-#include "qbluetoothserver_p.h"
-#include "qbluetoothsocket.h"
-#include "qbluetoothlocaldevice.h"
-
-#include <QtCore/QLoggingCategory>
-#include <QtCore/QSocketNotifier>
-
-#include <winsock2.h>
-#include <ws2bth.h>
-#include <bluetoothapis.h>
-#include <errno.h>
-
-QT_BEGIN_NAMESPACE
-
-Q_DECLARE_LOGGING_CATEGORY(QT_BT_WINDOWS)
-
-QBluetoothServerPrivate::QBluetoothServerPrivate(QBluetoothServiceInfo::Protocol sType,
- QBluetoothServer *parent)
- : maxPendingConnections(1), serverType(sType), q_ptr(parent),
- m_lastError(QBluetoothServer::NoError)
-{
- Q_Q(QBluetoothServer);
- Q_ASSERT(sType == QBluetoothServiceInfo::RfcommProtocol);
- socket = new QBluetoothSocket(QBluetoothServiceInfo::RfcommProtocol, q);
-}
-
-QBluetoothServerPrivate::~QBluetoothServerPrivate()
-{
-}
-
-void QBluetoothServerPrivate::_q_newConnection()
-{
- // disable socket notifier until application calls nextPendingConnection().
- socketNotifier->setEnabled(false);
-
- emit q_ptr->newConnection();
-}
-
-void QBluetoothServer::close()
-{
- Q_D(QBluetoothServer);
-
- delete d->socketNotifier;
- d->socketNotifier = nullptr;
-
- d->socket->close();
-}
-
-bool QBluetoothServer::listen(const QBluetoothAddress &address, quint16 port)
-{
- Q_D(QBluetoothServer);
-
- if (d->serverType != QBluetoothServiceInfo::RfcommProtocol) {
- qCWarning(QT_BT_WINDOWS) << "Protocol is not supported.";
- d->m_lastError = QBluetoothServer::UnsupportedProtocolError;
- emit error(d->m_lastError);
- return false;
- }
-
- if (d->socket->state() == QBluetoothSocket::ListeningState) {
- qCWarning(QT_BT_WINDOWS) << "Socket already in listen mode, close server first";
- return false;
- }
-
- const QBluetoothLocalDevice device(address);
- if (!device.isValid()) {
- qCWarning(QT_BT_WINDOWS) << "Device does not support Bluetooth or"
- << address.toString() << "is not a valid local adapter";
- d->m_lastError = QBluetoothServer::UnknownError;
- emit error(d->m_lastError);
- return false;
- }
-
- const QBluetoothLocalDevice::HostMode hostMode = device.hostMode();
- if (hostMode == QBluetoothLocalDevice::HostPoweredOff) {
- d->m_lastError = QBluetoothServer::PoweredOffError;
- emit error(d->m_lastError);
- qCWarning(QT_BT_WINDOWS) << "Bluetooth device is powered off";
- return false;
- }
-
- int sock = d->socket->socketDescriptor();
- if (sock < 0) {
- /* Negative socket descriptor is not always an error case.
- * Another cause could be a call to close()/abort().
- * Check whether we can recover by re-creating the socket.
- */
- delete d->socket;
- d->socket = new QBluetoothSocket(QBluetoothServiceInfo::RfcommProtocol, this);
- sock = d->socket->socketDescriptor();
- if (sock < 0) {
- d->m_lastError = InputOutputError;
- emit error(d->m_lastError);
- return false;
- }
- }
-
- if (sock < 0)
- return false;
-
- SOCKADDR_BTH addr = {};
- addr.addressFamily = AF_BTH;
- addr.port = (port == 0) ? BT_PORT_ANY : port;
- addr.btAddr = address.toUInt64();
-
- if (::bind(sock, reinterpret_cast<sockaddr *>(&addr), sizeof(SOCKADDR_BTH)) < 0) {
- if (errno == EADDRINUSE)
- d->m_lastError = ServiceAlreadyRegisteredError;
- else
- d->m_lastError = InputOutputError;
- emit error(d->m_lastError);
- return false;
- }
-
- if (::listen(sock, d->maxPendingConnections) < 0) {
- d->m_lastError = InputOutputError;
- emit error(d->m_lastError);
- return false;
- }
-
- d->socket->setSocketState(QBluetoothSocket::ListeningState);
-
- if (!d->socketNotifier) {
- d->socketNotifier = new QSocketNotifier(d->socket->socketDescriptor(),
- QSocketNotifier::Read, this);
- connect(d->socketNotifier, &QSocketNotifier::activated, this, [d](){
- d->_q_newConnection();
- });
- }
-
- return true;
-}
-
-void QBluetoothServer::setMaxPendingConnections(int numConnections)
-{
- Q_UNUSED(numConnections);
-}
-
-bool QBluetoothServer::hasPendingConnections() const
-{
- Q_D(const QBluetoothServer);
-
- if (!d || !d->socketNotifier)
- return false;
-
- // if the socket notifier is disabled there is a pending connection waiting for us to accept.
- return !d->socketNotifier->isEnabled();
-}
-
-QBluetoothSocket *QBluetoothServer::nextPendingConnection()
-{
- Q_D(QBluetoothServer);
-
- if (!hasPendingConnections())
- return nullptr;
-
- if (d->serverType != QBluetoothServiceInfo::RfcommProtocol)
- return nullptr;
-
- SOCKADDR_BTH addr = {};
- int length = sizeof(SOCKADDR_BTH);
- int pending = ::accept(d->socket->socketDescriptor(),
- reinterpret_cast<sockaddr *>(&addr), &length);
-
- QBluetoothSocket *newSocket = nullptr;
-
- if (pending >= 0) {
- newSocket = new QBluetoothSocket();
- newSocket->setSocketDescriptor(pending, QBluetoothServiceInfo::RfcommProtocol);
- }
-
- d->socketNotifier->setEnabled(true);
- return newSocket;
-}
-
-QBluetoothAddress QBluetoothServer::serverAddress() const
-{
- Q_D(const QBluetoothServer);
-
- return d->socket->localAddress();
-}
-
-quint16 QBluetoothServer::serverPort() const
-{
- Q_D(const QBluetoothServer);
-
- return d->socket->localPort();
-}
-
-void QBluetoothServer::setSecurityFlags(QBluetooth::SecurityFlags security)
-{
- Q_UNUSED(security);
-}
-
-QBluetooth::SecurityFlags QBluetoothServer::securityFlags() const
-{
- return QBluetooth::NoSecurity;
-}
-
-QT_END_NAMESPACE
diff --git a/src/bluetooth/qbluetoothserver_winrt.cpp b/src/bluetooth/qbluetoothserver_winrt.cpp
index b9d98eb7..c7961f8d 100644
--- a/src/bluetooth/qbluetoothserver_winrt.cpp
+++ b/src/bluetooth/qbluetoothserver_winrt.cpp
@@ -1,53 +1,15 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qbluetoothserver.h"
#include "qbluetoothserver_p.h"
#include "qbluetoothsocket.h"
+#include "qbluetoothlocaldevice.h"
#include "qbluetoothsocket_winrt_p.h"
+#include "qbluetoothutils_winrt_p.h"
#include <QtCore/QLoggingCategory>
-#include <QtCore/private/qeventdispatcher_winrt_p.h>
-#ifdef CLASSIC_APP_BUILD
-#define Q_OS_WINRT
-#endif
-#include <qfunctions_winrt.h>
+#include <QtCore/private/qfunctions_winrt_p.h>
#include <windows.networking.h>
#include <windows.networking.connectivity.h>
@@ -66,33 +28,25 @@ typedef ITypedEventHandler<StreamSocketListener *, StreamSocketListenerConnectio
QT_BEGIN_NAMESPACE
-Q_DECLARE_LOGGING_CATEGORY(QT_BT_WINRT)
+Q_DECLARE_LOGGING_CATEGORY(QT_BT_WINDOWS)
QHash<QBluetoothServerPrivate *, int> __fakeServerPorts;
QBluetoothServerPrivate::QBluetoothServerPrivate(QBluetoothServiceInfo::Protocol sType,
QBluetoothServer *parent)
- : maxPendingConnections(1), serverType(sType), m_lastError(QBluetoothServer::NoError),
- socket(0), q_ptr(parent)
+ : serverType(sType), q_ptr(parent)
{
-#ifdef CLASSIC_APP_BUILD
- CoInitialize(NULL);
-#endif
- socket = new QBluetoothSocket(QBluetoothServiceInfo::RfcommProtocol);
+ mainThreadCoInit(this);
}
QBluetoothServerPrivate::~QBluetoothServerPrivate()
{
deactivateActiveListening();
__fakeServerPorts.remove(this);
- if (socket)
- delete socket;
-#ifdef CLASSIC_APP_BUILD
// If we do not reset that pointer, socketListener will go out of scope after CoUninitialize was
// called, which will lead to a crash.
socketListener = nullptr;
- CoUninitialize();
-#endif
+ mainThreadCoUninit(this);
}
bool QBluetoothServerPrivate::isListening() const
@@ -128,7 +82,7 @@ HRESULT QBluetoothServerPrivate::handleClientConnection(IStreamSocketListener *l
{
Q_Q(QBluetoothServer);
if (!socketListener || socketListener.Get() != listener) {
- qCDebug(QT_BT_WINRT) << "Accepting connection from wrong listener. We should not be here.";
+ qCDebug(QT_BT_WINDOWS) << "Accepting connection from wrong listener. We should not be here.";
Q_UNREACHABLE();
return S_OK;
}
@@ -138,12 +92,13 @@ HRESULT QBluetoothServerPrivate::handleClientConnection(IStreamSocketListener *l
hr = args->get_Socket(&socket);
Q_ASSERT_SUCCEEDED(hr);
QMutexLocker locker(&pendingConnectionsMutex);
- if (pendingConnections.count() < maxPendingConnections) {
- qCDebug(QT_BT_WINRT) << "Accepting connection";
+ if (pendingConnections.size() < maxPendingConnections) {
+ qCDebug(QT_BT_WINDOWS) << "Accepting connection";
pendingConnections.append(socket);
+ locker.unlock();
q->newConnection();
} else {
- qCDebug(QT_BT_WINRT) << "Refusing connection";
+ qCDebug(QT_BT_WINDOWS) << "Refusing connection";
}
return S_OK;
@@ -163,24 +118,18 @@ bool QBluetoothServer::listen(const QBluetoothAddress &address, quint16 port)
Q_D(QBluetoothServer);
if (serverType() != QBluetoothServiceInfo::RfcommProtocol) {
d->m_lastError = UnsupportedProtocolError;
- emit error(d->m_lastError);
+ emit errorOccurred(d->m_lastError);
return false;
}
if (isListening())
return false;
- HRESULT hr;
- hr = QEventDispatcherWinRT::runOnXamlThread([d, this] ()
- {
- HRESULT hr = RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_Networking_Sockets_StreamSocketListener).Get(),
- &d->socketListener);
- Q_ASSERT_SUCCEEDED(hr);
- hr = d->socketListener->add_ConnectionReceived(Callback<ClientConnectedHandler>(d, &QBluetoothServerPrivate::handleClientConnection).Get(),
- &d->connectionToken);
- Q_ASSERT_SUCCEEDED(hr);
- return S_OK;
- });
+ HRESULT hr = RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_Networking_Sockets_StreamSocketListener).Get(),
+ &d->socketListener);
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = d->socketListener->add_ConnectionReceived(Callback<ClientConnectedHandler>(d, &QBluetoothServerPrivate::handleClientConnection).Get(),
+ &d->connectionToken);
Q_ASSERT_SUCCEEDED(hr);
//We can not register an actual Rfcomm port, because the platform does not allow it
@@ -197,11 +146,11 @@ bool QBluetoothServer::listen(const QBluetoothAddress &address, quint16 port)
if (__fakeServerPorts.key(port) == 0) {
__fakeServerPorts[d] = port;
- qCDebug(QT_BT_WINRT) << "Port" << port << "registered";
+ qCDebug(QT_BT_WINDOWS) << "Port" << port << "registered";
} else {
- qCWarning(QT_BT_WINRT) << "server with port" << port << "already registered or port invalid";
+ qCWarning(QT_BT_WINDOWS) << "server with port" << port << "already registered or port invalid";
d->m_lastError = ServiceAlreadyRegisteredError;
- emit error(d->m_lastError);
+ emit errorOccurred(d->m_lastError);
return false;
}
@@ -212,8 +161,8 @@ void QBluetoothServer::setMaxPendingConnections(int numConnections)
{
Q_D(QBluetoothServer);
QMutexLocker locker(&d->pendingConnectionsMutex);
- if (d->pendingConnections.count() > numConnections) {
- qCWarning(QT_BT_WINRT) << "There are currently more than" << numConnections << "connections"
+ if (d->pendingConnections.size() > numConnections) {
+ qCWarning(QT_BT_WINDOWS) << "There are currently more than" << numConnections << "connections"
<< "pending. Number of maximum pending connections was not changed.";
return;
}
@@ -231,7 +180,7 @@ bool QBluetoothServer::hasPendingConnections() const
QBluetoothSocket *QBluetoothServer::nextPendingConnection()
{
Q_D(QBluetoothServer);
- if (d->pendingConnections.count() == 0)
+ if (d->pendingConnections.isEmpty())
return nullptr;
ComPtr<IStreamSocket> socket = d->pendingConnections.takeFirst();
@@ -248,7 +197,12 @@ QBluetoothSocket *QBluetoothServer::nextPendingConnection()
QBluetoothAddress QBluetoothServer::serverAddress() const
{
- return QBluetoothAddress();
+ QList<QBluetoothHostInfo> hosts = QBluetoothLocalDevice::allDevices();
+
+ if (hosts.isEmpty())
+ return QBluetoothAddress();
+ else
+ return hosts.at(0).address();
}
quint16 QBluetoothServer::serverPort() const
@@ -265,7 +219,7 @@ void QBluetoothServer::setSecurityFlags(QBluetooth::SecurityFlags security)
QBluetooth::SecurityFlags QBluetoothServer::securityFlags() const
{
- return QBluetooth::NoSecurity;
+ return QBluetooth::Security::NoSecurity;
}
QT_END_NAMESPACE
diff --git a/src/bluetooth/qbluetoothservicediscoveryagent.cpp b/src/bluetooth/qbluetoothservicediscoveryagent.cpp
index f50aa45b..2f5d9dd6 100644
--- a/src/bluetooth/qbluetoothservicediscoveryagent.cpp
+++ b/src/bluetooth/qbluetoothservicediscoveryagent.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qbluetoothhostinfo.h"
#include "qbluetoothlocaldevice.h"
@@ -99,9 +63,12 @@ QT_BEGIN_NAMESPACE
\value NoError No error has occurred.
\value PoweredOffError The Bluetooth adaptor is powered off, power it on before doing discovery.
\value InputOutputError Writing or reading from the device resulted in an error.
- \value InvalidBluetoothAdapterError The passed local adapter address does not match the physical
- adapter address of any local Bluetooth device. This value
- was introduced by Qt 5.3.
+ \value [since 5.3] InvalidBluetoothAdapterError The passed local adapter address does not
+ match the physical adapter address of any
+ local Bluetooth device.
+ \value [since 6.4] MissingPermissionsError The operating system requests
+ permissions which were not
+ granted by the user.
\value UnknownError An unknown error has occurred.
*/
@@ -136,15 +103,18 @@ QT_BEGIN_NAMESPACE
Unlike the \l QBluetoothDeviceDiscoveryAgent::finished() signal this
signal will even be emitted when an error occurred during the service discovery. Therefore
- it is recommended to check the \l error() signal to evaluate the success of the
+ it is recommended to check the \l errorOccurred() signal to evaluate the success of the
service discovery discovery.
*/
/*!
- \fn void QBluetoothServiceDiscoveryAgent::error(QBluetoothServiceDiscoveryAgent::Error error)
+ \fn void QBluetoothServiceDiscoveryAgent::errorOccurred(QBluetoothServiceDiscoveryAgent::Error
+ error)
This signal is emitted when an \a error occurs. The \a error parameter describes the error that
occurred.
+
+ \since 6.2
*/
/*!
@@ -231,7 +201,7 @@ QList<QBluetoothServiceInfo> QBluetoothServiceDiscoveryAgent::discoveredServices
\l {QBluetoothServiceInfo::ServiceId}{ServiceId} and \l {QBluetoothServiceInfo::ServiceClassIds} {ServiceClassIds}
attributes.
- An empty UUID list is equivalent to a list containing only QBluetoothUuid::PublicBrowseGroup.
+ An empty UUID list is equivalent to a list containing only QBluetoothUuid::ServiceClassUuid::PublicBrowseGroup.
\sa uuidFilter()
*/
@@ -338,6 +308,9 @@ void QBluetoothServiceDiscoveryAgent::start(DiscoveryMode mode)
d->foundHostAdapterPath.clear();
#endif
d->setDiscoveryMode(mode);
+ // Clear any possible previous errors
+ d->error = QBluetoothServiceDiscoveryAgent::NoError;
+ d->errorString.clear();
if (d->deviceAddress.isNull()) {
d->startDeviceDiscovery();
} else {
@@ -408,9 +381,10 @@ bool QBluetoothServiceDiscoveryAgent::isActive() const
discovered by a scan, errors during service discovery on individual
devices are not saved and no signals are emitted. In this case, errors are
fairly normal as some devices may not respond to discovery or
- may no longer be in range. Such errors are surpressed. If no services
+ may no longer be in range. Such errors are suppressed. If no services
are returned, it can be assumed no services could be discovered.
+ Any possible previous errors are cleared upon restarting the discovery.
*/
QBluetoothServiceDiscoveryAgent::Error QBluetoothServiceDiscoveryAgent::error() const
{
@@ -422,6 +396,8 @@ QBluetoothServiceDiscoveryAgent::Error QBluetoothServiceDiscoveryAgent::error()
/*!
Returns a human-readable description of the last error that occurred during the
service discovery.
+
+ \sa error(), errorOccurred()
*/
QString QBluetoothServiceDiscoveryAgent::errorString() const
{
@@ -458,11 +434,10 @@ void QBluetoothServiceDiscoveryAgentPrivate::startDeviceDiscovery()
q, [this](const QBluetoothDeviceInfo &info){
this->_q_deviceDiscovered(info);
});
- QObject::connect(deviceDiscoveryAgent,
- QOverload<QBluetoothDeviceDiscoveryAgent::Error>::of(&QBluetoothDeviceDiscoveryAgent::error),
- q, [this](QBluetoothDeviceDiscoveryAgent::Error newError){
- this->_q_deviceDiscoveryError(newError);
- });
+ QObject::connect(deviceDiscoveryAgent, &QBluetoothDeviceDiscoveryAgent::errorOccurred, q,
+ [this](QBluetoothDeviceDiscoveryAgent::Error newError) {
+ this->_q_deviceDiscoveryError(newError);
+ });
}
setDiscoveryState(DeviceDiscovery);
@@ -500,7 +475,7 @@ void QBluetoothServiceDiscoveryAgentPrivate::_q_deviceDiscoveryFinished()
errorString = deviceDiscoveryAgent->errorString();
setDiscoveryState(Inactive);
Q_Q(QBluetoothServiceDiscoveryAgent);
- emit q->error(error);
+ emit q->errorOccurred(error);
emit q->finished();
return;
}
@@ -514,10 +489,10 @@ void QBluetoothServiceDiscoveryAgentPrivate::_q_deviceDiscoveryFinished()
void QBluetoothServiceDiscoveryAgentPrivate::_q_deviceDiscovered(const QBluetoothDeviceInfo &info)
{
// look for duplicates, and cached entries
- for (int i = 0; i < discoveredDevices.count(); i++) {
- if (discoveredDevices.at(i).address() == info.address())
- discoveredDevices.removeAt(i);
- }
+ const auto addressEquals = [](const auto &a) {
+ return [a](const auto &info) { return info.address() == a; };
+ };
+ erase_if(discoveredDevices, addressEquals(info.address()));
discoveredDevices.prepend(info);
}
@@ -536,7 +511,7 @@ void QBluetoothServiceDiscoveryAgentPrivate::_q_deviceDiscoveryError(QBluetoothD
setDiscoveryState(Inactive);
Q_Q(QBluetoothServiceDiscoveryAgent);
- emit q->error(error);
+ emit q->errorOccurred(error);
emit q->finished();
}
@@ -580,8 +555,7 @@ bool QBluetoothServiceDiscoveryAgentPrivate::isDuplicatedService(
const QBluetoothServiceInfo &serviceInfo) const
{
//check the service is not already part of our known list
- for (int j = 0; j < discoveredServices.count(); j++) {
- const QBluetoothServiceInfo &info = discoveredServices.at(j);
+ for (const QBluetoothServiceInfo &info : discoveredServices) {
if (info.device() == serviceInfo.device()
&& info.serviceClassUuids() == serviceInfo.serviceClassUuids()
&& info.serviceUuid() == serviceInfo.serviceUuid()
diff --git a/src/bluetooth/qbluetoothservicediscoveryagent.h b/src/bluetooth/qbluetoothservicediscoveryagent.h
index f1fa4640..9c34b432 100644
--- a/src/bluetooth/qbluetoothservicediscoveryagent.h
+++ b/src/bluetooth/qbluetoothservicediscoveryagent.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QBLUETOOTHSERVICEDISCOVERYAGENT_H
#define QBLUETOOTHSERVICEDISCOVERYAGENT_H
@@ -69,6 +33,7 @@ public:
InputOutputError = QBluetoothDeviceDiscoveryAgent::InputOutputError,
PoweredOffError = QBluetoothDeviceDiscoveryAgent::PoweredOffError,
InvalidBluetoothAdapterError = QBluetoothDeviceDiscoveryAgent::InvalidBluetoothAdapterError,
+ MissingPermissionsError = QBluetoothDeviceDiscoveryAgent::MissingPermissionsError,
UnknownError = QBluetoothDeviceDiscoveryAgent::UnknownError //=100
//New Errors must be added after Unknown Error the space before UnknownError is reserved
//for future device discovery errors
@@ -107,7 +72,7 @@ Q_SIGNALS:
void serviceDiscovered(const QBluetoothServiceInfo &info);
void finished();
void canceled();
- void error(QBluetoothServiceDiscoveryAgent::Error error);
+ void errorOccurred(QBluetoothServiceDiscoveryAgent::Error error);
private:
QBluetoothServiceDiscoveryAgentPrivate *d_ptr;
diff --git a/src/bluetooth/qbluetoothservicediscoveryagent_android.cpp b/src/bluetooth/qbluetoothservicediscoveryagent_android.cpp
index 3ab0d580..952ba3dd 100644
--- a/src/bluetooth/qbluetoothservicediscoveryagent_android.cpp
+++ b/src/bluetooth/qbluetoothservicediscoveryagent_android.cpp
@@ -1,60 +1,28 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+#include "qbluetoothservicediscoveryagent_p.h"
+#include "qbluetoothsocket_android_p.h"
+#include "android/servicediscoverybroadcastreceiver_p.h"
+#include "android/localdevicebroadcastreceiver_p.h"
+#include "android/androidutils_p.h"
+#include "android/jni_android_p.h"
+
+#include <QCoreApplication>
#include <QtCore/qcoreapplication.h>
#include <QtCore/QLoggingCategory>
#include <QtCore/QTimer>
-#include <QtCore/private/qjnihelpers_p.h>
-#include <QtAndroidExtras/QAndroidJniEnvironment>
+#include <QtCore/QJniEnvironment>
#include <QtBluetooth/QBluetoothHostInfo>
#include <QtBluetooth/QBluetoothLocalDevice>
#include <QtBluetooth/QBluetoothServiceDiscoveryAgent>
-#include "qbluetoothservicediscoveryagent_p.h"
-#include "qbluetoothsocket_android_p.h"
-#include "android/servicediscoverybroadcastreceiver_p.h"
-#include "android/localdevicebroadcastreceiver_p.h"
-
QT_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(QT_BT_ANDROID)
+static constexpr auto uuidFetchTimeLimit = std::chrono::seconds{4};
+
QBluetoothServiceDiscoveryAgentPrivate::QBluetoothServiceDiscoveryAgentPrivate(
QBluetoothServiceDiscoveryAgent *qp, const QBluetoothAddress &deviceAdapter)
: error(QBluetoothServiceDiscoveryAgent::NoError),
@@ -85,22 +53,14 @@ QBluetoothServiceDiscoveryAgentPrivate::QBluetoothServiceDiscoveryAgentPrivate(
}
}
- if (QtAndroidPrivate::androidSdkVersion() < 15)
- qCWarning(QT_BT_ANDROID)
- << "SDP not supported by Android API below version 15. Detected version: "
- << QtAndroidPrivate::androidSdkVersion()
- << "Service discovery will return empty list.";
-
-
/*
We assume that the current local adapter has been passed.
The logic below must change once there is more than one adapter.
*/
if (createAdapter)
- btAdapter = QAndroidJniObject::callStaticObjectMethod("android/bluetooth/BluetoothAdapter",
- "getDefaultAdapter",
- "()Landroid/bluetooth/BluetoothAdapter;");
+ btAdapter = getDefaultBluetoothAdapter();
+
if (!btAdapter.isValid())
qCWarning(QT_BT_ANDROID) << "Platform does not support Bluetooth";
@@ -123,6 +83,16 @@ void QBluetoothServiceDiscoveryAgentPrivate::start(const QBluetoothAddress &addr
{
Q_Q(QBluetoothServiceDiscoveryAgent);
+ if (!ensureAndroidPermission(QBluetoothPermission::Access)) {
+ qCWarning(QT_BT_ANDROID) << "Service discovery start() failed due to missing permissions";
+ error = QBluetoothServiceDiscoveryAgent::MissingPermissionsError;
+ errorString = QBluetoothServiceDiscoveryAgent::tr(
+ "Failed to start service discovery due to missing permissions.");
+ emit q->errorOccurred(error);
+ _q_serviceDiscoveryFinished();
+ return;
+ }
+
if (!btAdapter.isValid()) {
if (m_deviceAdapterAddress.isNull()) {
error = QBluetoothServiceDiscoveryAgent::UnknownError;
@@ -136,44 +106,17 @@ void QBluetoothServiceDiscoveryAgentPrivate::start(const QBluetoothAddress &addr
//abort any outstanding discoveries
discoveredDevices.clear();
- emit q->error(error);
+ emit q->errorOccurred(error);
_q_serviceDiscoveryFinished();
return;
}
- /* SDP discovery was officially added by Android API v15
- * BluetoothDevice.getUuids() existed in earlier APIs already and in the future we may use
- * reflection to support earlier Android versions than 15. Unfortunately
- * BluetoothDevice.fetchUuidsWithSdp() and related APIs had some structure changes
- * over time. Therefore we won't attempt this with reflection.
- *
- * TODO: Use reflection to support getUuuids() where possible.
- * */
- if (QtAndroidPrivate::androidSdkVersion() < 15) {
- qCWarning(QT_BT_ANDROID) << "Aborting SDP enquiry due to too low Android API version (requires v15+)";
-
- error = QBluetoothServiceDiscoveryAgent::UnknownError;
- errorString = QBluetoothServiceDiscoveryAgent::tr("Android API below v15 does not support SDP discovery");
-
- //abort any outstanding discoveries
- sdpCache.clear();
- discoveredDevices.clear();
- emit q->error(error);
- _q_serviceDiscoveryFinished();
-
- return;
- }
-
- QAndroidJniObject inputString = QAndroidJniObject::fromString(address.toString());
- QAndroidJniObject remoteDevice =
- btAdapter.callObjectMethod("getRemoteDevice",
- "(Ljava/lang/String;)Landroid/bluetooth/BluetoothDevice;",
- inputString.object<jstring>());
- QAndroidJniEnvironment env;
- if (env->ExceptionCheck()) {
- env->ExceptionClear();
- env->ExceptionDescribe();
+ QJniObject inputString = QJniObject::fromString(address.toString());
+ QJniObject remoteDevice =
+ btAdapter.callMethod<QtJniTypes::BluetoothDevice>("getRemoteDevice",
+ inputString.object<jstring>());
+ if (!remoteDevice.isValid()) {
//if it was only device then its error -> otherwise go to next device
if (singleDevice) {
@@ -182,7 +125,7 @@ void QBluetoothServiceDiscoveryAgentPrivate::start(const QBluetoothAddress &addr
qCWarning(QT_BT_ANDROID) << "Cannot start SDP for" << discoveredDevices.at(0).name()
<< "(" << address.toString() << ")";
- emit q->error(error);
+ emit q->errorOccurred(error);
}
_q_serviceDiscoveryFinished();
return;
@@ -194,14 +137,14 @@ void QBluetoothServiceDiscoveryAgentPrivate::start(const QBluetoothAddress &addr
<< ")" << address.toString() ;
//Minimal discovery uses BluetoothDevice.getUuids()
- QAndroidJniObject parcelUuidArray = remoteDevice.callObjectMethod(
- "getUuids", "()[Landroid/os/ParcelUuid;");
+ QJniObject parcelUuidArray =
+ remoteDevice.callMethod<QtJniTypes::ParcelUuidArray>("getUuids");
if (!parcelUuidArray.isValid()) {
if (singleDevice) {
error = QBluetoothServiceDiscoveryAgent::InputOutputError;
errorString = QBluetoothServiceDiscoveryAgent::tr("Cannot obtain service uuids");
- emit q->error(error);
+ emit q->errorOccurred(error);
}
qCWarning(QT_BT_ANDROID) << "Cannot retrieve SDP UUIDs for" << discoveredDevices.at(0).name()
<< "(" << address.toString() << ")";
@@ -252,9 +195,11 @@ void QBluetoothServiceDiscoveryAgentPrivate::stop()
discoveredDevices.clear();
//kill receiver to limit load of signals
- receiver->unregisterReceiver();
- receiver->deleteLater();
- receiver = nullptr;
+ if (receiver) {
+ receiver->unregisterReceiver();
+ receiver->deleteLater();
+ receiver = nullptr;
+ }
Q_Q(QBluetoothServiceDiscoveryAgent);
emit q->canceled();
@@ -265,32 +210,33 @@ void QBluetoothServiceDiscoveryAgentPrivate::_q_processFetchedUuids(
const QBluetoothAddress &address, const QList<QBluetoothUuid> &uuids)
{
//don't leave more data through if we are not interested anymore
- if (discoveredDevices.count() == 0)
+ if (discoveredDevices.isEmpty())
return;
//could not find any service for the current address/device -> go to next one
if (address.isNull() || uuids.isEmpty()) {
- if (discoveredDevices.count() == 1) {
+ if (discoveredDevices.size() == 1) {
Q_Q(QBluetoothServiceDiscoveryAgent);
- QTimer::singleShot(4000, q, [this]() {
+ QTimer::singleShot(uuidFetchTimeLimit, q, [this]() {
this->_q_fetchUuidsTimeout();
- });
+ }); // will also call _q_serviceDiscoveryFinished()
+ } else {
+ _q_serviceDiscoveryFinished();
}
- _q_serviceDiscoveryFinished();
return;
}
if (QT_BT_ANDROID().isDebugEnabled()) {
qCDebug(QT_BT_ANDROID) << "Found UUID for" << address.toString()
- << "\ncount: " << uuids.count();
+ << "\ncount: " << uuids.size();
QString result;
- for (int i = 0; i<uuids.count(); i++)
- result += uuids.at(i).toString() + QStringLiteral("**");
+ for (const QBluetoothUuid &uuid : uuids)
+ result += uuid.toString() + QLatin1String("**");
qCDebug(QT_BT_ANDROID) << result;
}
- /* In general there are two uuid events per device.
+ /* In general there may be up-to two uuid events per device.
* We'll wait for the second event to arrive before we process the UUIDs.
* We utilize a timeout to catch cases when the second
* event doesn't arrive at all.
@@ -305,7 +251,7 @@ void QBluetoothServiceDiscoveryAgentPrivate::_q_processFetchedUuids(
//prefer second uuid set over first
populateDiscoveredServices(pair.first, uuids);
- if (discoveredDevices.count() == 1 && sdpCache.isEmpty()) {
+ if (discoveredDevices.size() == 1 && sdpCache.isEmpty()) {
//last regular uuid data set from OS -> we finish here
_q_serviceDiscoveryFinished();
}
@@ -321,10 +267,10 @@ void QBluetoothServiceDiscoveryAgentPrivate::_q_processFetchedUuids(
sdpCache.insert(address, pair);
//the discovery on the last device cannot immediately finish
- //we have to grant the 2 seconds timeout delay
- if (discoveredDevices.count() == 1) {
+ //we have to grant the timeout delay to allow potential second event to arrive
+ if (discoveredDevices.size() == 1) {
Q_Q(QBluetoothServiceDiscoveryAgent);
- QTimer::singleShot(4000, q, [this]() {
+ QTimer::singleShot(uuidFetchTimeLimit, q, [this]() {
this->_q_fetchUuidsTimeout();
});
return;
@@ -355,18 +301,16 @@ void QBluetoothServiceDiscoveryAgentPrivate::populateDiscoveredServices(const QB
//find SPP and custom uuid
bool haveSppClass = false;
- QVector<int> customUuids;
+ QVarLengthArray<qsizetype> customUuids;
- for (int i = 0; i < uuids.count(); i++) {
+ for (qsizetype i = 0; i < uuids.size(); ++i) {
const QBluetoothUuid uuid = uuids.at(i);
if (uuid.isNull())
continue;
//check for SPP protocol
- bool ok = false;
- auto uuid16 = uuid.toUInt16(&ok);
- haveSppClass |= ok && uuid16 == QBluetoothUuid::SerialPort;
+ haveSppClass |= uuid == QBluetoothUuid::ServiceClassUuid::SerialPort;
//check for custom uuid
if (uuid.minimumSize() == 16)
@@ -375,7 +319,7 @@ void QBluetoothServiceDiscoveryAgentPrivate::populateDiscoveredServices(const QB
auto rfcommProtocolDescriptorList = []() -> QBluetoothServiceInfo::Sequence {
QBluetoothServiceInfo::Sequence protocol;
- protocol << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::Rfcomm))
+ protocol << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::ProtocolUuid::Rfcomm))
<< QVariant::fromValue(0);
return protocol;
};
@@ -383,13 +327,13 @@ void QBluetoothServiceDiscoveryAgentPrivate::populateDiscoveredServices(const QB
auto sppProfileDescriptorList = []() -> QBluetoothServiceInfo::Sequence {
QBluetoothServiceInfo::Sequence profileSequence;
QBluetoothServiceInfo::Sequence classId;
- classId << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::SerialPort));
+ classId << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::ServiceClassUuid::SerialPort));
classId << QVariant::fromValue(quint16(0x100));
profileSequence.append(QVariant::fromValue(classId));
return profileSequence;
};
- for (int i = 0; i < uuids.count(); i++) {
+ for (qsizetype i = 0; i < uuids.size(); ++i) {
const QBluetoothUuid &uuid = uuids.at(i);
if (uuid.isNull())
continue;
@@ -400,7 +344,7 @@ void QBluetoothServiceDiscoveryAgentPrivate::populateDiscoveredServices(const QB
QBluetoothServiceInfo::Sequence protocolDescriptorList;
{
QBluetoothServiceInfo::Sequence protocol;
- protocol << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::L2cap));
+ protocol << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::ProtocolUuid::L2cap));
protocolDescriptorList.append(QVariant::fromValue(protocol));
}
@@ -417,12 +361,12 @@ void QBluetoothServiceDiscoveryAgentPrivate::populateDiscoveredServices(const QB
QBluetoothServiceInfo::Sequence classId;
//set SPP service class uuid
classId << QVariant::fromValue(uuid);
- classId << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::SerialPort));
+ classId << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::ServiceClassUuid::SerialPort));
serviceInfo.setAttribute(QBluetoothServiceInfo::ServiceClassIds, classId);
serviceInfo.setServiceName(QBluetoothServiceDiscoveryAgent::tr("Serial Port Profile"));
serviceInfo.setServiceUuid(uuid);
- } else if (uuid == QBluetoothUuid{QBluetoothUuid::SerialPort}) {
+ } else if (uuid == QBluetoothUuid{QBluetoothUuid::ServiceClassUuid::SerialPort}) {
//set rfcomm protocol
protocolDescriptorList.append(QVariant::fromValue(rfcommProtocolDescriptorList()));
@@ -440,7 +384,7 @@ void QBluetoothServiceDiscoveryAgentPrivate::populateDiscoveredServices(const QB
serviceInfo.setAttribute(QBluetoothServiceInfo::ProtocolDescriptorList, protocolDescriptorList);
QBluetoothServiceInfo::Sequence publicBrowse;
- publicBrowse << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::PublicBrowseGroup));
+ publicBrowse << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::ServiceClassUuid::PublicBrowseGroup));
serviceInfo.setAttribute(QBluetoothServiceInfo::BrowseGroupList, publicBrowse);
if (!customUuids.contains(i)) {
@@ -456,7 +400,7 @@ void QBluetoothServiceDiscoveryAgentPrivate::populateDiscoveredServices(const QB
if (!uuidFilter.isEmpty()) {
bool match = uuidFilter.contains(serviceInfo.serviceUuid());
match |= uuidFilter.contains(QBluetoothSocketPrivateAndroid::reverseUuid(serviceInfo.serviceUuid()));
- for (const auto &uuid : qAsConst(uuidFilter)) {
+ for (const auto &uuid : std::as_const(uuidFilter)) {
match |= serviceInfo.serviceClassUuids().contains(uuid);
match |= serviceInfo.serviceClassUuids().contains(QBluetoothSocketPrivateAndroid::reverseUuid(uuid));
}
@@ -468,30 +412,39 @@ void QBluetoothServiceDiscoveryAgentPrivate::populateDiscoveredServices(const QB
//don't include the service if we already discovered it before
if (!isDuplicatedService(serviceInfo)) {
discoveredServices << serviceInfo;
- //qCDebug(QT_BT_ANDROID) << serviceInfo;
- emit q->serviceDiscovered(serviceInfo);
+ // Use queued connection to allow us finish the service discovery reporting;
+ // the application might call stop() when it has detected the service-of-interest,
+ // which in turn can cause the use of already released resources
+ QMetaObject::invokeMethod(q, "serviceDiscovered", Qt::QueuedConnection,
+ Q_ARG(QBluetoothServiceInfo, serviceInfo));
}
}
}
void QBluetoothServiceDiscoveryAgentPrivate::_q_fetchUuidsTimeout()
{
- if (sdpCache.isEmpty())
+ // In practice if device list is empty, discovery has been stopped or bluetooth is offline
+ if (discoveredDevices.isEmpty())
return;
- QPair<QBluetoothDeviceInfo,QList<QBluetoothUuid> > pair;
- const QList<QBluetoothAddress> keys = sdpCache.keys();
- for (const QBluetoothAddress &key : keys) {
- pair = sdpCache.take(key);
- populateDiscoveredServices(pair.first, pair.second);
+ // Process remaining services in the cache (these didn't get a second UUID event)
+ if (!sdpCache.isEmpty()) {
+ QPair<QBluetoothDeviceInfo,QList<QBluetoothUuid> > pair;
+ const QList<QBluetoothAddress> keys = sdpCache.keys();
+ for (const QBluetoothAddress &key : keys) {
+ pair = sdpCache.take(key);
+ populateDiscoveredServices(pair.first, pair.second);
+ }
}
Q_ASSERT(sdpCache.isEmpty());
//kill receiver to limit load of signals
- receiver->unregisterReceiver();
- receiver->deleteLater();
- receiver = nullptr;
+ if (receiver) {
+ receiver->unregisterReceiver();
+ receiver->deleteLater();
+ receiver = nullptr;
+ }
_q_serviceDiscoveryFinished();
}
@@ -506,12 +459,14 @@ void QBluetoothServiceDiscoveryAgentPrivate::_q_hostModeStateChanged(QBluetoothL
errorString = QBluetoothServiceDiscoveryAgent::tr("Device is powered off");
//kill receiver to limit load of signals
- receiver->unregisterReceiver();
- receiver->deleteLater();
- receiver = nullptr;
+ if (receiver) {
+ receiver->unregisterReceiver();
+ receiver->deleteLater();
+ receiver = nullptr;
+ }
Q_Q(QBluetoothServiceDiscoveryAgent);
- emit q->error(error);
+ emit q->errorOccurred(error);
_q_serviceDiscoveryFinished();
}
}
diff --git a/src/bluetooth/qbluetoothservicediscoveryagent_bluez.cpp b/src/bluetooth/qbluetoothservicediscoveryagent_bluez.cpp
index 6a93143b..844c79b1 100644
--- a/src/bluetooth/qbluetoothservicediscoveryagent_bluez.cpp
+++ b/src/bluetooth/qbluetoothservicediscoveryagent_bluez.cpp
@@ -1,48 +1,9 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qbluetoothservicediscoveryagent.h"
#include "qbluetoothservicediscoveryagent_p.h"
-#include "bluez/manager_p.h"
-#include "bluez/adapter_p.h"
-#include "bluez/device_p.h"
#include "bluez/bluez5_helper_p.h"
#include "bluez/objectmanager_p.h"
#include "bluez/adapter1_bluez5_p.h"
@@ -51,8 +12,9 @@
#include <QtCore/QLibraryInfo>
#include <QtCore/QLoggingCategory>
#include <QtCore/QProcess>
+#include <QtCore/QScopeGuard>
+
#include <QtDBus/QDBusPendingCallWatcher>
-#include <QtConcurrent/QtConcurrentRun>
QT_BEGIN_NAMESPACE
@@ -64,26 +26,15 @@ QBluetoothServiceDiscoveryAgentPrivate::QBluetoothServiceDiscoveryAgentPrivate(
mode(QBluetoothServiceDiscoveryAgent::MinimalDiscovery), singleDevice(false),
q_ptr(qp)
{
- if (isBluez5()) {
- managerBluez5 = new OrgFreedesktopDBusObjectManagerInterface(
- QStringLiteral("org.bluez"), QStringLiteral("/"),
- QDBusConnection::systemBus());
- qRegisterMetaType<QBluetoothServiceDiscoveryAgent::Error>();
- } else {
- qRegisterMetaType<ServiceMap>();
- qDBusRegisterMetaType<ServiceMap>();
-
- manager = new OrgBluezManagerInterface(QStringLiteral("org.bluez"), QStringLiteral("/"),
- QDBusConnection::systemBus());
- }
+ initializeBluez5();
+ manager = new OrgFreedesktopDBusObjectManagerInterface(
+ QStringLiteral("org.bluez"), QStringLiteral("/"), QDBusConnection::systemBus());
+ qRegisterMetaType<QBluetoothServiceDiscoveryAgent::Error>();
}
QBluetoothServiceDiscoveryAgentPrivate::~QBluetoothServiceDiscoveryAgentPrivate()
{
- delete device;
delete manager;
- delete managerBluez5;
- delete adapter;
}
void QBluetoothServiceDiscoveryAgentPrivate::start(const QBluetoothAddress &address)
@@ -92,53 +43,6 @@ void QBluetoothServiceDiscoveryAgentPrivate::start(const QBluetoothAddress &addr
qCDebug(QT_BT_BLUEZ) << "Discovery on: " << address.toString() << "Mode:" << DiscoveryMode();
- if (managerBluez5) {
- startBluez5(address);
- return;
- }
-
- QDBusPendingReply<QDBusObjectPath> reply;
- if (m_deviceAdapterAddress.isNull())
- reply = manager->DefaultAdapter();
- else
- reply = manager->FindAdapter(m_deviceAdapterAddress.toString());
-
- reply.waitForFinished();
- if (reply.isError()) {
- error = QBluetoothServiceDiscoveryAgent::InputOutputError;
- errorString = QBluetoothServiceDiscoveryAgent::tr("Unable to find appointed local adapter");
- emit q->error(error);
- _q_serviceDiscoveryFinished();
- return;
- }
-
- adapter = new OrgBluezAdapterInterface(QStringLiteral("org.bluez"), reply.value().path(),
- QDBusConnection::systemBus());
-
- if (m_deviceAdapterAddress.isNull()) {
- QDBusPendingReply<QVariantMap> reply = adapter->GetProperties();
- reply.waitForFinished();
- if (!reply.isError()) {
- const QBluetoothAddress path_address(reply.value().value(QStringLiteral("Address")).toString());
- m_deviceAdapterAddress = path_address;
- }
- }
-
- QDBusPendingReply<QDBusObjectPath> deviceObjectPath = adapter->FindDevice(address.toString());
-
- QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(deviceObjectPath, q);
- watcher->setProperty("_q_BTaddress", QVariant::fromValue(address));
- QObject::connect(watcher, &QDBusPendingCallWatcher::finished,
- q, [this](QDBusPendingCallWatcher *watcher){
- this->_q_foundDevice(watcher);
- });
-}
-
-// Bluez 5
-void QBluetoothServiceDiscoveryAgentPrivate::startBluez5(const QBluetoothAddress &address)
-{
- Q_Q(QBluetoothServiceDiscoveryAgent);
-
if (foundHostAdapterPath.isEmpty()) {
// check that we match adapter addresses or use first if it wasn't specified
@@ -148,7 +52,7 @@ void QBluetoothServiceDiscoveryAgentPrivate::startBluez5(const QBluetoothAddress
discoveredDevices.clear();
error = QBluetoothServiceDiscoveryAgent::InputOutputError;
errorString = QBluetoothDeviceDiscoveryAgent::tr("Cannot access adapter during service discovery");
- emit q->error(error);
+ emit q->errorOccurred(error);
_q_serviceDiscoveryFinished();
return;
}
@@ -160,7 +64,7 @@ void QBluetoothServiceDiscoveryAgentPrivate::startBluez5(const QBluetoothAddress
error = QBluetoothServiceDiscoveryAgent::InvalidBluetoothAdapterError;
errorString = QBluetoothServiceDiscoveryAgent::tr("Cannot find local Bluetooth adapter");
- emit q->error(error);
+ emit q->errorOccurred(error);
_q_serviceDiscoveryFinished();
return;
@@ -175,7 +79,7 @@ void QBluetoothServiceDiscoveryAgentPrivate::startBluez5(const QBluetoothAddress
error = QBluetoothServiceDiscoveryAgent::PoweredOffError;
errorString = QBluetoothServiceDiscoveryAgent::tr("Local device is powered off");
- emit q->error(error);
+ emit q->errorOccurred(error);
_q_serviceDiscoveryFinished();
return;
@@ -198,7 +102,7 @@ void QBluetoothServiceDiscoveryAgentPrivate::runExternalSdpScan(
Q_Q(QBluetoothServiceDiscoveryAgent);
if (!sdpScannerProcess) {
- const QString binPath = QLibraryInfo::location(QLibraryInfo::BinariesPath);
+ const QString binPath = QLibraryInfo::path(QLibraryInfo::LibraryExecutablesPath);
QFileInfo fileInfo(binPath, QStringLiteral("sdpscanner"));
if (!fileInfo.exists() || !fileInfo.isExecutable()) {
_q_finishSdpScan(QBluetoothServiceDiscoveryAgent::InputOutputError,
@@ -227,7 +131,7 @@ void QBluetoothServiceDiscoveryAgentPrivate::runExternalSdpScan(
// No filter implies PUBLIC_BROWSE_GROUP based SDP scan
if (!uuidFilter.isEmpty()) {
arguments << QLatin1String("-u"); // cmd line option for list of uuids
- for (const QBluetoothUuid& uuid : qAsConst(uuidFilter))
+ for (const QBluetoothUuid& uuid : std::as_const(uuidFilter))
arguments << uuid.toString();
}
@@ -235,7 +139,6 @@ void QBluetoothServiceDiscoveryAgentPrivate::runExternalSdpScan(
sdpScannerProcess->start();
}
-// Bluez 5
void QBluetoothServiceDiscoveryAgentPrivate::_q_sdpScannerDone(int exitCode, QProcess::ExitStatus status)
{
if (status != QProcess::NormalExit || exitCode != 0) {
@@ -252,19 +155,20 @@ void QBluetoothServiceDiscoveryAgentPrivate::_q_sdpScannerDone(int exitCode, QPr
}
QStringList xmlRecords;
- const QByteArray output = sdpScannerProcess->readAllStandardOutput();
- const QString decodedData = QString::fromUtf8(QByteArray::fromBase64(output));
+ const QByteArray utf8Data = QByteArray::fromBase64(sdpScannerProcess->readAllStandardOutput());
+ const QByteArrayView utf8View = utf8Data;
// split the various xml docs up
- int next;
- int start = decodedData.indexOf(QStringLiteral("<?xml"), 0);
+ constexpr auto matcher = qMakeStaticByteArrayMatcher("<?xml");
+ qsizetype next;
+ qsizetype start = matcher.indexIn(utf8View, 0);
if (start != -1) {
do {
- next = decodedData.indexOf(QStringLiteral("<?xml"), start + 1);
+ next = matcher.indexIn(utf8View, start + 1);
if (next != -1)
- xmlRecords.append(decodedData.mid(start, next-start));
+ xmlRecords.append(QString::fromUtf8(utf8View.sliced(start, next - start)));
else
- xmlRecords.append(decodedData.mid(start, decodedData.size() - start));
+ xmlRecords.append(QString::fromUtf8(utf8View.sliced(start)));
start = next;
} while ( start != -1);
}
@@ -272,7 +176,6 @@ void QBluetoothServiceDiscoveryAgentPrivate::_q_sdpScannerDone(int exitCode, QPr
_q_finishSdpScan(QBluetoothServiceDiscoveryAgent::NoError, QString(), xmlRecords);
}
-// Bluez 5
void QBluetoothServiceDiscoveryAgentPrivate::_q_finishSdpScan(QBluetoothServiceDiscoveryAgent::Error errorCode,
const QString &errorDescription,
const QStringList &xmlRecords)
@@ -288,7 +191,7 @@ void QBluetoothServiceDiscoveryAgentPrivate::_q_finishSdpScan(QBluetoothServiceD
discoveredDevices.clear();
error = errorCode;
errorString = errorDescription;
- emit q->error(error);
+ emit q->errorOccurred(error);
} else if (!xmlRecords.isEmpty() && discoveryState() != Inactive) {
for (const QString &record : xmlRecords) {
QBluetoothServiceInfo serviceInfo = parseServiceXml(record);
@@ -320,7 +223,10 @@ void QBluetoothServiceDiscoveryAgentPrivate::_q_finishSdpScan(QBluetoothServiceD
for (const QBluetoothUuid &id : serviceClassUuids) {
if (id.minimumSize() == 16) {
serviceInfo.setServiceUuid(id);
- serviceInfo.setServiceName(QBluetoothServiceDiscoveryAgent::tr("Custom Service"));
+ if (serviceInfo.serviceName().isEmpty()) {
+ serviceInfo.setServiceName(
+ QBluetoothServiceDiscoveryAgent::tr("Custom Service"));
+ }
QBluetoothServiceInfo::Sequence modSeq =
serviceInfo.attribute(QBluetoothServiceInfo::ServiceClassIds).value<QBluetoothServiceInfo::Sequence>();
modSeq.removeOne(QVariant::fromValue(id));
@@ -334,8 +240,10 @@ void QBluetoothServiceDiscoveryAgentPrivate::_q_finishSdpScan(QBluetoothServiceD
qCDebug(QT_BT_BLUEZ) << "Discovered services" << discoveredDevices.at(0).address().toString()
<< serviceInfo.serviceName() << serviceInfo.serviceUuid()
<< ">>>" << serviceInfo.serviceClassUuids();
-
- emit q->serviceDiscovered(serviceInfo);
+ // Use queued connection to allow us finish the service looping; the application
+ // might call stop() when it has detected the service-of-interest.
+ QMetaObject::invokeMethod(q, "serviceDiscovered", Qt::QueuedConnection,
+ Q_ARG(QBluetoothServiceInfo, serviceInfo));
}
}
}
@@ -346,22 +254,6 @@ void QBluetoothServiceDiscoveryAgentPrivate::_q_finishSdpScan(QBluetoothServiceD
void QBluetoothServiceDiscoveryAgentPrivate::stop()
{
qCDebug(QT_BT_BLUEZ) << Q_FUNC_INFO << "Stop called";
- if (device) {
- //we are waiting for _q_discoveredServices() to be called
- // adapter is already 0
- QDBusPendingReply<> reply = device->CancelDiscovery();
- reply.waitForFinished();
-
- device->deleteLater();
- device = nullptr;
- Q_ASSERT(!adapter);
- } else if (adapter) {
- //we are waiting for _q_createdDevice() to be called
- adapter->deleteLater();
- adapter = nullptr;
- Q_ASSERT(!device);
- }
-
discoveredDevices.clear();
setDiscoveryState(Inactive);
@@ -379,263 +271,6 @@ void QBluetoothServiceDiscoveryAgentPrivate::stop()
emit q->canceled();
}
-void QBluetoothServiceDiscoveryAgentPrivate::_q_foundDevice(QDBusPendingCallWatcher *watcher)
-{
- if (!adapter) {
- watcher->deleteLater();
- return;
- }
-
- Q_Q(QBluetoothServiceDiscoveryAgent);
-
- const QBluetoothAddress &address = watcher->property("_q_BTaddress").value<QBluetoothAddress>();
-
- qCDebug(QT_BT_BLUEZ) << Q_FUNC_INFO << "found" << address.toString();
-
- QDBusPendingReply<QDBusObjectPath> deviceObjectPath = *watcher;
- watcher->deleteLater();
- if (deviceObjectPath.isError()) {
- if (deviceObjectPath.error().name() != QStringLiteral("org.bluez.Error.DoesNotExist")) {
- qCDebug(QT_BT_BLUEZ) << "Find device failed Error: " << error << deviceObjectPath.error().name();
- delete adapter;
- adapter = nullptr;
- if (singleDevice) {
- error = QBluetoothServiceDiscoveryAgent::InputOutputError;
- errorString = QBluetoothServiceDiscoveryAgent::tr("Unable to access device");
- emit q->error(error);
- }
- _q_serviceDiscoveryFinished();
- return;
- }
-
- deviceObjectPath = adapter->CreateDevice(address.toString());
- watcher = new QDBusPendingCallWatcher(deviceObjectPath, q);
- watcher->setProperty("_q_BTaddress", QVariant::fromValue(address));
- QObject::connect(watcher, &QDBusPendingCallWatcher::finished,
- q, [this](QDBusPendingCallWatcher *watcher){
- this->_q_createdDevice(watcher);
- });
-
- return;
- }
-
- qCDebug(QT_BT_BLUEZ) << Q_FUNC_INFO << "path" << deviceObjectPath.value().path();
- discoverServices(deviceObjectPath.value().path());
-}
-
-void QBluetoothServiceDiscoveryAgentPrivate::_q_createdDevice(QDBusPendingCallWatcher *watcher)
-{
- Q_Q(QBluetoothServiceDiscoveryAgent);
-
- if (!adapter) {
- watcher->deleteLater();
- return;
- }
-
- const QBluetoothAddress &address = watcher->property("_q_BTaddress").value<QBluetoothAddress>();
-
- qCDebug(QT_BT_BLUEZ) << Q_FUNC_INFO << "created" << address.toString();
-
- QDBusPendingReply<QDBusObjectPath> deviceObjectPath = *watcher;
- watcher->deleteLater();
- if (deviceObjectPath.isError()) {
- if (deviceObjectPath.error().name() != QLatin1String("org.bluez.Error.AlreadyExists")) {
- qCDebug(QT_BT_BLUEZ) << "Create device failed Error: " << error << deviceObjectPath.error().name();
- delete adapter;
- adapter = nullptr;
- if (singleDevice) {
- error = QBluetoothServiceDiscoveryAgent::InputOutputError;
- errorString = QBluetoothServiceDiscoveryAgent::tr("Unable to access device");
- emit q->error(error);
- }
- _q_serviceDiscoveryFinished();
- return;
- }
- }
-
- qCDebug(QT_BT_BLUEZ) << Q_FUNC_INFO << "path" << deviceObjectPath.value().path();
- discoverServices(deviceObjectPath.value().path());
-}
-
-void QBluetoothServiceDiscoveryAgentPrivate::discoverServices(const QString &deviceObjectPath)
-{
- Q_Q(QBluetoothServiceDiscoveryAgent);
-
- device = new OrgBluezDeviceInterface(QStringLiteral("org.bluez"),
- deviceObjectPath,
- QDBusConnection::systemBus());
- delete adapter;
- adapter = nullptr;
-
- QVariantMap deviceProperties;
- QString classType;
- QDBusPendingReply<QVariantMap> deviceReply = device->GetProperties();
- deviceReply.waitForFinished();
- if (!deviceReply.isError()) {
- deviceProperties = deviceReply.value();
- classType = deviceProperties.value(QStringLiteral("Class")).toString();
- }
-
- /*
- * Low Energy services in bluez are represented as the list of the paths that can be
- * accessed with org.bluez.Characteristic
- */
- //QDBusArgument services = v.value(QLatin1String("Services")).value<QDBusArgument>();
-
-
- /*
- * Bluez v4.1 does not have extra bit which gives information if device is Bluetooth
- * Low Energy device and the way to discover it is with Class property of the Bluetooth device.
- * Low Energy devices do not have property Class.
- * In case we have LE device finish service discovery; otherwise search for regular services.
- */
- if (classType.isEmpty()) { //is BLE device or device properties above not retrievable
- qCDebug(QT_BT_BLUEZ) << "Discovered BLE-only device. Normal service discovery skipped.";
- delete device;
- device = nullptr;
-
- const QStringList deviceUuids = deviceProperties.value(QStringLiteral("UUIDs")).toStringList();
- for (int i = 0; i < deviceUuids.size(); i++) {
- QString b = deviceUuids.at(i);
- b = b.remove(QLatin1Char('{')).remove(QLatin1Char('}'));
- const QBluetoothUuid uuid(b);
-
- qCDebug(QT_BT_BLUEZ) << "Discovered service" << uuid << uuidFilter.size();
- QBluetoothServiceInfo service;
- service.setDevice(discoveredDevices.at(0));
- bool ok = false;
- quint16 serviceClass = uuid.toUInt16(&ok);
- if (ok)
- service.setServiceName(QBluetoothUuid::serviceClassToString(
- static_cast<QBluetoothUuid::ServiceClassUuid>(serviceClass)));
-
- QBluetoothServiceInfo::Sequence classId;
- classId << QVariant::fromValue(uuid);
- service.setAttribute(QBluetoothServiceInfo::ServiceClassIds, classId);
-
- QBluetoothServiceInfo::Sequence protocolDescriptorList;
- {
- QBluetoothServiceInfo::Sequence protocol;
- protocol << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::L2cap));
- protocolDescriptorList.append(QVariant::fromValue(protocol));
- }
- {
- QBluetoothServiceInfo::Sequence protocol;
- protocol << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::Att));
- protocolDescriptorList.append(QVariant::fromValue(protocol));
- }
- service.setAttribute(QBluetoothServiceInfo::ProtocolDescriptorList, protocolDescriptorList);
-
- if (uuidFilter.isEmpty())
- emit q->serviceDiscovered(service);
- else {
- for (int j = 0; j < uuidFilter.size(); j++) {
- if (uuidFilter.at(j) == uuid)
- emit q->serviceDiscovered(service);
- }
- }
- }
-
- if (singleDevice && deviceReply.isError()) {
- error = QBluetoothServiceDiscoveryAgent::InputOutputError;
- errorString = QBluetoothServiceDiscoveryAgent::tr("Unable to access device");
- emit q->error(error);
- }
- _q_serviceDiscoveryFinished();
- } else {
- QString pattern;
- for (const QBluetoothUuid &uuid : qAsConst(uuidFilter))
- pattern += uuid.toString().remove(QLatin1Char('{')).remove(QLatin1Char('}')) + QLatin1Char(' ');
-
- pattern = pattern.trimmed();
- qCDebug(QT_BT_BLUEZ) << Q_FUNC_INFO << "Discover restrictions:" << pattern;
-
- QDBusPendingReply<ServiceMap> discoverReply = device->DiscoverServices(pattern);
- QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(discoverReply, q);
- QObject::connect(watcher, &QDBusPendingCallWatcher::finished,
- q, [this](QDBusPendingCallWatcher *watcher){
- this->_q_discoveredServices(watcher);
- });
- }
-}
-
-// Bluez 4
-void QBluetoothServiceDiscoveryAgentPrivate::_q_discoveredServices(QDBusPendingCallWatcher *watcher)
-{
- if (!device) {
- watcher->deleteLater();
- return;
- }
-
- qCDebug(QT_BT_BLUEZ) << Q_FUNC_INFO;
- Q_Q(QBluetoothServiceDiscoveryAgent);
-
- QDBusPendingReply<ServiceMap> reply = *watcher;
- if (reply.isError()) {
- qCDebug(QT_BT_BLUEZ) << "discoveredServices error: " << error << reply.error().message();
- watcher->deleteLater();
- if (singleDevice) {
- error = QBluetoothServiceDiscoveryAgent::UnknownError;
- errorString = reply.error().message();
- emit q->error(error);
- }
- delete device;
- device = nullptr;
- _q_serviceDiscoveryFinished();
- return;
- }
-
- const ServiceMap map = reply.value();
-
- qCDebug(QT_BT_BLUEZ) << "Parsing xml" << discoveredDevices.at(0).address().toString() << discoveredDevices.count() << map.count();
-
-
-
- for (const QString &record : map) {
- QBluetoothServiceInfo serviceInfo = parseServiceXml(record);
-
- if (!serviceInfo.isValid())
- continue;
-
- // Don't need to apply uuidFilter because Bluez 4 applies
- // search pattern during DiscoverServices() call
-
- Q_Q(QBluetoothServiceDiscoveryAgent);
- // Some service uuids are unknown to Bluez. In such cases we fall back
- // to our own naming resolution.
- if (serviceInfo.serviceName().isEmpty()
- && !serviceInfo.serviceClassUuids().isEmpty()) {
- const QList<QBluetoothUuid> classUuids = serviceInfo.serviceClassUuids();
- for (const QBluetoothUuid &classUuid : classUuids) {
- bool ok = false;
- QBluetoothUuid::ServiceClassUuid clsId
- = static_cast<QBluetoothUuid::ServiceClassUuid>(classUuid.toUInt16(&ok));
- if (ok) {
- serviceInfo.setServiceName(QBluetoothUuid::serviceClassToString(clsId));
- break;
- }
- }
- }
-
- if (!isDuplicatedService(serviceInfo)) {
- discoveredServices.append(serviceInfo);
- qCDebug(QT_BT_BLUEZ) << "Discovered services" << discoveredDevices.at(0).address().toString()
- << serviceInfo.serviceName();
- emit q->serviceDiscovered(serviceInfo);
- }
-
- // could stop discovery, check for state
- if (discoveryState() == Inactive)
- qCDebug(QT_BT_BLUEZ) << "Exit discovery after stop";
- }
-
- watcher->deleteLater();
- delete device;
- device = nullptr;
-
- _q_serviceDiscoveryFinished();
-}
-
QBluetoothServiceInfo QBluetoothServiceDiscoveryAgentPrivate::parseServiceXml(
const QString& xmlRecord)
{
@@ -650,7 +285,7 @@ QBluetoothServiceInfo QBluetoothServiceDiscoveryAgentPrivate::parseServiceXml(
if (xml.tokenType() == QXmlStreamReader::StartElement &&
xml.name() == QLatin1String("attribute")) {
quint16 attributeId =
- xml.attributes().value(QLatin1String("id")).toString().toUShort(nullptr, 0);
+ xml.attributes().value(QLatin1String("id")).toUShort(nullptr, 0);
if (xml.readNextStartElement()) {
const QVariant value = readAttributeValue(xml);
@@ -672,14 +307,13 @@ void QBluetoothServiceDiscoveryAgentPrivate::performMinimalServiceDiscovery(cons
Q_Q(QBluetoothServiceDiscoveryAgent);
- QDBusPendingReply<ManagedObjectList> reply = managerBluez5->GetManagedObjects();
+ QDBusPendingReply<ManagedObjectList> reply = manager->GetManagedObjects();
reply.waitForFinished();
if (reply.isError()) {
if (singleDevice) {
error = QBluetoothServiceDiscoveryAgent::InputOutputError;
errorString = reply.error().message();
- emit q->error(error);
-
+ emit q->errorOccurred(error);
}
_q_serviceDiscoveryFinished();
return;
@@ -716,7 +350,7 @@ void QBluetoothServiceDiscoveryAgentPrivate::performMinimalServiceDiscovery(cons
qCDebug(QT_BT_BLUEZ) << "Minimal uuid list for" << deviceAddress.toString() << uuidStrings;
QBluetoothUuid uuid;
- for (int i = 0; i < uuidStrings.count(); i++) {
+ for (qsizetype i = 0; i < uuidStrings.size(); ++i) {
uuid = QBluetoothUuid(uuidStrings.at(i));
if (uuid.isNull())
continue;
@@ -744,12 +378,12 @@ void QBluetoothServiceDiscoveryAgentPrivate::performMinimalServiceDiscovery(cons
QBluetoothServiceInfo::Sequence protocolDescriptorList;
{
QBluetoothServiceInfo::Sequence protocol;
- protocol << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::L2cap));
+ protocol << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::ProtocolUuid::L2cap));
protocolDescriptorList.append(QVariant::fromValue(protocol));
}
{
QBluetoothServiceInfo::Sequence protocol;
- protocol << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::Att));
+ protocol << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::ProtocolUuid::Att));
protocolDescriptorList.append(QVariant::fromValue(protocol));
}
serviceInfo.setAttribute(QBluetoothServiceInfo::ProtocolDescriptorList, protocolDescriptorList);
@@ -768,51 +402,47 @@ void QBluetoothServiceDiscoveryAgentPrivate::performMinimalServiceDiscovery(cons
QVariant QBluetoothServiceDiscoveryAgentPrivate::readAttributeValue(QXmlStreamReader &xml)
{
+ auto skippingCurrentElementByDefault = qScopeGuard([&] { xml.skipCurrentElement(); });
+
if (xml.name() == QLatin1String("boolean")) {
- const QString value = xml.attributes().value(QStringLiteral("value")).toString();
- xml.skipCurrentElement();
- return value == QLatin1String("true");
+ return xml.attributes().value(QLatin1String("value")) == QLatin1String("true");
} else if (xml.name() == QLatin1String("uint8")) {
- quint8 value = xml.attributes().value(QStringLiteral("value")).toString().toUShort(nullptr, 0);
- xml.skipCurrentElement();
+ quint8 value = xml.attributes().value(QLatin1String("value")).toUShort(nullptr, 0);
return value;
} else if (xml.name() == QLatin1String("uint16")) {
- quint16 value = xml.attributes().value(QStringLiteral("value")).toString().toUShort(nullptr, 0);
- xml.skipCurrentElement();
+ quint16 value = xml.attributes().value(QLatin1String("value")).toUShort(nullptr, 0);
return value;
} else if (xml.name() == QLatin1String("uint32")) {
- quint32 value = xml.attributes().value(QStringLiteral("value")).toString().toUInt(nullptr, 0);
- xml.skipCurrentElement();
+ quint32 value = xml.attributes().value(QLatin1String("value")).toUInt(nullptr, 0);
return value;
} else if (xml.name() == QLatin1String("uint64")) {
- quint64 value = xml.attributes().value(QStringLiteral("value")).toString().toULongLong(nullptr, 0);
- xml.skipCurrentElement();
+ quint64 value = xml.attributes().value(QLatin1String("value")).toULongLong(nullptr, 0);
return value;
} else if (xml.name() == QLatin1String("uuid")) {
QBluetoothUuid uuid;
- const QString value = xml.attributes().value(QStringLiteral("value")).toString();
- if (value.startsWith(QStringLiteral("0x"))) {
- if (value.length() == 6) {
+ const QStringView value = xml.attributes().value(QLatin1String("value"));
+ if (value.startsWith(QLatin1String("0x"))) {
+ if (value.size() == 6) {
quint16 v = value.toUShort(nullptr, 0);
uuid = QBluetoothUuid(v);
- } else if (value.length() == 10) {
+ } else if (value.size() == 10) {
quint32 v = value.toUInt(nullptr, 0);
uuid = QBluetoothUuid(v);
}
} else {
- uuid = QBluetoothUuid(value);
+ uuid = QBluetoothUuid(value.toString());
}
- xml.skipCurrentElement();
return QVariant::fromValue(uuid);
} else if (xml.name() == QLatin1String("text") || xml.name() == QLatin1String("url")) {
- QString value = xml.attributes().value(QStringLiteral("value")).toString();
- if (xml.attributes().value(QStringLiteral("encoding")) == QLatin1String("hex"))
- value = QString::fromUtf8(QByteArray::fromHex(value.toLatin1()));
- xml.skipCurrentElement();
- return value;
+ const QStringView value = xml.attributes().value(QLatin1String("value"));
+ if (xml.attributes().value(QLatin1String("encoding")) == QLatin1String("hex"))
+ return QString::fromUtf8(QByteArray::fromHex(value.toLatin1()));
+ return value.toString();
} else if (xml.name() == QLatin1String("sequence")) {
QBluetoothServiceInfo::Sequence sequence;
+ skippingCurrentElementByDefault.dismiss(); // we skip several elements here
+
while (xml.readNextStartElement()) {
QVariant value = readAttributeValue(xml);
sequence.append(value);
@@ -821,9 +451,8 @@ QVariant QBluetoothServiceDiscoveryAgentPrivate::readAttributeValue(QXmlStreamRe
return QVariant::fromValue<QBluetoothServiceInfo::Sequence>(sequence);
} else {
qCWarning(QT_BT_BLUEZ) << "unknown attribute type"
- << xml.name().toString()
- << xml.attributes().value(QStringLiteral("value")).toString();
- xml.skipCurrentElement();
+ << xml.name()
+ << xml.attributes().value(QLatin1String("value"));
return QVariant();
}
}
diff --git a/src/bluetooth/qbluetoothservicediscoveryagent_macos.mm b/src/bluetooth/qbluetoothservicediscoveryagent_macos.mm
index f6bee6bf..10d36e98 100644
--- a/src/bluetooth/qbluetoothservicediscoveryagent_macos.mm
+++ b/src/bluetooth/qbluetoothservicediscoveryagent_macos.mm
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qbluetoothservicediscoveryagent_p.h"
#include "qbluetoothservicediscoveryagent.h"
@@ -46,8 +10,9 @@
#include "darwin/btutility_p.h"
#include "darwin/uistrings_p.h"
+#include <QtCore/qoperatingsystemversion.h>
+#include <QtCore/qcoreapplication.h>
#include <QtCore/qloggingcategory.h>
-#include <QtCore/qscopedpointer.h>
#include <QtCore/qstring.h>
#include <QtCore/qglobal.h>
#include <QtCore/qdebug.h>
@@ -62,7 +27,6 @@ QT_BEGIN_NAMESPACE
namespace {
using DarwinBluetooth::RetainPolicy;
-using ObjCServiceInquiry = QT_MANGLE_NAMESPACE(DarwinBTSDPInquiry);
}
@@ -78,7 +42,7 @@ QBluetoothServiceDiscoveryAgentPrivate::QBluetoothServiceDiscoveryAgentPrivate(
{
Q_ASSERT(q_ptr);
- serviceInquiry.reset([[ObjCServiceInquiry alloc] initWithDelegate:this], RetainPolicy::noInitialRetain);
+ serviceInquiry.reset([[DarwinBTSDPInquiry alloc] initWithDelegate:this], RetainPolicy::noInitialRetain);
}
QBluetoothServiceDiscoveryAgentPrivate::~QBluetoothServiceDiscoveryAgentPrivate()
@@ -103,7 +67,7 @@ void QBluetoothServiceDiscoveryAgentPrivate::start(const QBluetoothAddress &devi
if (singleDevice) {
error = QBluetoothServiceDiscoveryAgent::PoweredOffError;
errorString = QCoreApplication::translate(SERVICE_DISCOVERY, SD_LOCAL_DEV_OFF);
- emit q_ptr->error(error);
+ emit q_ptr->errorOccurred(error);
}
return _q_serviceDiscoveryFinished();
@@ -113,7 +77,7 @@ void QBluetoothServiceDiscoveryAgentPrivate::start(const QBluetoothAddress &devi
performMinimalServiceDiscovery(deviceAddress);
} else {
IOReturn result = kIOReturnSuccess;
- auto nativeInquiry = serviceInquiry.getAs<ObjCServiceInquiry>();
+ auto nativeInquiry = serviceInquiry.getAs<DarwinBTSDPInquiry>();
if (uuidFilter.size())
result = [nativeInquiry performSDPQueryWithDevice:deviceAddress filters:uuidFilter];
else
@@ -133,7 +97,7 @@ void QBluetoothServiceDiscoveryAgentPrivate::stop()
discoveredDevices.clear();
// "Stops" immediately.
- [serviceInquiry.getAs<ObjCServiceInquiry>() stopSDPQuery];
+ [serviceInquiry.getAs<DarwinBTSDPInquiry>() stopSDPQuery];
emit q_ptr->canceled();
}
@@ -149,15 +113,38 @@ void QBluetoothServiceDiscoveryAgentPrivate::SDPInquiryFinished(void *generic)
QT_BT_MAC_AUTORELEASEPOOL;
NSArray *const records = device.services;
+ qCDebug(QT_BT_DARWIN) << "SDP finished for device" << [device nameOrAddress]
+ << ", services found:" << [records count];
for (IOBluetoothSDPServiceRecord *record in records) {
QBluetoothServiceInfo serviceInfo;
Q_ASSERT_X(discoveredDevices.size() >= 1, Q_FUNC_INFO, "invalid number of devices");
+ qCDebug(QT_BT_DARWIN) << "Processing service" << [record getServiceName];
serviceInfo.setDevice(discoveredDevices.at(0));
DarwinBluetooth::extract_service_record(record, serviceInfo);
- if (!serviceInfo.isValid())
+ if (!serviceInfo.isValid()) {
+ qCDebug(QT_BT_DARWIN) << "Discarding invalid service";
continue;
+ }
+
+ if (QOperatingSystemVersion::current() > QOperatingSystemVersion::MacOSBigSur
+ && uuidFilter.size()) {
+ const auto &serviceId = serviceInfo.serviceUuid();
+ bool match = !serviceId.isNull() && uuidFilter.contains(serviceId);
+ if (!match) {
+ const auto &classUuids = serviceInfo.serviceClassUuids();
+ for (const auto &uuid : classUuids) {
+ if (uuidFilter.contains(uuid)) {
+ match = true;
+ break;
+ }
+ }
+ if (!match)
+ continue;
+ }
+ }
+
if (!isDuplicatedService(serviceInfo)) {
discoveredServices.append(serviceInfo);
@@ -174,7 +161,7 @@ void QBluetoothServiceDiscoveryAgentPrivate::SDPInquiryFinished(void *generic)
void QBluetoothServiceDiscoveryAgentPrivate::SDPInquiryError(void *device, IOReturn errorCode)
{
- Q_UNUSED(device)
+ Q_UNUSED(device);
qCWarning(QT_BT_DARWIN) << "inquiry failed with IOKit code:" << int(errorCode);
@@ -183,7 +170,7 @@ void QBluetoothServiceDiscoveryAgentPrivate::SDPInquiryError(void *device, IORet
if (singleDevice) {
error = QBluetoothServiceDiscoveryAgent::UnknownError;
errorString = QCoreApplication::translate(DEV_DISCOVERY, DD_UNKNOWN_ERROR);
- emit q_ptr->error(error);
+ emit q_ptr->errorOccurred(error);
}
_q_serviceDiscoveryFinished();
@@ -201,7 +188,7 @@ void QBluetoothServiceDiscoveryAgentPrivate::performMinimalServiceDiscovery(cons
if (singleDevice) {
error = QBluetoothServiceDiscoveryAgent::UnknownError;
errorString = QCoreApplication::translate(SERVICE_DISCOVERY, SD_MINIMAL_FAILED);
- emit q_ptr->error(error);
+ emit q_ptr->errorOccurred(error);
}
} else {
diff --git a/src/bluetooth/qbluetoothservicediscoveryagent_p.cpp b/src/bluetooth/qbluetoothservicediscoveryagent_p.cpp
index a23fda95..aaaf3dd9 100644
--- a/src/bluetooth/qbluetoothservicediscoveryagent_p.cpp
+++ b/src/bluetooth/qbluetoothservicediscoveryagent_p.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qbluetoothservicediscoveryagent.h"
#include "qbluetoothservicediscoveryagent_p.h"
@@ -73,3 +37,5 @@ void QBluetoothServiceDiscoveryAgentPrivate::stop()
}
QT_END_NAMESPACE
+
+#include "moc_qbluetoothservicediscoveryagent_p.cpp"
diff --git a/src/bluetooth/qbluetoothservicediscoveryagent_p.h b/src/bluetooth/qbluetoothservicediscoveryagent_p.h
index d9b1e5f4..2bdfd404 100644
--- a/src/bluetooth/qbluetoothservicediscoveryagent_p.h
+++ b/src/bluetooth/qbluetoothservicediscoveryagent_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QBLUETOOTHSERVICEDISCOVERYAGENT_P_H
#define QBLUETOOTHSERVICEDISCOVERYAGENT_P_H
@@ -72,21 +36,7 @@ class QXmlStreamReader;
QT_END_NAMESPACE
#endif
-#ifdef QT_WIN_BLUETOOTH
-#include <QtCore/QVariant>
-
-QT_BEGIN_NAMESPACE
-class QThread;
-
-class ThreadWorkerFind : public QObject
-{
- Q_OBJECT
-signals:
- void findFinished(QVariant result);
-};
-QT_END_NAMESPACE
-
-#elif defined(QT_WINRT_BLUETOOTH)
+#ifdef QT_WINRT_BLUETOOTH
#include <QtCore/QPointer>
#endif
@@ -95,14 +45,17 @@ QT_END_NAMESPACE
#include "darwin/btraii_p.h"
#endif
+#ifdef QT_ANDROID_BLUETOOTH
+#include <QtCore/QJniObject>
+#include <QtBluetooth/QBluetoothLocalDevice>
+#endif
+
QT_BEGIN_NAMESPACE
class QBluetoothDeviceDiscoveryAgent;
#ifdef QT_ANDROID_BLUETOOTH
class ServiceDiscoveryBroadcastReceiver;
class LocalDeviceBroadcastReceiver;
-#include <QtAndroidExtras/QAndroidJniObject>
-#include <QtBluetooth/QBluetoothLocalDevice>
#endif
#ifdef QT_WINRT_BLUETOOTH
@@ -110,7 +63,7 @@ class QWinRTBluetoothServiceDiscoveryWorker;
#endif
class QBluetoothServiceDiscoveryAgentPrivate
-#if defined QT_WINRT_BLUETOOTH || defined QT_WIN_BLUETOOTH
+#if defined(QT_WINRT_BLUETOOTH)
: public QObject
{
Q_OBJECT
@@ -149,15 +102,6 @@ public:
void _q_serviceDiscoveryFinished();
void _q_deviceDiscoveryError(QBluetoothDeviceDiscoveryAgent::Error);
#if QT_CONFIG(bluez)
- void _q_discoveredServices(QDBusPendingCallWatcher *watcher);
- void _q_createdDevice(QDBusPendingCallWatcher *watcher);
- void _q_foundDevice(QDBusPendingCallWatcher *watcher);
- //Slots below are used for discovering Bluetooth Low Energy devices. It will be used with Bluez 5.x version.
- /*
- void _g_discoveredGattService();
- void _q_discoverGattCharacteristics(QDBusPendingCallWatcher *watcher);
- void _q_discoveredGattCharacteristic(QDBusPendingCallWatcher *watcher);
- */
void _q_sdpScannerDone(int exitCode, QProcess::ExitStatus status);
void _q_finishSdpScan(QBluetoothServiceDiscoveryAgent::Error errorCode,
const QString &errorDescription,
@@ -171,10 +115,6 @@ public:
void _q_fetchUuidsTimeout();
void _q_hostModeStateChanged(QBluetoothLocalDevice::HostMode state);
#endif
-#ifdef QT_WIN_BLUETOOTH
- void _q_nextSdpScan(const QVariant &input);
- bool serviceMatches(const QBluetoothServiceInfo &info);
-#endif
private:
void start(const QBluetoothAddress &address);
@@ -189,7 +129,6 @@ private:
QVariant readAttributeValue(QXmlStreamReader &xml);
QBluetoothServiceInfo parseServiceXml(const QString& xml);
void performMinimalServiceDiscovery(const QBluetoothAddress &deviceAddress);
- void discoverServices(const QString &deviceObjectPath);
#endif
public:
@@ -211,10 +150,7 @@ private:
bool singleDevice;
#if QT_CONFIG(bluez)
QString foundHostAdapterPath;
- OrgBluezManagerInterface *manager = nullptr;
- OrgFreedesktopDBusObjectManagerInterface *managerBluez5 = nullptr;
- OrgBluezAdapterInterface *adapter = nullptr;
- OrgBluezDeviceInterface *device = nullptr;
+ OrgFreedesktopDBusObjectManagerInterface *manager = nullptr;
QProcess *sdpScannerProcess = nullptr;
#endif
@@ -222,27 +158,24 @@ private:
ServiceDiscoveryBroadcastReceiver *receiver = nullptr;
LocalDeviceBroadcastReceiver *localDeviceReceiver = nullptr;
- QAndroidJniObject btAdapter;
+ QJniObject btAdapter;
+ // The sdpCache caches service discovery results while it is running, and is
+ // cleared once finished. The cache is used as we may (or may not) get more accurate
+ // results after the first result. This temporary caching allows to send the
+ // serviceDiscovered() signal once per service and with the most accurate information.
+ // Partial cache clearing may occur already during the scan if the second (more accurate)
+ // scan result is received.
QMap<QBluetoothAddress,QPair<QBluetoothDeviceInfo,QList<QBluetoothUuid> > > sdpCache;
#endif
-#ifdef QT_WIN_BLUETOOTH
-private:
- bool pendingStop;
- bool pendingFinish;
-
- QThread *threadFind = nullptr;
- ThreadWorkerFind *threadWorkerFind = nullptr;
-#endif
-
#ifdef QT_WINRT_BLUETOOTH
private slots:
void processFoundService(quint64 deviceAddress, const QBluetoothServiceInfo &info);
void onScanFinished(quint64 deviceAddress);
- void onScanCanceled();
void onError();
private:
+ void releaseWorker();
QPointer<QWinRTBluetoothServiceDiscoveryWorker> worker;
#endif
diff --git a/src/bluetooth/qbluetoothservicediscoveryagent_win.cpp b/src/bluetooth/qbluetoothservicediscoveryagent_win.cpp
deleted file mode 100644
index c34443aa..00000000
--- a/src/bluetooth/qbluetoothservicediscoveryagent_win.cpp
+++ /dev/null
@@ -1,437 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qbluetoothservicediscoveryagent.h"
-#include "qbluetoothservicediscoveryagent_p.h"
-
-#include <QtCore/QByteArray>
-#include <QtCore/QLibrary>
-#include <QtCore/QLoggingCategory>
-#include <QtCore/QThread>
-#include <QtCore/QUrl>
-
-#include <initguid.h>
-#include <winsock2.h>
-#include <qt_windows.h>
-
-#if defined(Q_CC_MINGW)
-// Workaround for MinGW headers declaring BluetoothSdpGetElementData incorrectly.
-# define BluetoothSdpGetElementData _BluetoothSdpGetElementData_notok
-# include <bluetoothapis.h>
-# undef BluetoothSdpGetElementData
- extern "C" DWORD WINAPI BluetoothSdpGetElementData(LPBYTE, ULONG, PSDP_ELEMENT_DATA);
-#else
-# include <bluetoothapis.h>
-#endif
-
-#include <ws2bth.h>
-#include <iostream>
-
-QT_BEGIN_NAMESPACE
-
-struct FindServiceResult {
- QBluetoothServiceInfo info;
- Qt::HANDLE hSearch = INVALID_HANDLE_VALUE;
- int systemError = NO_ERROR;
-};
-
-Q_DECLARE_LOGGING_CATEGORY(QT_BT_WINDOWS)
-
-static QList<QVariant> spdContainerToVariantList(LPBYTE containerStream, ULONG containerLength);
-
-static QVariant spdElementToVariant(const SDP_ELEMENT_DATA &element)
-{
- QVariant variant;
-
- switch (element.type) {
- case SDP_TYPE_UINT: {
- switch (element.specificType) {
- case SDP_ST_UINT128:
- //Not supported!!!
- break;
- case SDP_ST_UINT64:
- variant = QVariant::fromValue<quint64>(element.data.uint64);
- break;
- case SDP_ST_UINT32:
- variant = QVariant::fromValue<quint32>(element.data.uint32);
- break;
- case SDP_ST_UINT16:
- variant = QVariant::fromValue<quint16>(element.data.uint16);
- break;
- case SDP_ST_UINT8:
- variant = QVariant::fromValue<quint8>(element.data.uint8);
- break;
- default:
- break;
- }
- break;
- }
- case SDP_TYPE_INT: {
- switch (element.specificType) {
- case SDP_ST_INT128: {
- //Not supported!!!
- break;
- }
- case SDP_ST_INT64:
- variant = QVariant::fromValue<qint64>(element.data.int64);
- break;
- case SDP_ST_INT32:
- variant = QVariant::fromValue<qint32>(element.data.int32);
- break;
- case SDP_ST_INT16:
- variant = QVariant::fromValue<qint16>(element.data.int16);
- break;
- case SDP_ST_INT8:
- variant = QVariant::fromValue<qint8>(element.data.int8);
- break;
- default:
- break;
- }
- break;
- }
- case SDP_TYPE_UUID: {
- switch (element.specificType) {
- case SDP_ST_UUID128:
- variant = QVariant::fromValue(QBluetoothUuid(element.data.uuid128));
- break;
- case SDP_ST_UUID32:
- variant = QVariant::fromValue(QBluetoothUuid(quint32(element.data.uuid32)));
- break;
- case SDP_ST_UUID16:
- variant = QVariant::fromValue(QBluetoothUuid(quint16(element.data.uuid16)));
- break;
- default:
- break;
- }
- break;
- }
- case SDP_TYPE_STRING: {
- const QByteArray stringBuffer(reinterpret_cast<const char*>(element.data.string.value), element.data.string.length);
- variant = QVariant::fromValue<QString>(QString::fromLocal8Bit(stringBuffer));
- break;
- }
- case SDP_TYPE_URL: {
- const QString urlString = QString::fromLocal8Bit(reinterpret_cast<const char*>(element.data.url.value),
- int(element.data.url.length));
- const QUrl url(urlString);
- if (url.isValid())
- variant = QVariant::fromValue<QUrl>(url);
- break;
- }
- case SDP_TYPE_SEQUENCE: {
- const QList<QVariant> sequenceList = spdContainerToVariantList(element.data.sequence.value,
- element.data.sequence.length);
- const QBluetoothServiceInfo::Sequence sequence(sequenceList);
- variant = QVariant::fromValue(sequence);
- break;
- }
- case SDP_TYPE_ALTERNATIVE: {
- const QList<QVariant> alternativeList = spdContainerToVariantList(element.data.alternative.value,
- element.data.alternative.length);
- const QBluetoothServiceInfo::Alternative alternative(alternativeList);
- variant = QVariant::fromValue(alternative);
- break;
- }
- case SDP_TYPE_BOOLEAN:
- variant = QVariant::fromValue<bool>(bool(element.data.booleanVal));
- break;
- case SDP_TYPE_NIL:
- break;
- default:
- break;
- }
-
- return variant;
-}
-
-static QList<QVariant> spdContainerToVariantList(LPBYTE containerStream, ULONG containerLength)
-{
- HBLUETOOTH_CONTAINER_ELEMENT iter = nullptr;
- SDP_ELEMENT_DATA element = {};
-
- QList<QVariant> sequence;
-
- for (;;) {
- const DWORD result = ::BluetoothSdpGetContainerElementData(containerStream,
- containerLength,
- &iter,
- &element);
-
- if (result == ERROR_SUCCESS) {
- const QVariant variant = spdElementToVariant(element);
- sequence.append(variant);
- } else if (result == ERROR_NO_MORE_ITEMS) {
- break;
- } else if (result == ERROR_INVALID_PARAMETER) {
- break;
- }
- }
-
- return sequence;
-}
-
-#if defined(Q_CC_MINGW)
-# define SDP_CALLBACK
-#else
-# define SDP_CALLBACK QT_WIN_CALLBACK
-#endif
-static BOOL SDP_CALLBACK bluetoothSdpCallback(ULONG attributeId, LPBYTE valueStream, ULONG streamSize, LPVOID param)
-{
- QBluetoothServiceInfo *result = static_cast<QBluetoothServiceInfo*>(param);
-
- SDP_ELEMENT_DATA element = {};
-
- if (::BluetoothSdpGetElementData(valueStream, streamSize, &element) == ERROR_SUCCESS) {
- switch (element.type) {
- case SDP_TYPE_UINT:
- case SDP_TYPE_INT:
- case SDP_TYPE_UUID:
- case SDP_TYPE_STRING:
- case SDP_TYPE_URL:
- case SDP_TYPE_BOOLEAN:
- case SDP_TYPE_SEQUENCE:
- case SDP_TYPE_ALTERNATIVE: {
- const QVariant variant = spdElementToVariant(element);
-
- result->setAttribute(attributeId, variant);
- break;
- }
- case SDP_TYPE_NIL:
- break;
- default:
- break;
- }
- }
- return true;
-}
-
-enum {
- WSAControlFlags = LUP_FLUSHCACHE
- | LUP_RETURN_NAME
- | LUP_RETURN_TYPE
- | LUP_RETURN_ADDR
- | LUP_RETURN_BLOB
- | LUP_RETURN_COMMENT
-};
-
-static FindServiceResult findNextService(HANDLE hSearch)
-{
- FindServiceResult result;
- result.hSearch = hSearch;
-
- QByteArray resultBuffer(2048, 0);
- WSAQUERYSET *resultQuery = reinterpret_cast<WSAQUERYSET*>(resultBuffer.data());
- DWORD resultBufferSize = DWORD(resultBuffer.size());
- const int resultCode = ::WSALookupServiceNext(hSearch,
- WSAControlFlags,
- &resultBufferSize,
- resultQuery);
-
- if (resultCode == SOCKET_ERROR) {
- result.systemError = ::WSAGetLastError();
- if (result.systemError == WSA_E_NO_MORE)
- ::WSALookupServiceEnd(hSearch);
- return result;
- }
-
- if (resultQuery->lpBlob
- && ::BluetoothSdpEnumAttributes(resultQuery->lpBlob->pBlobData,
- resultQuery->lpBlob->cbSize,
- bluetoothSdpCallback,
- &result.info)) {
- return result;
- } else {
- result.systemError = GetLastError();
- }
- return result;
-}
-
-static FindServiceResult findFirstService(const QBluetoothAddress &address)
-{
- WSAData wsadata = {};
- FindServiceResult result;
-
- // IPv6 requires Winsock v2.0 or better.
- if (::WSAStartup(MAKEWORD(2, 0), &wsadata) != 0) {
- result.systemError = ::WSAGetLastError();
- return result;
- }
-
- const QString addressAsString = QStringLiteral("(%1)").arg(address.toString());
- QVector<WCHAR> addressAsWChar(addressAsString.size() + 1);
- addressAsString.toWCharArray(addressAsWChar.data());
-
- GUID protocol = L2CAP_PROTOCOL_UUID; //Search for L2CAP and RFCOMM services
-
- WSAQUERYSET serviceQuery = {};
- serviceQuery.dwSize = sizeof(WSAQUERYSET);
- serviceQuery.lpServiceClassId = &protocol;
- serviceQuery.dwNameSpace = NS_BTH;
- serviceQuery.dwNumberOfCsAddrs = 0;
- serviceQuery.lpszContext = addressAsWChar.data();
-
- HANDLE hSearch = nullptr;
- const int resultCode = ::WSALookupServiceBegin(&serviceQuery,
- WSAControlFlags,
- &hSearch);
- if (resultCode == SOCKET_ERROR) {
- result.systemError = ::WSAGetLastError();
- ::WSALookupServiceEnd(hSearch);
- return result;
- }
- return findNextService(hSearch);
-}
-
-QBluetoothServiceDiscoveryAgentPrivate::QBluetoothServiceDiscoveryAgentPrivate(
- QBluetoothServiceDiscoveryAgent *qp, const QBluetoothAddress &deviceAdapter)
- : error(QBluetoothServiceDiscoveryAgent::NoError),
- state(Inactive),
- deviceDiscoveryAgent(0),
- mode(QBluetoothServiceDiscoveryAgent::MinimalDiscovery),
- singleDevice(false),
- pendingStop(false),
- pendingFinish(false),
- q_ptr(qp)
-{
- Q_UNUSED(deviceAdapter);
-
- threadFind = new QThread;
- threadWorkerFind = new ThreadWorkerFind;
- threadWorkerFind->moveToThread(threadFind);
- connect(threadWorkerFind, &ThreadWorkerFind::findFinished, this, &QBluetoothServiceDiscoveryAgentPrivate::_q_nextSdpScan);
- connect(threadFind, &QThread::finished, threadWorkerFind, &ThreadWorkerFind::deleteLater);
- connect(threadFind, &QThread::finished, threadFind, &QThread::deleteLater);
- threadFind->start();
-}
-
-QBluetoothServiceDiscoveryAgentPrivate::~QBluetoothServiceDiscoveryAgentPrivate()
-{
- if (pendingFinish)
- stop();
- if (threadFind)
- threadFind->quit();
-}
-
-void QBluetoothServiceDiscoveryAgentPrivate::start(const QBluetoothAddress &address)
-{
- if (!pendingFinish) {
- pendingFinish = true;
- pendingStop = false;
-
- const auto threadWorker = threadWorkerFind;
- QMetaObject::invokeMethod(threadWorkerFind, [threadWorker, address]()
- {
- const FindServiceResult result = findFirstService(address);
- emit threadWorker->findFinished(QVariant::fromValue(result));
- }, Qt::QueuedConnection);
- }
-}
-
-void QBluetoothServiceDiscoveryAgentPrivate::stop()
-{
- pendingStop = true;
-}
-
-bool QBluetoothServiceDiscoveryAgentPrivate::serviceMatches(const QBluetoothServiceInfo &info)
-{
- if (uuidFilter.isEmpty())
- return true;
-
- if (uuidFilter.contains(info.serviceUuid()))
- return true;
-
- const QList<QBluetoothUuid> serviceClassUuids = info.serviceClassUuids();
- for (const QBluetoothUuid &uuid : serviceClassUuids)
- if (uuidFilter.contains(uuid))
- return true;
-
- return false;
-}
-
-void QBluetoothServiceDiscoveryAgentPrivate::_q_nextSdpScan(const QVariant &input)
-{
- Q_Q(QBluetoothServiceDiscoveryAgent);
- auto result = input.value<FindServiceResult>();
-
- if (pendingStop) {
- ::WSALookupServiceEnd(result.hSearch);
- pendingStop = false;
- pendingFinish = false;
- emit q->canceled();
- } else {
- if (result.systemError == WSA_E_NO_MORE) {
- result.systemError = NO_ERROR;
- } else if (result.systemError != NO_ERROR) {
- if (result.hSearch != INVALID_HANDLE_VALUE)
- ::WSALookupServiceEnd(result.hSearch);
- error = (result.systemError == ERROR_INVALID_HANDLE) ?
- QBluetoothServiceDiscoveryAgent::InvalidBluetoothAdapterError
- : QBluetoothServiceDiscoveryAgent::InputOutputError;
- errorString = qt_error_string(result.systemError);
- qCWarning(QT_BT_WINDOWS) << errorString;
- emit q->error(this->error);
- } else {
-
- if (serviceMatches(result.info)) {
- result.info.setDevice(discoveredDevices.at(0));
- if (result.info.isValid()) {
- if (!isDuplicatedService(result.info)) {
- discoveredServices.append(result.info);
- emit q->serviceDiscovered(result.info);
- }
- }
- }
-
- const auto threadWorker = threadWorkerFind;
- const auto hSearch = result.hSearch;
- QMetaObject::invokeMethod(threadWorkerFind, [threadWorker, hSearch]()
- {
- FindServiceResult result = findNextService(hSearch);
- emit threadWorker->findFinished(QVariant::fromValue(result));
- }, Qt::QueuedConnection);
- return;
- }
- pendingFinish = false;
- _q_serviceDiscoveryFinished();
- }
-}
-
-QT_END_NAMESPACE
-
-Q_DECLARE_METATYPE(FindServiceResult)
diff --git a/src/bluetooth/qbluetoothservicediscoveryagent_winrt.cpp b/src/bluetooth/qbluetoothservicediscoveryagent_winrt.cpp
index 69b6ac06..928dc4b6 100644
--- a/src/bluetooth/qbluetoothservicediscoveryagent_winrt.cpp
+++ b/src/bluetooth/qbluetoothservicediscoveryagent_winrt.cpp
@@ -1,51 +1,12 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qbluetoothservicediscoveryagent.h"
#include "qbluetoothservicediscoveryagent_p.h"
+#include "qbluetoothutils_winrt_p.h"
-#ifdef CLASSIC_APP_BUILD
-#define Q_OS_WINRT
-#endif
-#include <qfunctions_winrt.h>
#include <QtCore/QLoggingCategory>
-#include <QtCore/private/qeventdispatcher_winrt_p.h>
+#include <QtCore/private/qfunctions_winrt_p.h>
#include <functional>
#include <robuffer.h>
@@ -72,7 +33,7 @@ typedef Collections::IIterator<ValueItem *> ValueIterator;
QT_BEGIN_NAMESPACE
-Q_DECLARE_LOGGING_CATEGORY(QT_BT_WINRT)
+Q_DECLARE_LOGGING_CATEGORY(QT_BT_WINDOWS)
#define TYPE_UINT8 8
#define TYPE_UINT16 9
@@ -82,6 +43,13 @@ Q_DECLARE_LOGGING_CATEGORY(QT_BT_WINRT)
#define TYPE_STRING 37
#define TYPE_SEQUENCE 53
+// Helper to reverse given uchar array
+static void reverseArray(uchar data[], size_t length)
+{
+ for (size_t i = length; i > length/2; i--)
+ std::swap(data[length - i], data[i - 1]);
+}
+
class QWinRTBluetoothServiceDiscoveryWorker : public QObject
{
Q_OBJECT
@@ -94,7 +62,6 @@ public:
Q_SIGNALS:
void serviceFound(quint64 deviceAddress, const QBluetoothServiceInfo &info);
void scanFinished(quint64 deviceAddress);
- void scanCanceled();
void errorOccured();
private:
@@ -121,26 +88,21 @@ QWinRTBluetoothServiceDiscoveryWorker::~QWinRTBluetoothServiceDiscoveryWorker()
void QWinRTBluetoothServiceDiscoveryWorker::start()
{
- HRESULT hr;
- hr = QEventDispatcherWinRT::runOnXamlThread([this]() {
- ComPtr<IBluetoothDeviceStatics> deviceStatics;
- HRESULT hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Devices_Bluetooth_BluetoothDevice).Get(), &deviceStatics);
- Q_ASSERT_SUCCEEDED(hr);
- ComPtr<IAsyncOperation<BluetoothDevice *>> deviceFromAddressOperation;
- hr = deviceStatics->FromBluetoothAddressAsync(m_targetAddress, &deviceFromAddressOperation);
- Q_ASSERT_SUCCEEDED(hr);
- hr = deviceFromAddressOperation->put_Completed(Callback<IAsyncOperationCompletedHandler<BluetoothDevice *>>
- (this, &QWinRTBluetoothServiceDiscoveryWorker::onBluetoothDeviceFoundAsync).Get());
- Q_ASSERT_SUCCEEDED(hr);
- return S_OK;
- });
+ ComPtr<IBluetoothDeviceStatics> deviceStatics;
+ HRESULT hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Devices_Bluetooth_BluetoothDevice).Get(), &deviceStatics);
+ Q_ASSERT_SUCCEEDED(hr);
+ ComPtr<IAsyncOperation<BluetoothDevice *>> deviceFromAddressOperation;
+ hr = deviceStatics->FromBluetoothAddressAsync(m_targetAddress, &deviceFromAddressOperation);
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = deviceFromAddressOperation->put_Completed(Callback<IAsyncOperationCompletedHandler<BluetoothDevice *>>
+ (this, &QWinRTBluetoothServiceDiscoveryWorker::onBluetoothDeviceFoundAsync).Get());
Q_ASSERT_SUCCEEDED(hr);
}
HRESULT QWinRTBluetoothServiceDiscoveryWorker::onBluetoothDeviceFoundAsync(IAsyncOperation<BluetoothDevice *> *op, AsyncStatus status)
{
if (status != Completed) {
- qCDebug(QT_BT_WINRT) << "Could not find device";
+ qCDebug(QT_BT_WINDOWS) << "Could not find device";
emit errorOccured();
return S_OK;
}
@@ -152,17 +114,6 @@ HRESULT QWinRTBluetoothServiceDiscoveryWorker::onBluetoothDeviceFoundAsync(IAsyn
quint64 address;
device->get_BluetoothAddress(&address);
-#ifdef QT_WINRT_LIMITED_SERVICEDISCOVERY
- if (m_mode != QBluetoothServiceDiscoveryAgent::MinimalDiscovery) {
- qWarning() << "Used Windows SDK version (" << QString::number(QT_UCRTVERSION) << ") does not "
- "support full service discovery. Consider updating to a more recent Windows 10 "
- "SDK (14393 or above).";
- }
- ComPtr<IVectorView<RfcommDeviceService*>> commServices;
- hr = device->get_RfcommServices(&commServices);
- Q_ASSERT_SUCCEEDED(hr);
- processServiceSearchResult(address, commServices);
-#else // !QT_WINRT_LIMITED_SERVICEDISOVERY
ComPtr<IBluetoothDevice3> device3;
hr = device.As(&device3);
Q_ASSERT_SUCCEEDED(hr);
@@ -175,7 +126,7 @@ HRESULT QWinRTBluetoothServiceDiscoveryWorker::onBluetoothDeviceFoundAsync(IAsyn
([address, this](IAsyncOperation<RfcommDeviceServicesResult *> *op, AsyncStatus status)
{
if (status != Completed) {
- qCDebug(QT_BT_WINRT) << "Could not obtain service list";
+ qCDebug(QT_BT_WINDOWS) << "Could not obtain service list";
emit errorOccured();
return S_OK;
}
@@ -190,7 +141,6 @@ HRESULT QWinRTBluetoothServiceDiscoveryWorker::onBluetoothDeviceFoundAsync(IAsyn
return S_OK;
}).Get());
Q_ASSERT_SUCCEEDED(hr);
-#endif // !QT_WINRT_LIMITED_SERVICEDISOVERY
return S_OK;
}
@@ -234,7 +184,7 @@ void QWinRTBluetoothServiceDiscoveryWorker::processServiceSearchResult(quint64 a
hr = service->GetSdpRawAttributesAsync(op.GetAddressOf());
if (FAILED(hr)) {
emit errorOccured();
- qDebug() << "Check manifest capabilities";
+ qCDebug(QT_BT_WINDOWS) << "Check manifest capabilities";
continue;
}
ComPtr<IMapView<UINT32, IBuffer *>> mapView;
@@ -285,33 +235,35 @@ void QWinRTBluetoothServiceDiscoveryWorker::processServiceSearchResult(quint64 a
hr = dataReader->ReadByte(&value);
Q_ASSERT_SUCCEEDED(hr);
info.setAttribute(key, value);
- qCDebug(QT_BT_WINRT) << "UUID" << uuid << "KEY" << Qt::hex << key << "TYPE" << Qt::dec << type << "UINT8" << Qt::hex << value;
+ qCDebug(QT_BT_WINDOWS) << "UUID" << uuid << "KEY" << Qt::hex << key << "TYPE" << Qt::dec << type << "UINT8" << Qt::hex << value;
} else if (type == TYPE_UINT16) {
quint16 value;
hr = dataReader->ReadUInt16(&value);
Q_ASSERT_SUCCEEDED(hr);
info.setAttribute(key, value);
- qCDebug(QT_BT_WINRT) << "UUID" << uuid << "KEY" << Qt::hex << key << "TYPE" << Qt::dec << type << "UINT16" << Qt::hex << value;
+ qCDebug(QT_BT_WINDOWS) << "UUID" << uuid << "KEY" << Qt::hex << key << "TYPE" << Qt::dec << type << "UINT16" << Qt::hex << value;
} else if (type == TYPE_UINT32) {
quint32 value;
hr = dataReader->ReadUInt32(&value);
Q_ASSERT_SUCCEEDED(hr);
info.setAttribute(key, value);
- qCDebug(QT_BT_WINRT) << "UUID" << uuid << "KEY" << Qt::hex << key << "TYPE" << Qt::dec << type << "UINT32" << Qt::hex << value;
+ qCDebug(QT_BT_WINDOWS) << "UUID" << uuid << "KEY" << Qt::hex << key << "TYPE" << Qt::dec << type << "UINT32" << Qt::hex << value;
} else if (type == TYPE_SHORT_UUID) {
quint16 value;
hr = dataReader->ReadUInt16(&value);
Q_ASSERT_SUCCEEDED(hr);
const QBluetoothUuid uuid(value);
info.setAttribute(key, uuid);
- qCDebug(QT_BT_WINRT) << "UUID" << uuid << "KEY" << Qt::hex << key << "TYPE" << Qt::dec << type << "UUID" << Qt::hex << uuid;
+ qCDebug(QT_BT_WINDOWS) << "UUID" << uuid << "KEY" << Qt::hex << key << "TYPE" << Qt::dec << type << "UUID" << Qt::hex << uuid;
} else if (type == TYPE_LONG_UUID) {
GUID value;
hr = dataReader->ReadGuid(&value);
Q_ASSERT_SUCCEEDED(hr);
+ // The latter 8 bytes are in reverse order
+ reverseArray(value.Data4, sizeof(value.Data4)/sizeof(value.Data4[0]));
const QBluetoothUuid uuid(value);
info.setAttribute(key, uuid);
- qCDebug(QT_BT_WINRT) << "UUID" << uuid << "KEY" << Qt::hex << key << "TYPE" << Qt::dec << type << "UUID" << Qt::hex << uuid;
+ qCDebug(QT_BT_WINDOWS) << "UUID" << uuid << "KEY" << Qt::hex << key << "TYPE" << Qt::dec << type << "UUID" << Qt::hex << uuid;
} else if (type == TYPE_STRING) {
BYTE length;
hr = dataReader->ReadByte(&length);
@@ -321,28 +273,28 @@ void QWinRTBluetoothServiceDiscoveryWorker::processServiceSearchResult(quint64 a
Q_ASSERT_SUCCEEDED(hr);
const QString str = QString::fromWCharArray(WindowsGetStringRawBuffer(value.Get(), nullptr));
info.setAttribute(key, str);
- qCDebug(QT_BT_WINRT) << "UUID" << uuid << "KEY" << Qt::hex << key << "TYPE" << Qt::dec << type << "STRING" << str;
+ qCDebug(QT_BT_WINDOWS) << "UUID" << uuid << "KEY" << Qt::hex << key << "TYPE" << Qt::dec << type << "STRING" << str;
} else if (type == TYPE_SEQUENCE) {
bool ok;
QBluetoothServiceInfo::Sequence sequence = readSequence(dataReader, &ok, nullptr);
if (ok) {
info.setAttribute(key, sequence);
- qCDebug(QT_BT_WINRT) << "UUID" << uuid << "KEY" << Qt::hex << key << "TYPE" << Qt::dec << type << "SEQUENCE" << sequence;
+ qCDebug(QT_BT_WINDOWS) << "UUID" << uuid << "KEY" << Qt::hex << key << "TYPE" << Qt::dec << type << "SEQUENCE" << sequence;
} else {
- qCDebug(QT_BT_WINRT) << "UUID" << uuid << "KEY" << Qt::hex << key << "TYPE" << Qt::dec << type << "SEQUENCE ERROR";
+ qCDebug(QT_BT_WINDOWS) << "UUID" << uuid << "KEY" << Qt::hex << key << "TYPE" << Qt::dec << type << "SEQUENCE ERROR";
}
} else {
- qCDebug(QT_BT_WINRT) << "UUID" << uuid << "KEY" << Qt::hex << key << "TYPE" << Qt::dec << type;
+ qCDebug(QT_BT_WINDOWS) << "UUID" << uuid << "KEY" << Qt::hex << key << "TYPE" << Qt::dec << type;
}
hr = iterator->MoveNext(&current);
}
// Windows is only able to discover Rfcomm services but the according protocolDescriptor is
// not always set in the raw attribute map. If we encounter a service like that we should
// fill the protocol descriptor ourselves.
- if (info.protocolDescriptor(QBluetoothUuid::Rfcomm).isEmpty()) {
+ if (info.protocolDescriptor(QBluetoothUuid::ProtocolUuid::Rfcomm).isEmpty()) {
QBluetoothServiceInfo::Sequence protocolDescriptorList;
QBluetoothServiceInfo::Sequence protocol;
- protocol << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::Rfcomm))
+ protocol << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::ProtocolUuid::Rfcomm))
<< QVariant::fromValue(0);
protocolDescriptorList.append(QVariant::fromValue(protocol));
info.setAttribute(QBluetoothServiceInfo::ProtocolDescriptorList, protocolDescriptorList);
@@ -422,7 +374,8 @@ QBluetoothServiceInfo::Sequence QWinRTBluetoothServiceDiscoveryWorker::readSeque
GUID b;
hr = dataReader->ReadGuid(&b);
Q_ASSERT_SUCCEEDED(hr);
-
+ // The latter 8 bytes are in reverse order
+ reverseArray(b.Data4, sizeof(b.Data4)/sizeof(b.Data4[0]));
const QBluetoothUuid uuid(b);
result.append(QVariant::fromValue(uuid));
remainingLength -= sizeof(GUID);
@@ -461,7 +414,7 @@ QBluetoothServiceInfo::Sequence QWinRTBluetoothServiceDiscoveryWorker::readSeque
break;
}
default:
- qCDebug(QT_BT_WINRT) << "SEQUENCE ERROR" << type;
+ qCDebug(QT_BT_WINDOWS) << "SEQUENCE ERROR" << type;
result.clear();
return result;
}
@@ -488,13 +441,15 @@ QBluetoothServiceDiscoveryAgentPrivate::QBluetoothServiceDiscoveryAgentPrivate(
singleDevice(false),
q_ptr(qp)
{
+ mainThreadCoInit(this);
// TODO: use local adapter for discovery. Possible?
Q_UNUSED(deviceAdapter);
}
QBluetoothServiceDiscoveryAgentPrivate::~QBluetoothServiceDiscoveryAgentPrivate()
{
- stop();
+ releaseWorker();
+ mainThreadCoUninit(this);
}
void QBluetoothServiceDiscoveryAgentPrivate::start(const QBluetoothAddress &address)
@@ -508,8 +463,6 @@ void QBluetoothServiceDiscoveryAgentPrivate::start(const QBluetoothAddress &addr
this, &QBluetoothServiceDiscoveryAgentPrivate::processFoundService, Qt::QueuedConnection);
connect(worker, &QWinRTBluetoothServiceDiscoveryWorker::scanFinished,
this, &QBluetoothServiceDiscoveryAgentPrivate::onScanFinished, Qt::QueuedConnection);
- connect(worker, &QWinRTBluetoothServiceDiscoveryWorker::scanCanceled,
- this, &QBluetoothServiceDiscoveryAgentPrivate::onScanCanceled, Qt::QueuedConnection);
connect(worker, &QWinRTBluetoothServiceDiscoveryWorker::errorOccured,
this, &QBluetoothServiceDiscoveryAgentPrivate::onError, Qt::QueuedConnection);
worker->start();
@@ -517,20 +470,9 @@ void QBluetoothServiceDiscoveryAgentPrivate::start(const QBluetoothAddress &addr
void QBluetoothServiceDiscoveryAgentPrivate::stop()
{
- if (!worker)
- return;
-
- disconnect(worker, &QWinRTBluetoothServiceDiscoveryWorker::serviceFound,
- this, &QBluetoothServiceDiscoveryAgentPrivate::processFoundService);
- disconnect(worker, &QWinRTBluetoothServiceDiscoveryWorker::scanFinished,
- this, &QBluetoothServiceDiscoveryAgentPrivate::onScanFinished);
- disconnect(worker, &QWinRTBluetoothServiceDiscoveryWorker::scanCanceled,
- this, &QBluetoothServiceDiscoveryAgentPrivate::onScanCanceled);
- disconnect(worker, &QWinRTBluetoothServiceDiscoveryWorker::errorOccured,
- this, &QBluetoothServiceDiscoveryAgentPrivate::onError);
- // mWorker will delete itself as soon as it is done with its discovery
- worker = nullptr;
- setDiscoveryState(Inactive);
+ releaseWorker();
+ Q_Q(QBluetoothServiceDiscoveryAgent);
+ emit q->canceled();
}
void QBluetoothServiceDiscoveryAgentPrivate::processFoundService(quint64 deviceAddress, const QBluetoothServiceInfo &info)
@@ -558,7 +500,7 @@ void QBluetoothServiceDiscoveryAgentPrivate::processFoundService(quint64 deviceA
QBluetoothServiceInfo returnInfo(info);
bool deviceFound;
- for (const QBluetoothDeviceInfo &deviceInfo : qAsConst(discoveredDevices)) {
+ for (const QBluetoothDeviceInfo &deviceInfo : std::as_const(discoveredDevices)) {
if (deviceInfo.address().toUInt64() == deviceAddress) {
deviceFound = true;
returnInfo.setDevice(deviceInfo);
@@ -569,7 +511,7 @@ void QBluetoothServiceDiscoveryAgentPrivate::processFoundService(quint64 deviceA
if (!isDuplicatedService(returnInfo)) {
discoveredServices.append(returnInfo);
- qCDebug(QT_BT_WINRT) << "Discovered services" << discoveredDevices.at(0).address().toString()
+ qCDebug(QT_BT_WINDOWS) << "Discovered services" << discoveredDevices.at(0).address().toString()
<< returnInfo.serviceName() << returnInfo.serviceUuid()
<< ">>>" << returnInfo.serviceClassUuids();
@@ -579,26 +521,12 @@ void QBluetoothServiceDiscoveryAgentPrivate::processFoundService(quint64 deviceA
void QBluetoothServiceDiscoveryAgentPrivate::onScanFinished(quint64 deviceAddress)
{
- Q_Q(QBluetoothServiceDiscoveryAgent);
- bool deviceFound;
- for (const QBluetoothDeviceInfo &deviceInfo : qAsConst(discoveredDevices)) {
- if (deviceInfo.address().toUInt64() == deviceAddress) {
- deviceFound = true;
- discoveredDevices.removeOne(deviceInfo);
- if (discoveredDevices.isEmpty())
- setDiscoveryState(Inactive);
- break;
- }
- }
- Q_ASSERT(deviceFound);
- stop();
- emit q->finished();
-}
-
-void QBluetoothServiceDiscoveryAgentPrivate::onScanCanceled()
-{
- Q_Q(QBluetoothServiceDiscoveryAgent);
- emit q->canceled();
+ // The scan for a device's services has finished. Disconnect the
+ // worker and call the baseclass function which starts the scan for
+ // the next device if there are any unscanned devices left (or finishes
+ // the scan if none left)
+ releaseWorker();
+ _q_serviceDiscoveryFinished();
}
void QBluetoothServiceDiscoveryAgentPrivate::onError()
@@ -606,8 +534,23 @@ void QBluetoothServiceDiscoveryAgentPrivate::onError()
Q_Q(QBluetoothServiceDiscoveryAgent);
discoveredDevices.clear();
error = QBluetoothServiceDiscoveryAgent::InputOutputError;
- errorString = "errorDescription";
- emit q->error(error);
+ errorString = QStringLiteral("errorDescription");
+ emit q->errorOccurred(error);
+}
+
+void QBluetoothServiceDiscoveryAgentPrivate::releaseWorker()
+{
+ if (!worker)
+ return;
+
+ disconnect(worker, &QWinRTBluetoothServiceDiscoveryWorker::serviceFound,
+ this, &QBluetoothServiceDiscoveryAgentPrivate::processFoundService);
+ disconnect(worker, &QWinRTBluetoothServiceDiscoveryWorker::scanFinished,
+ this, &QBluetoothServiceDiscoveryAgentPrivate::onScanFinished);
+ disconnect(worker, &QWinRTBluetoothServiceDiscoveryWorker::errorOccured,
+ this, &QBluetoothServiceDiscoveryAgentPrivate::onError);
+ // mWorker will delete itself as soon as it is done with its discovery
+ worker = nullptr;
}
QT_END_NAMESPACE
diff --git a/src/bluetooth/qbluetoothserviceinfo.cpp b/src/bluetooth/qbluetoothserviceinfo.cpp
index 23a78c81..927b9edd 100644
--- a/src/bluetooth/qbluetoothserviceinfo.cpp
+++ b/src/bluetooth/qbluetoothserviceinfo.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qbluetoothserviceinfo.h"
#include "qbluetoothserviceinfo_p.h"
@@ -44,6 +8,11 @@
QT_BEGIN_NAMESPACE
+QT_IMPL_METATYPE_EXTERN(QBluetoothServiceInfo)
+QT_IMPL_METATYPE_EXTERN_TAGGED(QBluetoothServiceInfo::Sequence, QBluetoothServiceInfo__Sequence)
+QT_IMPL_METATYPE_EXTERN_TAGGED(QBluetoothServiceInfo::Alternative,
+ QBluetoothServiceInfo__Alternative)
+
/*!
\class QBluetoothServiceInfo::Sequence
\inmodule QtBluetooth
@@ -181,7 +150,7 @@ bool QBluetoothServiceInfo::isRegistered() const
bool QBluetoothServiceInfo::registerService(const QBluetoothAddress &localAdapter)
{
#ifdef QT_OSX_BLUETOOTH
- Q_UNUSED(localAdapter)
+ Q_UNUSED(localAdapter);
return d_ptr->registerService(*this);
#else
return d_ptr->registerService(localAdapter);
@@ -469,11 +438,11 @@ void QBluetoothServiceInfo::removeAttribute(quint16 attributeId)
*/
QBluetoothServiceInfo::Protocol QBluetoothServiceInfo::socketProtocol() const
{
- QBluetoothServiceInfo::Sequence parameters = protocolDescriptor(QBluetoothUuid::Rfcomm);
+ QBluetoothServiceInfo::Sequence parameters = protocolDescriptor(QBluetoothUuid::ProtocolUuid::Rfcomm);
if (!parameters.isEmpty())
return RfcommProtocol;
- parameters = protocolDescriptor(QBluetoothUuid::L2cap);
+ parameters = protocolDescriptor(QBluetoothUuid::ProtocolUuid::L2cap);
if (!parameters.isEmpty())
return L2capProtocol;
@@ -490,11 +459,11 @@ QBluetoothServiceInfo::Protocol QBluetoothServiceInfo::socketProtocol() const
*/
int QBluetoothServiceInfo::protocolServiceMultiplexer() const
{
- QBluetoothServiceInfo::Sequence parameters = protocolDescriptor(QBluetoothUuid::L2cap);
+ QBluetoothServiceInfo::Sequence parameters = protocolDescriptor(QBluetoothUuid::ProtocolUuid::L2cap);
if (parameters.isEmpty())
return -1;
- else if (parameters.count() == 1)
+ else if (parameters.size() == 1)
return 0;
else
return parameters.at(1).toUInt();
@@ -541,7 +510,7 @@ QList<QBluetoothUuid> QBluetoothServiceInfo::serviceClassUuids() const
return results;
const QBluetoothServiceInfo::Sequence seq = var.value<QBluetoothServiceInfo::Sequence>();
- for (int i = 0; i < seq.count(); i++)
+ for (qsizetype i = 0; i < seq.size(); ++i)
results.append(seq.at(i).value<QBluetoothUuid>());
return results;
@@ -560,7 +529,7 @@ QBluetoothServiceInfo &QBluetoothServiceInfo::operator=(const QBluetoothServiceI
static void dumpAttributeVariant(QDebug dbg, const QVariant &var, const QString& indent)
{
- switch (int(var.type())) {
+ switch (var.typeId()) {
case QMetaType::Void:
dbg << QString::asprintf("%sEmpty\n", indent.toUtf8().constData());
break;
@@ -597,8 +566,8 @@ static void dumpAttributeVariant(QDebug dbg, const QVariant &var, const QString&
dbg << QString::asprintf("%surl %s\n", indent.toUtf8().constData(),
var.toUrl().toString().toUtf8().constData());
break;
- case QVariant::UserType:
- if (var.userType() == qMetaTypeId<QBluetoothUuid>()) {
+ default:
+ if (var.typeId() == qMetaTypeId<QBluetoothUuid>()) {
QBluetoothUuid uuid = var.value<QBluetoothUuid>();
switch (uuid.minimumSize()) {
case 0:
@@ -615,31 +584,29 @@ static void dumpAttributeVariant(QDebug dbg, const QVariant &var, const QString&
case 16:
dbg << QString::asprintf("%suuid %s\n",
indent.toUtf8().constData(),
- QByteArray(reinterpret_cast<const char *>(uuid.toUInt128().data), 16).toHex().constData());
+ uuid.toByteArray(QUuid::Id128).constData());
break;
default:
dbg << QString::asprintf("%suuid ???\n", indent.toUtf8().constData());
}
- } else if (var.userType() == qMetaTypeId<QBluetoothServiceInfo::Sequence>()) {
+ } else if (var.typeId() == qMetaTypeId<QBluetoothServiceInfo::Sequence>()) {
dbg << QString::asprintf("%sSequence\n", indent.toUtf8().constData());
const QBluetoothServiceInfo::Sequence *sequence = static_cast<const QBluetoothServiceInfo::Sequence *>(var.data());
for (const QVariant &v : *sequence)
dumpAttributeVariant(dbg, v, indent + QLatin1Char('\t'));
- } else if (var.userType() == qMetaTypeId<QBluetoothServiceInfo::Alternative>()) {
+ } else if (var.typeId() == qMetaTypeId<QBluetoothServiceInfo::Alternative>()) {
dbg << QString::asprintf("%sAlternative\n", indent.toUtf8().constData());
const QBluetoothServiceInfo::Alternative *alternative = static_cast<const QBluetoothServiceInfo::Alternative *>(var.data());
for (const QVariant &v : *alternative)
dumpAttributeVariant(dbg, v, indent + QLatin1Char('\t'));
+ } else {
+ dbg << QString::asprintf("%sunknown variant type %d\n", indent.toUtf8().constData(), var.typeId());
}
- break;
- default:
- dbg << QString::asprintf("%sunknown variant type %d\n", indent.toUtf8().constData(),
- var.userType());
}
}
-
-QDebug operator<<(QDebug dbg, const QBluetoothServiceInfo &info)
+#ifndef QT_NO_DEBUG_STREAM
+QDebug QBluetoothServiceInfo::streamingOperator(QDebug dbg, const QBluetoothServiceInfo &info)
{
QDebugStateSaver saver(dbg);
dbg.noquote() << "\n";
@@ -649,6 +616,7 @@ QDebug operator<<(QDebug dbg, const QBluetoothServiceInfo &info)
}
return dbg;
}
+#endif
QBluetoothServiceInfo::Sequence QBluetoothServiceInfoPrivate::protocolDescriptor(QBluetoothUuid::ProtocolUuid protocol) const
{
@@ -672,11 +640,11 @@ QBluetoothServiceInfo::Sequence QBluetoothServiceInfoPrivate::protocolDescriptor
int QBluetoothServiceInfoPrivate::serverChannel() const
{
- QBluetoothServiceInfo::Sequence parameters = protocolDescriptor(QBluetoothUuid::Rfcomm);
+ QBluetoothServiceInfo::Sequence parameters = protocolDescriptor(QBluetoothUuid::ProtocolUuid::Rfcomm);
if (parameters.isEmpty())
return -1;
- else if (parameters.count() == 1)
+ else if (parameters.size() == 1)
return 0;
else
return parameters.at(1).toUInt();
diff --git a/src/bluetooth/qbluetoothserviceinfo.h b/src/bluetooth/qbluetoothserviceinfo.h
index cc4041e2..8ab2086d 100644
--- a/src/bluetooth/qbluetoothserviceinfo.h
+++ b/src/bluetooth/qbluetoothserviceinfo.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QBLUETOOTHSERVICEINFO_H
#define QBLUETOOTHSERVICEINFO_H
@@ -147,18 +111,26 @@ public:
bool registerService(const QBluetoothAddress &localAdapter = QBluetoothAddress());
bool unregisterService();
-protected:
- friend Q_BLUETOOTH_EXPORT QDebug operator<<(QDebug, const QBluetoothServiceInfo &);
-
+private:
+#ifndef QT_NO_DEBUG_STREAM
+ friend QDebug operator<<(QDebug d, const QBluetoothServiceInfo &i)
+ {
+ return streamingOperator(d, i);
+ }
+ static QDebug streamingOperator(QDebug, const QBluetoothServiceInfo &);
+#endif
protected:
QSharedPointer<QBluetoothServiceInfoPrivate> d_ptr;
};
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(QBluetoothServiceInfo)
-Q_DECLARE_METATYPE(QBluetoothServiceInfo::Sequence)
-Q_DECLARE_METATYPE(QBluetoothServiceInfo::Alternative)
+QT_DECL_METATYPE_EXTERN(QBluetoothServiceInfo, Q_BLUETOOTH_EXPORT)
+QT_DECL_METATYPE_EXTERN_TAGGED(QBluetoothServiceInfo::Sequence, QBluetoothServiceInfo__Sequence,
+ Q_BLUETOOTH_EXPORT)
+QT_DECL_METATYPE_EXTERN_TAGGED(QBluetoothServiceInfo::Alternative,
+ QBluetoothServiceInfo__Alternative,
+ Q_BLUETOOTH_EXPORT)
QT_BEGIN_NAMESPACE
diff --git a/src/bluetooth/qbluetoothserviceinfo_android.cpp b/src/bluetooth/qbluetoothserviceinfo_android.cpp
index b0193f73..33ca7d52 100644
--- a/src/bluetooth/qbluetoothserviceinfo_android.cpp
+++ b/src/bluetooth/qbluetoothserviceinfo_android.cpp
@@ -1,44 +1,8 @@
-/***************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#include <QtCore/QLoggingCategory>
+#include "android/androidutils_p.h"
#include "qbluetoothhostinfo.h"
#include "qbluetoothlocaldevice.h"
#include "qbluetoothserviceinfo.h"
@@ -46,6 +10,8 @@
#include "qbluetoothserver_p.h"
#include "qbluetoothserver.h"
+#include <QtCore/QLoggingCategory>
+
QT_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(QT_BT_ANDROID)
@@ -89,8 +55,14 @@ bool QBluetoothServiceInfoPrivate::unregisterService()
bool QBluetoothServiceInfoPrivate::registerService(const QBluetoothAddress& localAdapter)
{
+ if (!ensureAndroidPermission(QBluetoothPermission::Access)) {
+ qCWarning(QT_BT_ANDROID) << "Serviceinfo registerService() failed due to"
+ "missing permissions";
+ return false;
+ }
+
const QList<QBluetoothHostInfo> localDevices = QBluetoothLocalDevice::allDevices();
- if (!localDevices.count())
+ if (localDevices.isEmpty())
return false; //no Bluetooth device
if (!localAdapter.isNull()) {
@@ -112,7 +84,7 @@ bool QBluetoothServiceInfoPrivate::registerService(const QBluetoothAddress& loca
if (registered)
return false;
- if (protocolDescriptor(QBluetoothUuid::Rfcomm).isEmpty()) {
+ if (protocolDescriptor(QBluetoothUuid::ProtocolUuid::Rfcomm).isEmpty()) {
qCWarning(QT_BT_ANDROID) << Q_FUNC_INFO << "Only RFCOMM services can be registered on Android";
return false;
}
diff --git a/src/bluetooth/qbluetoothserviceinfo_bluez.cpp b/src/bluetooth/qbluetoothserviceinfo_bluez.cpp
index d91367c4..14c3e451 100644
--- a/src/bluetooth/qbluetoothserviceinfo_bluez.cpp
+++ b/src/bluetooth/qbluetoothserviceinfo_bluez.cpp
@@ -1,47 +1,9 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qbluetoothserviceinfo.h"
#include "qbluetoothserviceinfo_p.h"
-#include "bluez/manager_p.h"
-#include "bluez/service_p.h"
#include "bluez/bluez5_helper_p.h"
#include "bluez/profilemanager1_p.h"
@@ -51,16 +13,17 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
Q_DECLARE_LOGGING_CATEGORY(QT_BT_BLUEZ)
-static const QLatin1String profilePathTemplate("/qt/profile");
static QAtomicInt pathCounter;
static void writeAttribute(QXmlStreamWriter *stream, const QVariant &attribute)
{
const QString unsignedFormat(QStringLiteral("0x%1"));
- switch (int(attribute.type())) {
+ switch (attribute.typeId()) {
case QMetaType::Void:
stream->writeEmptyElement(QStringLiteral("nil"));
break;
@@ -119,7 +82,7 @@ static void writeAttribute(QXmlStreamWriter *stream, const QVariant &attribute)
stream->writeEmptyElement(QStringLiteral("url"));
stream->writeAttribute(QStringLiteral("value"), attribute.value<QUrl>().toString());
break;
- case QVariant::UserType:
+ default:
if (attribute.userType() == qMetaTypeId<QBluetoothUuid>()) {
stream->writeEmptyElement(QStringLiteral("uuid"));
@@ -158,22 +121,19 @@ static void writeAttribute(QXmlStreamWriter *stream, const QVariant &attribute)
for (const QVariant &v : *alternative)
writeAttribute(stream, v);
stream->writeEndElement();
+ } else {
+ qCWarning(QT_BT_BLUEZ) << "Unknown variant type" << attribute.userType();
}
- break;
- default:
- qCWarning(QT_BT_BLUEZ) << "Unknown variant type", attribute.userType();
}
}
QBluetoothServiceInfoPrivate::QBluetoothServiceInfoPrivate()
: serviceRecord(0), registered(false)
{
- if (isBluez5()) {
- serviceBluez5 = new OrgBluezProfileManager1Interface(
- QStringLiteral("org.bluez"),
- QStringLiteral("/org/bluez"),
- QDBusConnection::systemBus(), this);
- }
+ initializeBluez5();
+ service = new OrgBluezProfileManager1Interface(QStringLiteral("org.bluez"),
+ QStringLiteral("/org/bluez"),
+ QDBusConnection::systemBus(), this);
}
QBluetoothServiceInfoPrivate::~QBluetoothServiceInfoPrivate()
@@ -190,78 +150,28 @@ bool QBluetoothServiceInfoPrivate::unregisterService()
if (!registered)
return false;
- if (serviceBluez5) { // Bluez 5
- if (profilePath.isEmpty())
- return false;
-
- QDBusPendingReply<> reply = serviceBluez5->UnregisterProfile(
- QDBusObjectPath(profilePath));
- reply.waitForFinished();
- if (reply.isError()) {
- qCWarning(QT_BT_BLUEZ) << "Cannot unregister profile:"
- << profilePath << reply.error().message();
- return false;
- }
- profilePath.clear();
- } else { // Bluez 4
- if (!ensureSdpConnection(currentLocalAdapter))
- return false;
-
- QDBusPendingReply<> reply = service->RemoveRecord(serviceRecord);
- reply.waitForFinished();
- if (reply.isError())
- return false;
+ if (profilePath.isEmpty())
+ return false;
- serviceRecord = 0;
+ QDBusPendingReply<> reply = service->UnregisterProfile(QDBusObjectPath(profilePath));
+ reply.waitForFinished();
+ if (reply.isError()) {
+ qCWarning(QT_BT_BLUEZ) << "Cannot unregister profile:" << profilePath
+ << reply.error().message();
+ return false;
}
+ profilePath.clear();
registered = false;
return true;
}
-bool QBluetoothServiceInfoPrivate::ensureSdpConnection(const QBluetoothAddress &localAdapter)
+// TODO Implement local adapter behavior
+bool QBluetoothServiceInfoPrivate::registerService(const QBluetoothAddress & /*localAdapter*/)
{
- if (service && currentLocalAdapter == localAdapter)
- return true;
-
- delete service;
-
- OrgBluezManagerInterface manager(QStringLiteral("org.bluez"), QStringLiteral("/"),
- QDBusConnection::systemBus());
-
-
- QDBusPendingReply<QDBusObjectPath> reply;
- if (localAdapter.isNull())
- reply = manager.DefaultAdapter();
- else
- reply = manager.FindAdapter(localAdapter.toString());
- reply.waitForFinished();
- if (reply.isError())
+ if (registered)
return false;
- currentLocalAdapter = localAdapter;
- service = new OrgBluezServiceInterface(QStringLiteral("org.bluez"), reply.value().path(),
- QDBusConnection::systemBus(), this);
-
- return true;
-}
-
-bool QBluetoothServiceInfoPrivate::registerService(const QBluetoothAddress &localAdapter)
-{
- if (serviceBluez5) { // Bluez 5
- if (registered)
- return false;
- } else { // Bluez 4
- //if new adapter unregister previous one first
- if (registered && localAdapter != currentLocalAdapter)
- unregisterService();
-
- if (!ensureSdpConnection(localAdapter)) {
- qCWarning(QT_BT_BLUEZ) << "SDP not connected. Cannot register";
- return false;
- }
- }
-
QString xmlServiceRecord;
QXmlStreamWriter stream(&xmlServiceRecord);
@@ -287,84 +197,58 @@ bool QBluetoothServiceInfoPrivate::registerService(const QBluetoothAddress &loca
stream.writeEndDocument();
- if (serviceBluez5) { // Bluez 5
- // create path
- profilePath = profilePathTemplate;
- profilePath.append(QString::fromLatin1("/%1%2/%3").
- arg(sanitizeNameForDBus(QCoreApplication::applicationName())).
- arg(QCoreApplication::applicationPid()).
- arg(pathCounter.fetchAndAddOrdered(1)));
-
- QVariantMap mapping;
- mapping.insert(QStringLiteral("ServiceRecord"), xmlServiceRecord);
-
- // Strategy to pick service uuid
- // 1.) use serviceUuid()
- // 2.) use first custom uuid if available
- // 3.) use first service class uuid
- QBluetoothUuid profileUuid = attributes.value(QBluetoothServiceInfo::ServiceId)
- .value<QBluetoothUuid>();
- QBluetoothUuid firstCustomUuid;
- if (profileUuid.isNull()) {
- const QVariant var = attributes.value(QBluetoothServiceInfo::ServiceClassIds);
- if (var.isValid()) {
- const QBluetoothServiceInfo::Sequence seq
- = var.value<QBluetoothServiceInfo::Sequence>();
- QBluetoothUuid tempUuid;
-
- for (int i = 0; i < seq.count(); i++) {
- tempUuid = seq.at(i).value<QBluetoothUuid>();
- if (tempUuid.isNull())
- continue;
-
- int size = tempUuid.minimumSize();
- if (size == 2 || size == 4) { // Base UUID derived
- if (profileUuid.isNull())
- profileUuid = tempUuid;
- } else if (firstCustomUuid.isNull()){
- firstCustomUuid = tempUuid;
- }
+ // create path
+ profilePath = u"/qt/profile"_s;
+ profilePath.append(QString::fromLatin1("/%1%2/%3")
+ .arg(sanitizeNameForDBus(QCoreApplication::applicationName()))
+ .arg(QCoreApplication::applicationPid())
+ .arg(pathCounter.fetchAndAddOrdered(1)));
+
+ QVariantMap mapping;
+ mapping.insert(QStringLiteral("ServiceRecord"), xmlServiceRecord);
+ mapping.insert(QStringLiteral("Role"), QStringLiteral("server"));
+
+ // Strategy to pick service uuid
+ // 1.) use serviceUuid()
+ // 2.) use first custom uuid if available
+ // 3.) use first service class uuid
+ QBluetoothUuid profileUuid =
+ attributes.value(QBluetoothServiceInfo::ServiceId).value<QBluetoothUuid>();
+ QBluetoothUuid firstCustomUuid;
+ if (profileUuid.isNull()) {
+ const QVariant var = attributes.value(QBluetoothServiceInfo::ServiceClassIds);
+ if (var.isValid()) {
+ const QBluetoothServiceInfo::Sequence seq =
+ var.value<QBluetoothServiceInfo::Sequence>();
+ for (const auto &e : seq) {
+ auto tempUuid = e.value<QBluetoothUuid>();
+ if (tempUuid.isNull())
+ continue;
+
+ int size = tempUuid.minimumSize();
+ if (size == 2 || size == 4) { // Base UUID derived
+ if (profileUuid.isNull())
+ profileUuid = tempUuid;
+ } else if (firstCustomUuid.isNull()) {
+ firstCustomUuid = tempUuid;
}
}
}
+ }
- if (!firstCustomUuid.isNull())
- profileUuid = firstCustomUuid;
-
- QString uuidString = profileUuid.toString();
- uuidString.chop(1); // remove trailing '}'
- uuidString.remove(0, 1); // remove beginning '{'
+ if (!firstCustomUuid.isNull())
+ profileUuid = firstCustomUuid;
- qCDebug(QT_BT_BLUEZ) << "Registering profile under" << profilePath
- << uuidString;
+ QString uuidString = profileUuid.toString(QUuid::WithoutBraces);
- QDBusPendingReply<> reply = serviceBluez5->RegisterProfile(
- QDBusObjectPath(profilePath),
- uuidString,
- mapping);
- reply.waitForFinished();
- if (reply.isError()) {
- qCWarning(QT_BT_BLUEZ) << "Cannot register profile" << reply.error().message();
- return false;
- }
- } else { // Bluez 4
- if (!registered) {
- QDBusPendingReply<uint> reply = service->AddRecord(xmlServiceRecord);
- reply.waitForFinished();
- if (reply.isError()) {
- qCWarning(QT_BT_BLUEZ) << "AddRecord returned error" << reply.error();
- return false;
- }
+ qCDebug(QT_BT_BLUEZ) << "Registering profile under" << profilePath << uuidString;
- serviceRecord = reply.value();
- } else {
- QDBusPendingReply<> reply = service->UpdateRecord(serviceRecord, xmlServiceRecord);
- reply.waitForFinished();
- if (reply.isError()) {
- qCWarning(QT_BT_BLUEZ) << "UpdateRecord returned error" << reply.error();
- return false;
- }
- }
+ QDBusPendingReply<> reply =
+ service->RegisterProfile(QDBusObjectPath(profilePath), uuidString, mapping);
+ reply.waitForFinished();
+ if (reply.isError()) {
+ qCWarning(QT_BT_BLUEZ) << "Cannot register profile" << reply.error().message();
+ return false;
}
registered = true;
diff --git a/src/bluetooth/qbluetoothserviceinfo_macos.mm b/src/bluetooth/qbluetoothserviceinfo_macos.mm
index b73ae55f..e038a726 100644
--- a/src/bluetooth/qbluetoothserviceinfo_macos.mm
+++ b/src/bluetooth/qbluetoothserviceinfo_macos.mm
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qbluetoothserviceinfo_p.h"
#include "darwin/btservicerecord_p.h"
@@ -66,11 +30,11 @@ using ServiceInfo = QBluetoothServiceInfo;
// I need these getters duplicated here:
ServiceInfo::Protocol socket_protocol(const QBluetoothServiceInfoPrivate &privateInfo)
{
- ServiceInfo::Sequence parameters = privateInfo.protocolDescriptor(QBluetoothUuid::Rfcomm);
+ ServiceInfo::Sequence parameters = privateInfo.protocolDescriptor(QBluetoothUuid::ProtocolUuid::Rfcomm);
if (!parameters.isEmpty())
return ServiceInfo::RfcommProtocol;
- parameters = privateInfo.protocolDescriptor(QBluetoothUuid::L2cap);
+ parameters = privateInfo.protocolDescriptor(QBluetoothUuid::ProtocolUuid::L2cap);
if (!parameters.isEmpty())
return ServiceInfo::L2capProtocol;
@@ -82,7 +46,7 @@ int channel_or_psm(const QBluetoothServiceInfoPrivate &privateInfo, QBluetoothUu
const auto parameters = privateInfo.protocolDescriptor(uuid);
if (parameters.isEmpty())
return -1;
- else if (parameters.count() == 1)
+ else if (parameters.size() == 1)
return 0;
return parameters.at(1).toInt();
@@ -196,9 +160,9 @@ bool QBluetoothServiceInfoPrivate::unregisterService()
const QMutexLocker lock(&QBluetoothServerPrivate::channelMapMutex());
if (type == ServiceInfo::RfcommProtocol)
- server = QBluetoothServerPrivate::registeredServer(channel_or_psm(*this, QBluetoothUuid::Rfcomm), type);
+ server = QBluetoothServerPrivate::registeredServer(channel_or_psm(*this, QBluetoothUuid::ProtocolUuid::Rfcomm), type);
else if (type == ServiceInfo::L2capProtocol)
- server = QBluetoothServerPrivate::registeredServer(channel_or_psm(*this, QBluetoothUuid::L2cap), type);
+ server = QBluetoothServerPrivate::registeredServer(channel_or_psm(*this, QBluetoothUuid::ProtocolUuid::L2cap), type);
if (server)
server->stopListener();
diff --git a/src/bluetooth/qbluetoothserviceinfo_p.cpp b/src/bluetooth/qbluetoothserviceinfo_p.cpp
index 43e08db5..cefdcb9f 100644
--- a/src/bluetooth/qbluetoothserviceinfo_p.cpp
+++ b/src/bluetooth/qbluetoothserviceinfo_p.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qbluetoothserviceinfo.h"
#include "qbluetoothserviceinfo_p.h"
@@ -73,3 +37,5 @@ bool QBluetoothServiceInfoPrivate::unregisterService()
}
QT_END_NAMESPACE
+
+#include "moc_qbluetoothserviceinfo_p.cpp"
diff --git a/src/bluetooth/qbluetoothserviceinfo_p.h b/src/bluetooth/qbluetoothserviceinfo_p.h
index a51204c6..8f4a0296 100644
--- a/src/bluetooth/qbluetoothserviceinfo_p.h
+++ b/src/bluetooth/qbluetoothserviceinfo_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QBLUETOOTHSERVICEINFO_P_H
#define QBLUETOOTHSERVICEINFO_P_H
@@ -82,11 +46,6 @@ namespace ABI {
}
#endif
-#ifdef QT_WIN_BLUETOOTH
-#include <winsock2.h>
-#include <ws2bth.h>
-#endif
-
QT_BEGIN_NAMESPACE
class QBluetoothServiceInfo;
@@ -113,10 +72,7 @@ public:
int serverChannel() const;
private:
#if QT_CONFIG(bluez)
- bool ensureSdpConnection(const QBluetoothAddress &localAdapter = QBluetoothAddress());
-
- OrgBluezServiceInterface *service = nullptr;
- OrgBluezProfileManager1Interface *serviceBluez5 = nullptr;
+ OrgBluezProfileManager1Interface *service = nullptr;
quint32 serviceRecord;
QBluetoothAddress currentLocalAdapter;
QString profilePath;
@@ -128,14 +84,6 @@ private:
bool writeSdpAttributes();
#endif
-#ifdef QT_WIN_BLUETOOTH
- SOCKADDR_BTH sockaddr = {};
- CSADDR_INFO addrinfo = {};
- WSAQUERYSET regInfo = {};
- QVector<WCHAR> serviceName;
- QVector<WCHAR> serviceDescription;
-#endif
-
#if QT_OSX_BLUETOOTH
public:
bool registerService(const QBluetoothServiceInfo &info);
diff --git a/src/bluetooth/qbluetoothserviceinfo_win.cpp b/src/bluetooth/qbluetoothserviceinfo_win.cpp
deleted file mode 100644
index 1f1293ad..00000000
--- a/src/bluetooth/qbluetoothserviceinfo_win.cpp
+++ /dev/null
@@ -1,120 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qbluetoothserviceinfo.h"
-#include "qbluetoothserviceinfo_p.h"
-#include "qbluetoothserver_p.h"
-#include "qbluetoothserver.h"
-
-#include <bluetoothapis.h>
-
-QT_BEGIN_NAMESPACE
-
-QBluetoothServiceInfoPrivate::QBluetoothServiceInfoPrivate()
- : registered(false)
-{
-}
-
-QBluetoothServiceInfoPrivate::~QBluetoothServiceInfoPrivate()
-{
-}
-
-bool QBluetoothServiceInfoPrivate::isRegistered() const
-{
- return registered;
-}
-
-bool QBluetoothServiceInfoPrivate::registerService(const QBluetoothAddress &localAdapter)
-{
- if (registered)
- return false;
-
- GUID serviceUuid = attributes.value(QBluetoothServiceInfo::ServiceId).value<QBluetoothUuid>();
- const QString name = attributes.value(QBluetoothServiceInfo::ServiceName).toString();
- const QString description = attributes.value(QBluetoothServiceInfo::ServiceDescription).toString();
-
- ::memset(&sockaddr, 0, sizeof(sockaddr));
- sockaddr.addressFamily = AF_BTH;
- sockaddr.port = serverChannel();
- sockaddr.btAddr = localAdapter.toUInt64();
-
- ::memset(&addrinfo, 0, sizeof(addrinfo));
- addrinfo.LocalAddr.iSockaddrLength = sizeof(SOCKADDR_BTH);
- addrinfo.LocalAddr.lpSockaddr = (LPSOCKADDR)&sockaddr;
- addrinfo.RemoteAddr.iSockaddrLength = sizeof(SOCKADDR_BTH);
- addrinfo.RemoteAddr.lpSockaddr = (LPSOCKADDR)&sockaddr;
- addrinfo.iSocketType = SOCK_STREAM;
- addrinfo.iProtocol = BTHPROTO_RFCOMM;
-
- serviceName.resize(name.size() + 1);
- name.toWCharArray(serviceName.data());
- serviceName[name.size()] = WCHAR(0);
- serviceDescription.resize(description.size() + 1);
- description.toWCharArray(serviceDescription.data());
- serviceDescription[description.size()] = WCHAR(0);
-
- ::memset(&regInfo, 0, sizeof(regInfo));
- regInfo.dwSize = sizeof(WSAQUERYSET);
- regInfo.dwNameSpace = NS_BTH;
- regInfo.dwNumberOfCsAddrs = 1;
- regInfo.lpcsaBuffer = &addrinfo;
- regInfo.lpszServiceInstanceName = serviceName.data();
- regInfo.lpszComment = serviceDescription.data();
- regInfo.lpServiceClassId = &serviceUuid;
-
- if (::WSASetService(&regInfo, RNRSERVICE_REGISTER, 0) == SOCKET_ERROR)
- return false;
-
- registered = true;
- return true;
-}
-
-bool QBluetoothServiceInfoPrivate::unregisterService()
-{
- if (!registered)
- return false;
-
- if (::WSASetService(&regInfo, RNRSERVICE_DELETE, 0) == SOCKET_ERROR)
- return false;
-
- registered = false;
- return true;
-}
-
-QT_END_NAMESPACE
diff --git a/src/bluetooth/qbluetoothserviceinfo_winrt.cpp b/src/bluetooth/qbluetoothserviceinfo_winrt.cpp
index e806096f..8f6f111a 100644
--- a/src/bluetooth/qbluetoothserviceinfo_winrt.cpp
+++ b/src/bluetooth/qbluetoothserviceinfo_winrt.cpp
@@ -1,52 +1,13 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qbluetoothserviceinfo.h"
#include "qbluetoothserviceinfo_p.h"
#include "qbluetoothserver_p.h"
+#include "qbluetoothutils_winrt_p.h"
-#include <QtCore/private/qeventdispatcher_winrt_p.h>
#include <QtCore/QLoggingCategory>
-#ifdef CLASSIC_APP_BUILD
-#define Q_OS_WINRT
-#endif
-#include <qfunctions_winrt.h>
+#include <QtCore/private/qfunctions_winrt_p.h>
#include <wrl.h>
#include <windows.devices.bluetooth.h>
@@ -66,7 +27,7 @@ using namespace ABI::Windows::Storage::Streams;
QT_BEGIN_NAMESPACE
-Q_DECLARE_LOGGING_CATEGORY(QT_BT_WINRT)
+Q_DECLARE_LOGGING_CATEGORY(QT_BT_WINDOWS)
#define TYPE_VOID 0
#define TYPE_UINT8 8
@@ -133,10 +94,10 @@ qint64 getLengthForBaseType(unsigned char type, ComPtr<IDataReader> &reader)
bool writeStringHelper(const QString &string, ComPtr<IDataWriter> writer)
{
HRESULT hr;
- const int stringLength = string.length();
+ const qsizetype stringLength = string.size();
unsigned char type = TYPE_STRING_BASE;
if (stringLength < 0) {
- qCWarning(QT_BT_WINRT) << "Can not write invalid string value to buffer";
+ qCWarning(QT_BT_WINDOWS) << "Can not write invalid string value to buffer";
return false;
} if (stringLength <= 0xff) {
type += 5;
@@ -161,8 +122,8 @@ bool writeStringHelper(const QString &string, ComPtr<IDataWriter> writer)
quint32 bytesWritten;
hr = writer->WriteString(stringRef.Get(), &bytesWritten);
RETURN_FALSE_IF_FAILED("Could not write string to buffer.");
- if (bytesWritten != string.length()) {
- qCWarning(QT_BT_WINRT) << "Did not write full value to buffer";
+ if (bytesWritten != size_t(string.size())) {
+ qCWarning(QT_BT_WINDOWS) << "Did not write full value to buffer";
return false;
}
return true;
@@ -183,7 +144,7 @@ bool repairProfileDescriptorListIfNeeded(ComPtr<IBuffer> &buffer)
hr = reader->ReadByte(&type);
Q_ASSERT_SUCCEEDED(hr);
if (!typeIsOfBase(type, TYPE_SEQUENCE_BASE)) {
- qCWarning(QT_BT_WINRT) << Q_FUNC_INFO << "Malformed profile descriptor list read";
+ qCWarning(QT_BT_WINDOWS) << Q_FUNC_INFO << "Malformed profile descriptor list read";
return false;
}
@@ -192,7 +153,7 @@ bool repairProfileDescriptorListIfNeeded(ComPtr<IBuffer> &buffer)
Q_ASSERT_SUCCEEDED(hr);
// We have to "repair" the structure if the outer sequence contains a uuid directly
if (type == TYPE_UUID16 && length == 4) {
- qCDebug(QT_BT_WINRT) << Q_FUNC_INFO << "Repairing profile descriptor list";
+ qCDebug(QT_BT_WINDOWS) << Q_FUNC_INFO << "Repairing profile descriptor list";
quint16 uuid;
hr = reader->ReadUInt16(&uuid);
Q_ASSERT_SUCCEEDED(hr);
@@ -235,70 +196,70 @@ static ComPtr<IBuffer> bufferFromAttribute(const QVariant &attribute)
&writer);
Q_ASSERT_SUCCEEDED(hr);
- switch (int(attribute.type())) {
+ switch (attribute.typeId()) {
case QMetaType::Void:
- qCDebug(QT_BT_WINRT) << Q_FUNC_INFO << "Registering attribute of type QMetaType::Void:";
+ qCDebug(QT_BT_WINDOWS) << Q_FUNC_INFO << "Registering attribute of type QMetaType::Void:";
hr = writer->WriteByte(TYPE_VOID);
Q_ASSERT_SUCCEEDED(hr);
break;
case QMetaType::UChar:
- qCDebug(QT_BT_WINRT) << Q_FUNC_INFO << "Registering attribute of type QMetaType::UChar:" << attribute.value<quint8>();
+ qCDebug(QT_BT_WINDOWS) << Q_FUNC_INFO << "Registering attribute of type QMetaType::UChar:" << attribute.value<quint8>();
hr = writer->WriteByte(TYPE_UINT8);
Q_ASSERT_SUCCEEDED(hr);
hr = writer->WriteByte(attribute.value<quint8>());
Q_ASSERT_SUCCEEDED(hr);
break;
case QMetaType::UShort:
- qCDebug(QT_BT_WINRT) << Q_FUNC_INFO << "Registering attribute of type QMetaType::UShort:" << attribute.value<quint16>();
+ qCDebug(QT_BT_WINDOWS) << Q_FUNC_INFO << "Registering attribute of type QMetaType::UShort:" << attribute.value<quint16>();
hr = writer->WriteByte(TYPE_UINT16);
Q_ASSERT_SUCCEEDED(hr);
hr = writer->WriteUInt16(attribute.value<quint16>());
Q_ASSERT_SUCCEEDED(hr);
break;
case QMetaType::UInt:
- qCDebug(QT_BT_WINRT) << Q_FUNC_INFO << "Registering attribute of type QMetaType::UInt:" << attribute.value<quint32>();
+ qCDebug(QT_BT_WINDOWS) << Q_FUNC_INFO << "Registering attribute of type QMetaType::UInt:" << attribute.value<quint32>();
hr = writer->WriteByte(TYPE_UINT32);
Q_ASSERT_SUCCEEDED(hr);
hr = writer->WriteUInt32(attribute.value<quint32>());
Q_ASSERT_SUCCEEDED(hr);
break;
case QMetaType::ULongLong:
- qCDebug(QT_BT_WINRT) << Q_FUNC_INFO << "Registering attribute of type QMetaType::ULongLong:" << attribute.value<quint64>();
+ qCDebug(QT_BT_WINDOWS) << Q_FUNC_INFO << "Registering attribute of type QMetaType::ULongLong:" << attribute.value<quint64>();
hr = writer->WriteByte(TYPE_UINT64);
Q_ASSERT_SUCCEEDED(hr);
hr = writer->WriteUInt64(attribute.value<quint64>());
Q_ASSERT_SUCCEEDED(hr);
break;
case QMetaType::Char:
- qCDebug(QT_BT_WINRT) << Q_FUNC_INFO << "Registering attribute of type QMetaType::Char:" << attribute.value<qint8>();
+ qCDebug(QT_BT_WINDOWS) << Q_FUNC_INFO << "Registering attribute of type QMetaType::Char:" << attribute.value<qint8>();
hr = writer->WriteByte(TYPE_INT8);
Q_ASSERT_SUCCEEDED(hr);
hr = writer->WriteByte(attribute.value<qint8>());
Q_ASSERT_SUCCEEDED(hr);
break;
case QMetaType::Short:
- qCDebug(QT_BT_WINRT) << Q_FUNC_INFO << "Registering attribute of type QMetaType::Short:" << attribute.value<qint16>();
+ qCDebug(QT_BT_WINDOWS) << Q_FUNC_INFO << "Registering attribute of type QMetaType::Short:" << attribute.value<qint16>();
hr = writer->WriteByte(TYPE_INT16);
Q_ASSERT_SUCCEEDED(hr);
hr = writer->WriteInt16(attribute.value<qint16>());
Q_ASSERT_SUCCEEDED(hr);
break;
case QMetaType::Int:
- qCDebug(QT_BT_WINRT) << Q_FUNC_INFO << "Registering attribute of type QMetaType::Int:" << attribute.value<qint32>();
+ qCDebug(QT_BT_WINDOWS) << Q_FUNC_INFO << "Registering attribute of type QMetaType::Int:" << attribute.value<qint32>();
hr = writer->WriteByte(TYPE_INT32);
Q_ASSERT_SUCCEEDED(hr);
hr = writer->WriteInt32(attribute.value<qint32>());
Q_ASSERT_SUCCEEDED(hr);
break;
case QMetaType::LongLong:
- qCDebug(QT_BT_WINRT) << Q_FUNC_INFO << "Registering attribute of type QMetaType::LongLong:" << attribute.value<qint64>();
+ qCDebug(QT_BT_WINDOWS) << Q_FUNC_INFO << "Registering attribute of type QMetaType::LongLong:" << attribute.value<qint64>();
hr = writer->WriteByte(TYPE_INT64);
Q_ASSERT_SUCCEEDED(hr);
hr = writer->WriteInt64(attribute.value<qint64>());
Q_ASSERT_SUCCEEDED(hr);
break;
case QMetaType::QByteArray: {
- qCDebug(QT_BT_WINRT) << Q_FUNC_INFO << "Registering attribute of type QMetaType::QByteArray:" << attribute.value<QString>();
+ qCDebug(QT_BT_WINDOWS) << Q_FUNC_INFO << "Registering attribute of type QMetaType::QByteArray:" << attribute.value<QString>();
const QString stringValue = QString::fromLatin1(attribute.value<QByteArray>().toHex());
const bool writeSuccess = writeStringHelper(stringValue, writer);
if (!writeSuccess)
@@ -306,7 +267,7 @@ static ComPtr<IBuffer> bufferFromAttribute(const QVariant &attribute)
break;
}
case QMetaType::QString: {
- qCDebug(QT_BT_WINRT) << Q_FUNC_INFO << "Registering attribute of type QMetaType::QString:" << attribute.value<QString>();
+ qCDebug(QT_BT_WINDOWS) << Q_FUNC_INFO << "Registering attribute of type QMetaType::QString:" << attribute.value<QString>();
const QString stringValue = attribute.value<QString>();
const bool writeSucces = writeStringHelper(stringValue, writer);
if (!writeSucces)
@@ -314,33 +275,32 @@ static ComPtr<IBuffer> bufferFromAttribute(const QVariant &attribute)
break;
}
case QMetaType::Bool:
- qCDebug(QT_BT_WINRT) << Q_FUNC_INFO << "Registering attribute of type QMetaType::Bool:" << attribute.value<bool>();
+ qCDebug(QT_BT_WINDOWS) << Q_FUNC_INFO << "Registering attribute of type QMetaType::Bool:" << attribute.value<bool>();
hr = writer->WriteByte(TYPE_BOOLEAN);
Q_ASSERT_SUCCEEDED(hr);
hr = writer->WriteByte(attribute.value<bool>());
Q_ASSERT_SUCCEEDED(hr);
break;
case QMetaType::QUrl:
- qCWarning(QT_BT_WINRT) << "Don't know how to register QMetaType::QUrl";
+ qCWarning(QT_BT_WINDOWS) << "Don't know how to register QMetaType::QUrl";
return nullptr;
break;
- case QVariant::UserType:
+ default:
if (attribute.userType() == qMetaTypeId<QBluetoothUuid>()) {
QBluetoothUuid uuid = attribute.value<QBluetoothUuid>();
- const int minimumSize = uuid.minimumSize();
switch (uuid.minimumSize()) {
case 0:
- qCWarning(QT_BT_WINRT) << "Don't know how to register Uuid of length 0";
+ qCWarning(QT_BT_WINDOWS) << "Don't know how to register Uuid of length 0";
return nullptr;
case 2:
- qCDebug(QT_BT_WINRT) << Q_FUNC_INFO << "Registering Uuid attribute with length 2:" << uuid;
+ qCDebug(QT_BT_WINDOWS) << Q_FUNC_INFO << "Registering Uuid attribute with length 2:" << uuid;
hr = writer->WriteByte(TYPE_UUID16);
Q_ASSERT_SUCCEEDED(hr);
hr = writer->WriteUInt16(uuid.toUInt16());
Q_ASSERT_SUCCEEDED(hr);
break;
case 4:
- qCDebug(QT_BT_WINRT) << Q_FUNC_INFO << "Registering Uuid attribute with length 4:" << uuid;
+ qCDebug(QT_BT_WINDOWS) << Q_FUNC_INFO << "Registering Uuid attribute with length 4:" << uuid;
hr = writer->WriteByte(TYPE_UUID32);
Q_ASSERT_SUCCEEDED(hr);
hr = writer->WriteUInt32(uuid.toUInt32());
@@ -348,7 +308,7 @@ static ComPtr<IBuffer> bufferFromAttribute(const QVariant &attribute)
break;
case 16:
default:
- qCDebug(QT_BT_WINRT) << Q_FUNC_INFO << "Registering Uuid attribute:" << uuid;
+ qCDebug(QT_BT_WINDOWS) << Q_FUNC_INFO << "Registering Uuid attribute:" << uuid;
hr = writer->WriteByte(TYPE_UUID128);
Q_ASSERT_SUCCEEDED(hr);
hr = writer->WriteGuid(uuid);
@@ -356,7 +316,7 @@ static ComPtr<IBuffer> bufferFromAttribute(const QVariant &attribute)
break;
}
} else if (attribute.userType() == qMetaTypeId<QBluetoothServiceInfo::Sequence>()) {
- qCDebug(QT_BT_WINRT) << "Registering sequence attribute";
+ qCDebug(QT_BT_WINDOWS) << "Registering sequence attribute";
const QBluetoothServiceInfo::Sequence *sequence =
static_cast<const QBluetoothServiceInfo::Sequence *>(attribute.data());
ComPtr<IDataWriter> tmpWriter;
@@ -366,7 +326,7 @@ static ComPtr<IBuffer> bufferFromAttribute(const QVariant &attribute)
for (const QVariant &v : *sequence) {
ComPtr<IBuffer> tmpBuffer = bufferFromAttribute(v);
if (!tmpBuffer) {
- qCWarning(QT_BT_WINRT) << "Could not create buffer from attribute in sequence";
+ qCWarning(QT_BT_WINDOWS) << "Could not create buffer from attribute in sequence";
return nullptr;
}
quint32 l;
@@ -406,15 +366,14 @@ static ComPtr<IBuffer> bufferFromAttribute(const QVariant &attribute)
// write sequence data
hr = writer->WriteBuffer(tmpBuffer.Get());
Q_ASSERT_SUCCEEDED(hr);
- qCDebug(QT_BT_WINRT) << Q_FUNC_INFO << "Registered sequence attribute with length" << length;
+ qCDebug(QT_BT_WINDOWS) << Q_FUNC_INFO << "Registered sequence attribute with length" << length;
} else if (attribute.userType() == qMetaTypeId<QBluetoothServiceInfo::Alternative>()) {
- qCWarning(QT_BT_WINRT) << "Don't know how to register user type Alternative";
+ qCWarning(QT_BT_WINDOWS) << "Don't know how to register user type Alternative";
+ return nullptr;
+ } else {
+ qCWarning(QT_BT_WINDOWS) << "Unknown variant type" << attribute.userType();
return nullptr;
}
- break;
- default:
- qCWarning(QT_BT_WINRT) << "Unknown variant type" << attribute.userType();
- return nullptr;
}
ComPtr<IBuffer> buffer;
hr = writer->DetachBuffer(&buffer);
@@ -425,10 +384,12 @@ static ComPtr<IBuffer> bufferFromAttribute(const QVariant &attribute)
QBluetoothServiceInfoPrivate::QBluetoothServiceInfoPrivate()
: registered(false)
{
+ mainThreadCoInit(this);
}
QBluetoothServiceInfoPrivate::~QBluetoothServiceInfoPrivate()
{
+ mainThreadCoUninit(this);
}
bool QBluetoothServiceInfoPrivate::isRegistered() const
@@ -442,8 +403,8 @@ bool QBluetoothServiceInfoPrivate::registerService(const QBluetoothAddress &loca
if (registered)
return false;
- if (protocolDescriptor(QBluetoothUuid::Rfcomm).isEmpty()) {
- qCWarning(QT_BT_WINRT) << Q_FUNC_INFO << "Only RFCOMM services can be registered on WinRT";
+ if (protocolDescriptor(QBluetoothUuid::ProtocolUuid::Rfcomm).isEmpty()) {
+ qCWarning(QT_BT_WINDOWS) << Q_FUNC_INFO << "Only RFCOMM services can be registered on WinRT";
return false;
}
@@ -465,16 +426,11 @@ bool QBluetoothServiceInfoPrivate::registerService(const QBluetoothAddress &loca
IID_PPV_ARGS(&providerStatics));
Q_ASSERT_SUCCEEDED(hr);
ComPtr<IAsyncOperation<RfcommServiceProvider *>> op;
- hr = QEventDispatcherWinRT::runOnXamlThread([providerStatics, serviceId, &op]
- {
- HRESULT hr;
- hr = providerStatics->CreateAsync(serviceId.Get(), &op);
- return hr;
- });
+ hr = providerStatics->CreateAsync(serviceId.Get(), &op);
Q_ASSERT_SUCCEEDED(hr);
hr = QWinRTFunctions::await(op, serviceProvider.GetAddressOf());
if (hr == HRESULT_FROM_WIN32(ERROR_DEVICE_NOT_AVAILABLE)) {
- qCWarning(QT_BT_WINRT) << Q_FUNC_INFO << "No bluetooth adapter available.";
+ qCWarning(QT_BT_WINDOWS) << Q_FUNC_INFO << "No bluetooth adapter available.";
return false;
} else {
Q_ASSERT_SUCCEEDED(hr);
@@ -482,7 +438,7 @@ bool QBluetoothServiceInfoPrivate::registerService(const QBluetoothAddress &loca
ComPtr<IStreamSocketListener> listener = sPriv->listener();
if (!listener) {
- qCWarning(QT_BT_WINRT) << Q_FUNC_INFO << "Could not obtain listener from server.";
+ qCWarning(QT_BT_WINDOWS) << Q_FUNC_INFO << "Could not obtain listener from server.";
return false;
}
@@ -501,21 +457,17 @@ bool QBluetoothServiceInfoPrivate::registerService(const QBluetoothAddress &loca
result = writeSdpAttributes();
if (!result) {
- qCWarning(QT_BT_WINRT) << "Could not write SDP attributes.";
+ qCWarning(QT_BT_WINDOWS) << "Could not write SDP attributes.";
return false;
}
- qCDebug(QT_BT_WINRT) << "SDP attributes written.";
+ qCDebug(QT_BT_WINDOWS) << "SDP attributes written.";
ComPtr<IRfcommServiceProvider2> serviceProvider2;
hr = serviceProvider.As(&serviceProvider2);
Q_ASSERT_SUCCEEDED(hr);
- hr = QEventDispatcherWinRT::runOnXamlThread([listener, serviceProvider2] {
- HRESULT hr;
- hr = serviceProvider2->StartAdvertisingWithRadioDiscoverability(listener.Get(), true);
- return hr;
- });
+ hr = serviceProvider2->StartAdvertisingWithRadioDiscoverability(listener.Get(), true);
if (FAILED(hr)) {
- qCWarning(QT_BT_WINRT) << Q_FUNC_INFO << "Could not start advertising. Check your SDP data.";
+ qCWarning(QT_BT_WINDOWS) << Q_FUNC_INFO << "Could not start advertising. Check your SDP data.";
return false;
}
@@ -571,7 +523,7 @@ bool QBluetoothServiceInfoPrivate::writeSdpAttributes()
HRESULT hr;
ComPtr<IBuffer> buffer = bufferFromAttribute(attribute);
if (!buffer) {
- qCWarning(QT_BT_WINRT) << "Could not create buffer from attribute with id:" << key;
+ qCWarning(QT_BT_WINDOWS) << "Could not create buffer from attribute with id:" << key;
return false;
}
@@ -579,7 +531,7 @@ bool QBluetoothServiceInfoPrivate::writeSdpAttributes()
// WinRT accept the list without breaking existing apps we have to repair this structure.
if (key == QBluetoothServiceInfo::BluetoothProfileDescriptorList) {
if (!repairProfileDescriptorListIfNeeded(buffer)) {
- qCWarning(QT_BT_WINRT) << Q_FUNC_INFO << "Error while checking/repairing structure of profile descriptor list";
+ qCWarning(QT_BT_WINDOWS) << Q_FUNC_INFO << "Error while checking/repairing structure of profile descriptor list";
return false;
}
}
@@ -594,7 +546,7 @@ bool QBluetoothServiceInfoPrivate::writeSdpAttributes()
hr = rawAttributes->Insert(key, buffer.Get(), &replaced);
Q_ASSERT_SUCCEEDED(hr);
Q_ASSERT(!replaced);
- qCDebug(QT_BT_WINRT) << Q_FUNC_INFO << "Registered attribute" << QString::number(key, 16).rightJustified(4, '0') << "with value" << attribute;
+ qCDebug(QT_BT_WINDOWS) << Q_FUNC_INFO << "Registered attribute" << QString::number(key, 16).rightJustified(4, QLatin1Char('0')) << "with value" << attribute;
}
return true;
}
diff --git a/src/bluetooth/qbluetoothsocket.cpp b/src/bluetooth/qbluetoothsocket.cpp
index 972706bd..e05d8a7e 100644
--- a/src/bluetooth/qbluetoothsocket.cpp
+++ b/src/bluetooth/qbluetoothsocket.cpp
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Copyright (C) 2016 BlackBerry Limited. All rights reserved.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// Copyright (C) 2016 BlackBerry Limited. All rights reserved.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qbluetoothsocket.h"
#if QT_CONFIG(bluez)
@@ -47,8 +11,6 @@
#include "qbluetoothsocket_android_p.h"
#elif defined(QT_WINRT_BLUETOOTH)
#include "qbluetoothsocket_winrt_p.h"
-#elif defined(QT_WIN_BLUETOOTH)
-#include "qbluetoothsocket_win_p.h"
#elif defined(QT_OSX_BLUETOOTH)
#include "qbluetoothsocket_macos_p.h"
#else
@@ -87,7 +49,7 @@ Q_DECLARE_LOGGING_CATEGORY(QT_BT)
the connected() signal when the connection is established.
If the \l {QBluetoothServiceInfo::Protocol}{Protocol} is not supported on a platform, calling
- \l connectToService() will emit a \l {QBluetoothSocket::UnsupportedProtocolError}{UnsupportedProtocolError} error.
+ \l connectToService() will emit a \l {QBluetoothSocket::SocketError::UnsupportedProtocolError}{UnsupportedProtocolError} error.
\note QBluetoothSocket does not support synchronous read and write operations. Functions such
as \l waitForReadyRead() and \l waitForBytesWritten() are not implemented. I/O operations should be
@@ -95,6 +57,11 @@ Q_DECLARE_LOGGING_CATEGORY(QT_BT)
On iOS, this class cannot be used because the platform does not expose
an API which may permit access to QBluetoothSocket related features.
+
+ \note On macOS Monterey (12) the socket data flow is paused when a
+ modal dialogue is executing, or an event tracking mode is entered (for
+ example by long-pressing a Window close button). This may change in the
+ future releases of macOS.
*/
/*!
@@ -126,8 +93,10 @@ Q_DECLARE_LOGGING_CATEGORY(QT_BT)
supported on this platform.
\value OperationError An operation was attempted while the socket was in a state
that did not permit it.
- \value RemoteHostClosedError The remote host closed the connection. This value was
- introduced by Qt 5.10.
+ \value [since 5.10] RemoteHostClosedError The remote host closed the connection.
+ \value [since 6.4] MissingPermissionsError The operating system requests
+ permissions which were not
+ granted by the user.
*/
/*!
@@ -135,7 +104,7 @@ Q_DECLARE_LOGGING_CATEGORY(QT_BT)
This signal is emitted when a connection is established.
- \sa QBluetoothSocket::ConnectedState, stateChanged()
+ \sa QBluetoothSocket::SocketState::ConnectedState, stateChanged()
*/
/*!
@@ -143,15 +112,16 @@ Q_DECLARE_LOGGING_CATEGORY(QT_BT)
This signal is emitted when the socket is disconnected.
- \sa QBluetoothSocket::UnconnectedState, stateChanged()
+ \sa QBluetoothSocket::SocketState::UnconnectedState, stateChanged()
*/
/*!
- \fn void QBluetoothSocket::error(QBluetoothSocket::SocketError error)
+ \fn void QBluetoothSocket::errorOccurred(QBluetoothSocket::SocketError error)
This signal is emitted when an \a error occurs.
\sa error()
+ \since 6.2
*/
/*!
@@ -271,10 +241,8 @@ static QBluetoothSocketBasePrivate *createSocketPrivate()
return new QBluetoothSocketPrivateAndroid();
#elif defined(QT_WINRT_BLUETOOTH)
return new QBluetoothSocketPrivateWinRT();
-#elif defined(QT_WIN_BLUETOOTH)
- return new QBluetoothSocketPrivateWin();
#elif defined(QT_OSX_BLUETOOTH)
- return new QBluetoothSocketPrivate();
+ return new QBluetoothSocketPrivateDarwin();
#else
return new QBluetoothSocketPrivateDummy();
#endif
@@ -375,7 +343,7 @@ qint64 QBluetoothSocket::bytesToWrite() const
\a service. If a connection is established, QBluetoothSocket enters ConnectedState and
emits connected().
- At any point, the socket can emit error() to signal that an error occurred.
+ At any point, the socket can emit errorOccurred() to signal that an error occurred.
Note that most platforms require a pairing prior to connecting to the remote device. Otherwise
the connection process may fail.
@@ -415,7 +383,7 @@ void QBluetoothSocket::connectToService(const QBluetoothServiceInfo &service, Op
the \l ServiceLookupState and \l socketType() is always set to
\l QBluetoothServiceInfo::RfcommProtocol.
- At any point, the socket can emit error() to signal that an error occurred.
+ At any point, the socket can emit errorOccurred() to signal that an error occurred.
Note that most platforms require a pairing prior to connecting to the remote device. Otherwise
the connection process may fail.
@@ -436,10 +404,10 @@ void QBluetoothSocket::connectToService(const QBluetoothAddress &address, const
The socket first enters ConnectingState, and attempts to connect to \a address. If a
connection is established, QBluetoothSocket enters ConnectedState and emits connected().
- At any point, the socket can emit error() to signal that an error occurred.
+ At any point, the socket can emit errorOccurred() to signal that an error occurred.
On Android and BlueZ (version 5.46 or above), a connection to a service can not be established using a port.
- Calling this function will emit a \l {QBluetoothSocket::ServiceNotFoundError}{ServiceNotFoundError}.
+ Calling this function will emit a \l {QBluetoothSocket::SocketError::ServiceNotFoundError}{ServiceNotFoundError}.
Note that most platforms require a pairing prior to connecting to the remote device. Otherwise
the connection process may fail.
@@ -498,17 +466,18 @@ QString QBluetoothSocket::errorString() const
Therefore it is required to reconnect to change this parameter for an
existing connection.
- On Bluez this property is set to QBluetooth::Authorization by default.
+ On Bluez this property is set to QBluetooth::Security::Authorization by default.
On \macos, this value is ignored as the platform does not permit access
to the security parameter of the socket. By default the platform prefers
secure/encrypted connections though and therefore this function always
- returns \l QBluetooth::Secure.
+ returns \l QBluetooth::Security::Secure.
- Android only supports two levels of security (secure and non-secure). If this flag is set to
- \l QBluetooth::NoSecurity the socket object will not employ any authentication or encryption.
- Any other security flag combination will trigger a secure Bluetooth connection.
- This flag is set to \l QBluetooth::Secure by default.
+ Android only supports two levels of security (secure and non-secure).
+ If this flag is set to \l QBluetooth::Security::NoSecurity the socket
+ object will not employ any authentication or encryption. Any other
+ security flag combination will trigger a secure Bluetooth connection.
+ This flag is set to \l QBluetooth::Security::Secure by default.
\note A secure connection requires a pairing between the two devices. On
some platforms, the pairing is automatically initiated during the establishment
@@ -537,7 +506,7 @@ void QBluetoothSocket::setPreferredSecurityFlags(QBluetooth::SecurityFlags flags
during or after the connection has been established. If such a change happens
it is not reflected in the value of this flag.
- On \macos, this flag is always set to \l QBluetooth::Secure.
+ On \macos, this flag is always set to \l QBluetooth::Security::Secure.
\sa setPreferredSecurityFlags()
@@ -547,7 +516,7 @@ QBluetooth::SecurityFlags QBluetoothSocket::preferredSecurityFlags() const
{
#if QT_OSX_BLUETOOTH
// not supported on macOS - platform always uses encryption
- return QBluetooth::Secure;
+ return QBluetooth::Security::Secure;
#else
Q_D(const QBluetoothSocketBase);
return d->secFlags;
@@ -567,14 +536,14 @@ void QBluetoothSocket::setSocketState(QBluetoothSocket::SocketState state)
d->state = state;
if(old != d->state)
emit stateChanged(state);
- if (state == QBluetoothSocket::ConnectedState) {
+ if (state == QBluetoothSocket::SocketState::ConnectedState) {
emit connected();
- } else if ((old == QBluetoothSocket::ConnectedState
- || old == QBluetoothSocket::ClosingState)
- && state == QBluetoothSocket::UnconnectedState) {
+ } else if ((old == QBluetoothSocket::SocketState::ConnectedState
+ || old == QBluetoothSocket::SocketState::ClosingState)
+ && state == QBluetoothSocket::SocketState::UnconnectedState) {
emit disconnected();
}
- if(state == ListeningState){
+ if (state == SocketState::ListeningState){
#ifdef QT_OSX_BLUETOOTH
qCWarning(QT_BT) << "listening socket is not supported by IOBluetooth";
#endif
@@ -593,7 +562,7 @@ void QBluetoothSocket::setSocketState(QBluetoothSocket::SocketState state)
bool QBluetoothSocket::canReadLine() const
{
Q_D(const QBluetoothSocketBase);
- return d->canReadLine();
+ return d->canReadLine() || QIODevice::canReadLine();
}
/*!
@@ -603,7 +572,7 @@ void QBluetoothSocket::setSocketError(QBluetoothSocket::SocketError error_)
{
Q_D(QBluetoothSocketBase);
d->socketError = error_;
- emit error(error_);
+ emit errorOccurred(error_);
}
/*!
@@ -616,7 +585,7 @@ void QBluetoothSocket::doDeviceDiscovery(const QBluetoothServiceInfo &service, O
{
Q_D(QBluetoothSocketBase);
- setSocketState(QBluetoothSocket::ServiceLookupState);
+ setSocketState(QBluetoothSocket::SocketState::ServiceLookupState);
qCDebug(QT_BT) << "Starting Bluetooth service discovery";
if(d->discoveryAgent) {
@@ -678,8 +647,8 @@ void QBluetoothSocket::discoveryFinished()
if (d->discoveryAgent){
qCDebug(QT_BT) << "Didn't find any";
d->errorString = tr("Service cannot be found");
- setSocketError(ServiceNotFoundError);
- setSocketState(QBluetoothSocket::UnconnectedState);
+ setSocketError(SocketError::ServiceNotFoundError);
+ setSocketState(QBluetoothSocket::SocketState::UnconnectedState);
d->discoveryAgent->deleteLater();
d->discoveryAgent = nullptr;
}
@@ -687,19 +656,19 @@ void QBluetoothSocket::discoveryFinished()
void QBluetoothSocket::abort()
{
- if (state() == UnconnectedState)
+ if (state() == SocketState::UnconnectedState)
return;
Q_D(QBluetoothSocketBase);
setOpenMode(QIODevice::NotOpen);
- if (state() == ServiceLookupState && d->discoveryAgent) {
+ if (state() == SocketState::ServiceLookupState && d->discoveryAgent) {
d->discoveryAgent->disconnect();
d->discoveryAgent->stop();
d->discoveryAgent = nullptr;
}
- setSocketState(ClosingState);
+ setSocketState(SocketState::ClosingState);
d->abort();
}
@@ -750,7 +719,7 @@ qint64 QBluetoothSocket::writeData(const char *data, qint64 maxSize)
if (!data || maxSize <= 0) {
d_ptr->errorString = tr("Invalid data/data size");
- setSocketError(QBluetoothSocket::OperationError);
+ setSocketError(QBluetoothSocket::SocketError::OperationError);
return -1;
}
@@ -765,31 +734,38 @@ qint64 QBluetoothSocket::readData(char *data, qint64 maxSize)
void QBluetoothSocket::close()
{
- if (state() == UnconnectedState)
+ if (state() == SocketState::UnconnectedState)
return;
Q_D(QBluetoothSocketBase);
setOpenMode(QIODevice::NotOpen);
- if (state() == ServiceLookupState && d->discoveryAgent) {
+ if (state() == SocketState::ServiceLookupState && d->discoveryAgent) {
d->discoveryAgent->disconnect();
d->discoveryAgent->stop();
d->discoveryAgent = nullptr;
}
- setSocketState(ClosingState);
+ setSocketState(SocketState::ClosingState);
d->close();
}
/*!
- Set the socket to use \a socketDescriptor with a type of \a socketType,
- which is in state, \a socketState, and mode, \a openMode.
+ \fn bool QBluetoothSocket::setSocketDescriptor(int socketDescriptor, QBluetoothServiceInfo::Protocol socketType, SocketState socketState, OpenMode openMode)
- Returns true on success
-*/
+ Sets the socket to use \a socketDescriptor with a type of \a socketType,
+ which is in state \a socketState, and mode \a openMode.
+
+ The socket descriptor is owned by the QBluetoothSocket instance and may
+ be closed once finished.
+ Returns \c true on success.
+*/
+// ### Qt 7 consider making this function private. The qbluetoothsocket_bluez backend is the
+// the only backend providing publicly accessible support for this. Other backends implement
+// similarly named, but private, overload
bool QBluetoothSocket::setSocketDescriptor(int socketDescriptor, QBluetoothServiceInfo::Protocol socketType,
SocketState socketState, OpenMode openMode)
{
@@ -808,67 +784,6 @@ int QBluetoothSocket::socketDescriptor() const
return d->socket;
}
-
-
-#ifndef QT_NO_DEBUG_STREAM
-QDebug operator<<(QDebug debug, QBluetoothSocket::SocketError error)
-{
- switch (error) {
- case QBluetoothSocket::UnknownSocketError:
- debug << "QBluetoothSocket::UnknownSocketError";
- break;
- case QBluetoothSocket::HostNotFoundError:
- debug << "QBluetoothSocket::HostNotFoundError";
- break;
- case QBluetoothSocket::RemoteHostClosedError:
- debug << "QBluetoothSocket::RemoteHostClosedError";
- break;
- case QBluetoothSocket::ServiceNotFoundError:
- debug << "QBluetoothSocket::ServiceNotFoundError";
- break;
- case QBluetoothSocket::NetworkError:
- debug << "QBluetoothSocket::NetworkError";
- break;
- case QBluetoothSocket::UnsupportedProtocolError:
- debug << "QBluetoothSocket::UnsupportedProtocolError";
- break;
- default:
- debug << "QBluetoothSocket::SocketError(" << (int)error << ")";
- }
- return debug;
-}
-
-QDebug operator<<(QDebug debug, QBluetoothSocket::SocketState state)
-{
- switch (state) {
- case QBluetoothSocket::UnconnectedState:
- debug << "QBluetoothSocket::UnconnectedState";
- break;
- case QBluetoothSocket::ConnectingState:
- debug << "QBluetoothSocket::ConnectingState";
- break;
- case QBluetoothSocket::ConnectedState:
- debug << "QBluetoothSocket::ConnectedState";
- break;
- case QBluetoothSocket::BoundState:
- debug << "QBluetoothSocket::BoundState";
- break;
- case QBluetoothSocket::ClosingState:
- debug << "QBluetoothSocket::ClosingState";
- break;
- case QBluetoothSocket::ListeningState:
- debug << "QBluetoothSocket::ListeningState";
- break;
- case QBluetoothSocket::ServiceLookupState:
- debug << "QBluetoothSocket::ServiceLookupState";
- break;
- default:
- debug << "QBluetoothSocket::SocketState(" << (int)state << ")";
- }
- return debug;
-}
-#endif
-
QT_END_NAMESPACE
#include "moc_qbluetoothsocket.cpp"
diff --git a/src/bluetooth/qbluetoothsocket.h b/src/bluetooth/qbluetoothsocket.h
index 8d35f77e..53aa9f25 100644
--- a/src/bluetooth/qbluetoothsocket.h
+++ b/src/bluetooth/qbluetoothsocket.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QBLUETOOTHSOCKET_H
#define QBLUETOOTHSOCKET_H
@@ -48,7 +12,6 @@
#include <QtBluetooth/qbluetoothserviceinfo.h>
#include <QtCore/qiodevice.h>
-#include <QtNetwork/qabstractsocket.h>
QT_BEGIN_NAMESPACE
@@ -63,7 +26,7 @@ class Q_BLUETOOTH_EXPORT QBluetoothSocket : public QIODevice
friend class QBluetoothServer;
friend class QBluetoothServerPrivate;
- friend class QBluetoothSocketPrivate;
+ friend class QBluetoothSocketPrivateDarwin;
friend class QBluetoothSocketPrivateAndroid;
friend class QBluetoothSocketPrivateBluez;
friend class QBluetoothSocketPrivateBluezDBus;
@@ -73,28 +36,27 @@ class Q_BLUETOOTH_EXPORT QBluetoothSocket : public QIODevice
public:
- // TODO Decouple SocketState and SocketError enum values from QAbstractSocket in Qt 6
- enum SocketState {
- UnconnectedState = QAbstractSocket::UnconnectedState,
- ServiceLookupState = QAbstractSocket::HostLookupState,
- ConnectingState = QAbstractSocket::ConnectingState,
- ConnectedState = QAbstractSocket::ConnectedState,
- BoundState = QAbstractSocket::BoundState,
- ClosingState = QAbstractSocket::ClosingState,
- ListeningState = QAbstractSocket::ListeningState
+ enum class SocketState {
+ UnconnectedState,
+ ServiceLookupState,
+ ConnectingState,
+ ConnectedState,
+ BoundState,
+ ClosingState,
+ ListeningState
};
Q_ENUM(SocketState)
- enum SocketError {
- NoSocketError = -2,
- UnknownSocketError = QAbstractSocket::UnknownSocketError, //-1
- RemoteHostClosedError = QAbstractSocket::RemoteHostClosedError, //1
- HostNotFoundError = QAbstractSocket::HostNotFoundError, //2
- ServiceNotFoundError = QAbstractSocket::SocketAddressNotAvailableError, //9
- NetworkError = QAbstractSocket::NetworkError, //7
- UnsupportedProtocolError = 8,
- OperationError = QAbstractSocket::OperationError //19
- //New enums (independent of QAbstractSocket) should be added from 100 onwards
+ enum class SocketError {
+ NoSocketError,
+ UnknownSocketError,
+ RemoteHostClosedError,
+ HostNotFoundError,
+ ServiceNotFoundError,
+ NetworkError,
+ UnsupportedProtocolError,
+ OperationError,
+ MissingPermissionsError
};
Q_ENUM(SocketError)
@@ -103,14 +65,15 @@ public:
virtual ~QBluetoothSocket();
void abort();
- virtual void close();
- bool isSequential() const;
+ void close() override;
- virtual qint64 bytesAvailable() const;
- virtual qint64 bytesToWrite() const;
+ bool isSequential() const override;
- virtual bool canReadLine() const;
+ qint64 bytesAvailable() const override;
+ qint64 bytesToWrite() const override;
+
+ bool canReadLine() const override;
void connectToService(const QBluetoothServiceInfo &service, OpenMode openMode = ReadWrite);
void connectToService(const QBluetoothAddress &address, const QBluetoothUuid &uuid, OpenMode openMode = ReadWrite);
@@ -138,7 +101,7 @@ public:
//void setReadBufferSize(qint64 size);
bool setSocketDescriptor(int socketDescriptor, QBluetoothServiceInfo::Protocol socketType,
- SocketState socketState = ConnectedState,
+ SocketState socketState = SocketState::ConnectedState,
OpenMode openMode = ReadWrite);
int socketDescriptor() const;
@@ -157,12 +120,12 @@ public:
Q_SIGNALS:
void connected();
void disconnected();
- void error(QBluetoothSocket::SocketError error);
+ void errorOccurred(QBluetoothSocket::SocketError error);
void stateChanged(QBluetoothSocket::SocketState state);
protected:
- virtual qint64 readData(char *data, qint64 maxSize);
- virtual qint64 writeData(const char *data, qint64 maxSize);
+ qint64 readData(char *data, qint64 maxSize) override;
+ qint64 writeData(const char *data, qint64 maxSize) override;
void setSocketState(SocketState state);
void setSocketError(SocketError error);
@@ -188,10 +151,6 @@ private:
friend class QLowEnergyControllerPrivateBluez;
};
-#ifndef QT_NO_DEBUG_STREAM
-Q_BLUETOOTH_EXPORT QDebug operator<<(QDebug, QBluetoothSocket::SocketError);
-Q_BLUETOOTH_EXPORT QDebug operator<<(QDebug, QBluetoothSocket::SocketState);
-#endif
QT_END_NAMESPACE
diff --git a/src/bluetooth/qbluetoothsocket_android.cpp b/src/bluetooth/qbluetoothsocket_android.cpp
index 85da325b..147d533f 100644
--- a/src/bluetooth/qbluetoothsocket_android.cpp
+++ b/src/bluetooth/qbluetoothsocket_android.cpp
@@ -1,64 +1,26 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Lauri Laanmets (Proekspert AS) <lauri.laanmets@eesti.ee>
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 Lauri Laanmets (Proekspert AS) <lauri.laanmets@eesti.ee>
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qbluetoothsocket.h"
#include "qbluetoothsocket_android_p.h"
#include "qbluetoothaddress.h"
#include "qbluetoothdeviceinfo.h"
#include "qbluetoothserviceinfo.h"
+#include "android/androidutils_p.h"
+#include "android/jni_android_p.h"
+#include <QCoreApplication>
#include <QtCore/QLoggingCategory>
#include <QtCore/QThread>
#include <QtCore/QTime>
-#include <QtCore/private/qjni_p.h>
-#include <QtAndroidExtras/QAndroidJniEnvironment>
-#include <QtAndroid>
+#include <QtCore/QJniEnvironment>
QT_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(QT_BT_ANDROID)
-#define FALLBACK_CHANNEL 1
#define USE_FALLBACK true
-Q_DECLARE_METATYPE(QAndroidJniObject)
-
Q_BLUETOOTH_EXPORT bool useReverseUuidWorkAroundConnect = true;
/* BluetoothSocket.connect() can block up to 10s. Therefore it must be
@@ -81,34 +43,33 @@ class SocketConnectWorker : public QObject
{
Q_OBJECT
public:
- SocketConnectWorker(const QAndroidJniObject& socket,
- const QAndroidJniObject& targetUuid,
+ SocketConnectWorker(const QJniObject& socket,
+ const QJniObject& targetUuid,
const QBluetoothUuid& qtTargetUuid)
: QObject(),
mSocketObject(socket),
mTargetUuid(targetUuid),
mQtTargetUuid(qtTargetUuid)
{
- static int t = qRegisterMetaType<QAndroidJniObject>();
+ static int t = qRegisterMetaType<QJniObject>();
Q_UNUSED(t);
}
signals:
- void socketConnectDone(const QAndroidJniObject &socket);
- void socketConnectFailed(const QAndroidJniObject &socket,
- const QAndroidJniObject &targetUuid,
+ void socketConnectDone(const QJniObject &socket);
+ void socketConnectFailed(const QJniObject &socket,
+ const QJniObject &targetUuid,
const QBluetoothUuid &qtUuid);
public slots:
void connectSocket()
{
- QAndroidJniEnvironment env;
+ QJniEnvironment env;
qCDebug(QT_BT_ANDROID) << "Connecting socket";
- mSocketObject.callMethod<void>("connect");
- if (env->ExceptionCheck()) {
- env->ExceptionDescribe();
- env->ExceptionClear();
-
+ auto methodId = env.findMethod(mSocketObject.objectClass(), "connect", "()V");
+ if (methodId)
+ env->CallVoidMethod(mSocketObject.object(), methodId);
+ if (!methodId || env.checkAndClearExceptions()) {
emit socketConnectFailed(mSocketObject, mTargetUuid, mQtTargetUuid);
QThread::currentThread()->quit();
return;
@@ -122,21 +83,13 @@ public slots:
{
qCDebug(QT_BT_ANDROID) << "Executing queued closeSocket()";
- QAndroidJniEnvironment env;
mSocketObject.callMethod<void>("close");
- if (env->ExceptionCheck()) {
-
- qCWarning(QT_BT_ANDROID) << "Error during closure of abandoned socket";
- env->ExceptionDescribe();
- env->ExceptionClear();
- }
-
QThread::currentThread()->quit();
}
private:
- QAndroidJniObject mSocketObject;
- QAndroidJniObject mTargetUuid;
+ QJniObject mSocketObject;
+ QJniObject mTargetUuid;
// same as mTargetUuid above - just the Qt C++ version rather than jni uuid
QBluetoothUuid mQtTargetUuid;
};
@@ -151,8 +104,8 @@ public:
}
// Runs in same thread as QBluetoothSocketPrivateAndroid
- void setupWorker(QBluetoothSocketPrivateAndroid* d_ptr, const QAndroidJniObject& socketObject,
- const QAndroidJniObject& uuidObject, bool useFallback,
+ void setupWorker(QBluetoothSocketPrivateAndroid* d_ptr, const QJniObject& socketObject,
+ const QJniObject& uuidObject, bool useFallback,
const QBluetoothUuid& qtUuid = QBluetoothUuid())
{
SocketConnectWorker* worker = new SocketConnectWorker(
@@ -186,17 +139,15 @@ QBluetoothSocketPrivateAndroid::QBluetoothSocketPrivateAndroid()
:
inputThread(0)
{
- secFlags = QBluetooth::Secure;
- adapter = QAndroidJniObject::callStaticObjectMethod("android/bluetooth/BluetoothAdapter",
- "getDefaultAdapter",
- "()Landroid/bluetooth/BluetoothAdapter;");
+ secFlags = QBluetooth::Security::Secure;
+ adapter = getDefaultBluetoothAdapter();
qRegisterMetaType<QBluetoothSocket::SocketError>();
qRegisterMetaType<QBluetoothSocket::SocketState>();
}
QBluetoothSocketPrivateAndroid::~QBluetoothSocketPrivateAndroid()
{
- if (state != QBluetoothSocket::UnconnectedState)
+ if (state != QBluetoothSocket::SocketState::UnconnectedState)
emit closeJavaSocket();
}
@@ -209,124 +160,9 @@ bool QBluetoothSocketPrivateAndroid::ensureNativeSocket(QBluetoothServiceInfo::P
return false;
}
-bool QBluetoothSocketPrivateAndroid::fallBackConnect(QAndroidJniObject uuid, int channel)
-{
- qCWarning(QT_BT_ANDROID) << "Falling back to getServiceChannel() workaround.";
-
- QAndroidJniEnvironment env;
-
- QAndroidJniObject remoteDeviceClass = remoteDevice.callObjectMethod("getClass", "()Ljava/lang/Class;");
- if (!remoteDeviceClass.isValid()) {
- qCWarning(QT_BT_ANDROID) << "Could not invoke BluetoothDevice.getClass.";
- return false;
- }
-
- QAndroidJniObject integerObject = QAndroidJniObject::getStaticObjectField(
- "java/lang/Integer", "TYPE", "Ljava/lang/Class;");
- if (!integerObject.isValid()) {
- qCWarning(QT_BT_ANDROID) << "Could not get Integer.TYPE";
- if (env->ExceptionCheck()) {
- env->ExceptionDescribe();
- env->ExceptionClear();
- }
-
- return false;
- }
-
- jclass classClass = QJNIEnvironmentPrivate::findClass("java/lang/Class");
- jobjectArray rawArray = env->NewObjectArray(1, classClass,
- integerObject.object<jobject>());
- QAndroidJniObject paramTypes(rawArray);
- env->DeleteLocalRef(rawArray);
- if (!paramTypes.isValid()) {
- qCWarning(QT_BT_ANDROID) << "Could not create new Class[]{Integer.TYPE}";
-
- if (env->ExceptionCheck()) {
- env->ExceptionDescribe();
- env->ExceptionClear();
- }
- return false;
- }
-
- QAndroidJniObject parcelUuid("android/os/ParcelUuid", "(Ljava/util/UUID;)V",
- uuid.object());
- if (parcelUuid.isValid()) {
- jint socketChannel = remoteDevice.callMethod<jint>("getServiceChannel",
- "(Landroid/os/ParcelUuid;)I",
- parcelUuid.object());
- if (env->ExceptionCheck()) {
- env->ExceptionDescribe();
- env->ExceptionClear();
- } else {
- if (socketChannel
- == remoteDevice.getStaticField<jint>("android/bluetooth/BluetoothDevice", "ERROR")
- || socketChannel == -1) {
- qCWarning(QT_BT_ANDROID) << "Cannot determine RFCOMM service channel.";
- } else {
- qCWarning(QT_BT_ANDROID) << "Using found rfcomm channel" << socketChannel;
- channel = socketChannel;
- }
- }
- }
-
- QAndroidJniObject method;
- if (secFlags == QBluetooth::NoSecurity) {
- qCDebug(QT_BT_ANDROID) << "Connnecting via insecure rfcomm";
- method = remoteDeviceClass.callObjectMethod(
- "getMethod",
- "(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;",
- QAndroidJniObject::fromString(QLatin1String("createInsecureRfcommSocket")).object<jstring>(),
- paramTypes.object<jobjectArray>());
- } else {
- qCDebug(QT_BT_ANDROID) << "Connnecting via secure rfcomm";
- method = remoteDeviceClass.callObjectMethod(
- "getMethod",
- "(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;",
- QAndroidJniObject::fromString(QLatin1String("createRfcommSocket")).object<jstring>(),
- paramTypes.object<jobjectArray>());
- }
- if (!method.isValid() || env->ExceptionCheck()) {
- qCWarning(QT_BT_ANDROID) << "Could not invoke getMethod";
- if (env->ExceptionCheck()) {
- env->ExceptionDescribe();
- env->ExceptionClear();
- }
- return false;
- }
-
- jclass objectClass = QJNIEnvironmentPrivate::findClass("java/lang/Object");
- QAndroidJniObject channelObject = QAndroidJniObject::callStaticObjectMethod(
- "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", channel);
- rawArray = env->NewObjectArray(1, objectClass, channelObject.object<jobject>());
-
- QAndroidJniObject invokeResult = method.callObjectMethod("invoke",
- "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;",
- remoteDevice.object<jobject>(), rawArray);
- env->DeleteLocalRef(rawArray);
- if (!invokeResult.isValid())
- {
- qCWarning(QT_BT_ANDROID) << "Invoke Resulted with error.";
- if (env->ExceptionCheck()) {
- env->ExceptionDescribe();
- env->ExceptionClear();
- }
-
- return false;
- }
-
- socketObject = QAndroidJniObject(invokeResult);
-
- WorkerThread *workerThread = new WorkerThread();
- workerThread->setupWorker(this, socketObject, uuid, USE_FALLBACK);
- workerThread->start();
- emit connectJavaSocket();
-
- qCWarning(QT_BT_ANDROID) << "Workaround thread invoked.";
- return true;
-}
-
/*
- * Workaround for QTBUG-61392
+ * Workaround for QTBUG-61392. If the underlying Android bug gets fixed,
+ * we need to consider restoring the non-reversed fallbackConnect from the repository.
*/
bool QBluetoothSocketPrivateAndroid::fallBackReversedConnect(const QBluetoothUuid &uuid)
{
@@ -337,38 +173,32 @@ bool QBluetoothSocketPrivateAndroid::fallBackReversedConnect(const QBluetoothUui
if (reverse.isNull())
return false;
- //cut leading { and trailing } {xxx-xxx}
- QString tempUuid = reverse.toString();
- tempUuid.chop(1); //remove trailing '}'
- tempUuid.remove(0, 1); //remove first '{'
-
- QAndroidJniEnvironment env;
- const QAndroidJniObject inputString = QAndroidJniObject::fromString(tempUuid);
- const QAndroidJniObject uuidObject = QAndroidJniObject::callStaticObjectMethod("java/util/UUID", "fromString",
- "(Ljava/lang/String;)Ljava/util/UUID;",
- inputString.object<jstring>());
-
- if (secFlags == QBluetooth::NoSecurity) {
- qCDebug(QT_BT_ANDROID) << "Connnecting via insecure rfcomm";
- socketObject = remoteDevice.callObjectMethod("createInsecureRfcommSocketToServiceRecord",
- "(Ljava/util/UUID;)Landroid/bluetooth/BluetoothSocket;",
- uuidObject.object<jobject>());
+ QString tempUuid = reverse.toString(QUuid::WithoutBraces);
+
+ QJniEnvironment env;
+ const QJniObject inputString = QJniObject::fromString(tempUuid);
+ const QJniObject uuidObject = QJniObject::callStaticMethod<QtJniTypes::UUID>(
+ QtJniTypes::Traits<QtJniTypes::UUID>::className(), "fromString",
+ inputString.object<jstring>());
+
+ if (secFlags == QBluetooth::SecurityFlags(QBluetooth::Security::NoSecurity)) {
+ qCDebug(QT_BT_ANDROID) << "Connecting via insecure rfcomm";
+ socketObject = remoteDevice.callMethod<QtJniTypes::BluetoothSocket>(
+ "createInsecureRfcommSocketToServiceRecord",
+ uuidObject.object<QtJniTypes::UUID>());
} else {
- qCDebug(QT_BT_ANDROID) << "Connnecting via secure rfcomm";
- socketObject = remoteDevice.callObjectMethod("createRfcommSocketToServiceRecord",
- "(Ljava/util/UUID;)Landroid/bluetooth/BluetoothSocket;",
- uuidObject.object<jobject>());
+ qCDebug(QT_BT_ANDROID) << "Connecting via secure rfcomm";
+ socketObject = remoteDevice.callMethod<QtJniTypes::BluetoothSocket>(
+ "createRfcommSocketToServiceRecord",
+ uuidObject.object<QtJniTypes::UUID>());
}
- if (env->ExceptionCheck()) {
- env->ExceptionDescribe();
- env->ExceptionClear();
-
- socketObject = remoteDevice = QAndroidJniObject();
+ if (!socketObject.isValid()) {
+ remoteDevice = QJniObject();
errorString = QBluetoothSocket::tr("Cannot connect to %1",
"%1 = uuid").arg(reverse.toString());
- q->setSocketError(QBluetoothSocket::ServiceNotFoundError);
- q->setSocketState(QBluetoothSocket::UnconnectedState);
+ q->setSocketError(QBluetoothSocket::SocketError::ServiceNotFoundError);
+ q->setSocketState(QBluetoothSocket::SocketState::UnconnectedState);
return false;
}
@@ -388,14 +218,13 @@ bool QBluetoothSocketPrivateAndroid::fallBackReversedConnect(const QBluetoothUui
* 3. if threaded connect succeeds call socketConnectSuccess() via signals
* -> done
* 4. if threaded connect fails call defaultSocketConnectFailed() via signals
- * 5. call fallBackConnect() if Android version 22 or below
- * -> Android 23+ complete failure of entire connectToServiceHelper()
- * 6. call fallBackReversedConnect() if Android version 23 or above
+ * 5. call fallBackReversedConnect()
* -> if failure entire connectToServiceHelper() fails
- * 7. if threaded connect on one of above fallbacks succeeds call socketConnectSuccess()
+ * Note: This fallback can be disabled with private API boolean
+ * 6. if threaded connect on one of above fallbacks succeeds call socketConnectSuccess()
* via signals
* -> done
- * 8. if threaded connect on fallback channel fails call fallbackSocketConnectFailed()
+ * 7. if threaded connect on fallback channel fails call fallbackSocketConnectFailed()
* -> complete failure of entire connectToServiceHelper()
* */
void QBluetoothSocketPrivateAndroid::connectToServiceHelper(const QBluetoothAddress &address,
@@ -407,71 +236,71 @@ void QBluetoothSocketPrivateAndroid::connectToServiceHelper(const QBluetoothAddr
qCDebug(QT_BT_ANDROID) << "connectToServiceHelper()" << address.toString() << uuid.toString();
- q->setSocketState(QBluetoothSocket::ConnectingState);
+ if (!ensureAndroidPermission(QBluetoothPermission::Access)) {
+ qCWarning(QT_BT_ANDROID) << "Bluetooth socket connect failed due to missing permissions";
+ errorString = QBluetoothSocket::tr(
+ "Bluetooth socket connect failed due to missing permissions.");
+ q->setSocketError(QBluetoothSocket::SocketError::MissingPermissionsError);
+ q->setSocketState(QBluetoothSocket::SocketState::UnconnectedState);
+ return;
+ }
+
+ q->setSocketState(QBluetoothSocket::SocketState::ConnectingState);
if (!adapter.isValid()) {
qCWarning(QT_BT_ANDROID) << "Device does not support Bluetooth";
errorString = QBluetoothSocket::tr("Device does not support Bluetooth");
- q->setSocketError(QBluetoothSocket::NetworkError);
- q->setSocketState(QBluetoothSocket::UnconnectedState);
+ q->setSocketError(QBluetoothSocket::SocketError::NetworkError);
+ q->setSocketState(QBluetoothSocket::SocketState::UnconnectedState);
return;
}
const int state = adapter.callMethod<jint>("getState");
if (state != 12 ) { //BluetoothAdapter.STATE_ON
- qCWarning(QT_BT_ANDROID) << "Bt device offline";
+ qCWarning(QT_BT_ANDROID) << "Bluetooth device offline";
errorString = QBluetoothSocket::tr("Device is powered off");
- q->setSocketError(QBluetoothSocket::NetworkError);
- q->setSocketState(QBluetoothSocket::UnconnectedState);
+ q->setSocketError(QBluetoothSocket::SocketError::NetworkError);
+ q->setSocketState(QBluetoothSocket::SocketState::UnconnectedState);
return;
}
- QAndroidJniEnvironment env;
- QAndroidJniObject inputString = QAndroidJniObject::fromString(address.toString());
- remoteDevice = adapter.callObjectMethod("getRemoteDevice",
- "(Ljava/lang/String;)Landroid/bluetooth/BluetoothDevice;",
+ QJniEnvironment env;
+ QJniObject inputString = QJniObject::fromString(address.toString());
+ remoteDevice = adapter.callMethod<QtJniTypes::BluetoothDevice>("getRemoteDevice",
inputString.object<jstring>());
- if (env->ExceptionCheck()) {
- env->ExceptionDescribe();
- env->ExceptionClear();
-
+ if (!remoteDevice.isValid()) {
errorString = QBluetoothSocket::tr("Cannot access address %1", "%1 = Bt address e.g. 11:22:33:44:55:66").arg(address.toString());
- q->setSocketError(QBluetoothSocket::HostNotFoundError);
- q->setSocketState(QBluetoothSocket::UnconnectedState);
+ q->setSocketError(QBluetoothSocket::SocketError::HostNotFoundError);
+ q->setSocketState(QBluetoothSocket::SocketState::UnconnectedState);
return;
}
//cut leading { and trailing } {xxx-xxx}
- QString tempUuid = uuid.toString();
- tempUuid.chop(1); //remove trailing '}'
- tempUuid.remove(0, 1); //remove first '{'
-
- inputString = QAndroidJniObject::fromString(tempUuid);
- QAndroidJniObject uuidObject = QAndroidJniObject::callStaticObjectMethod("java/util/UUID", "fromString",
- "(Ljava/lang/String;)Ljava/util/UUID;",
- inputString.object<jstring>());
-
- if (secFlags == QBluetooth::NoSecurity) {
- qCDebug(QT_BT_ANDROID) << "Connnecting via insecure rfcomm";
- socketObject = remoteDevice.callObjectMethod("createInsecureRfcommSocketToServiceRecord",
- "(Ljava/util/UUID;)Landroid/bluetooth/BluetoothSocket;",
- uuidObject.object<jobject>());
+ const QString tempUuid = uuid.toString(QUuid::WithoutBraces);
+
+ inputString = QJniObject::fromString(tempUuid);
+ const QJniObject uuidObject = QJniObject::callStaticMethod<QtJniTypes::UUID>(
+ QtJniTypes::Traits<QtJniTypes::UUID>::className(), "fromString",
+ inputString.object<jstring>());
+
+ if (secFlags == QBluetooth::SecurityFlags(QBluetooth::Security::NoSecurity)) {
+ qCDebug(QT_BT_ANDROID) << "Connecting via insecure rfcomm";
+ socketObject = remoteDevice.callMethod<QtJniTypes::BluetoothSocket>(
+ "createInsecureRfcommSocketToServiceRecord",
+ uuidObject.object<QtJniTypes::UUID>());
} else {
- qCDebug(QT_BT_ANDROID) << "Connnecting via secure rfcomm";
- socketObject = remoteDevice.callObjectMethod("createRfcommSocketToServiceRecord",
- "(Ljava/util/UUID;)Landroid/bluetooth/BluetoothSocket;",
- uuidObject.object<jobject>());
+ qCDebug(QT_BT_ANDROID) << "Connecting via secure rfcomm";
+ socketObject = remoteDevice.callMethod<QtJniTypes::BluetoothSocket>(
+ "createRfcommSocketToServiceRecord",
+ uuidObject.object<QtJniTypes::UUID>());
}
- if (env->ExceptionCheck()) {
- env->ExceptionDescribe();
- env->ExceptionClear();
-
- socketObject = remoteDevice = QAndroidJniObject();
+ if (!socketObject.isValid()) {
+ remoteDevice = QJniObject();
errorString = QBluetoothSocket::tr("Cannot connect to %1 on %2",
"%1 = uuid, %2 = Bt address").arg(uuid.toString()).arg(address.toString());
- q->setSocketError(QBluetoothSocket::ServiceNotFoundError);
- q->setSocketState(QBluetoothSocket::UnconnectedState);
+ q->setSocketError(QBluetoothSocket::SocketError::ServiceNotFoundError);
+ q->setSocketState(QBluetoothSocket::SocketState::UnconnectedState);
return;
}
@@ -486,11 +315,11 @@ void QBluetoothSocketPrivateAndroid::connectToService(
{
Q_Q(QBluetoothSocket);
- if (q->state() != QBluetoothSocket::UnconnectedState
- && q->state() != QBluetoothSocket::ServiceLookupState) {
+ if (q->state() != QBluetoothSocket::SocketState::UnconnectedState
+ && q->state() != QBluetoothSocket::SocketState::ServiceLookupState) {
qCWarning(QT_BT_ANDROID) << "QBluetoothSocketPrivateAndroid::connectToService called on busy socket";
errorString = QBluetoothSocket::tr("Trying to connect while connection is in progress");
- q->setSocketError(QBluetoothSocket::OperationError);
+ q->setSocketError(QBluetoothSocket::SocketError::OperationError);
return;
}
@@ -522,7 +351,7 @@ void QBluetoothSocketPrivateAndroid::connectToService(
if (!ensureNativeSocket(protocol)) {
errorString = QBluetoothSocket::tr("Socket type not supported");
- q->setSocketError(QBluetoothSocket::UnsupportedProtocolError);
+ q->setSocketError(QBluetoothSocket::SocketError::UnsupportedProtocolError);
return;
}
connectToServiceHelper(service.device().address(), service.serviceUuid(), openMode);
@@ -534,10 +363,10 @@ void QBluetoothSocketPrivateAndroid::connectToService(
{
Q_Q(QBluetoothSocket);
- if (q->state() != QBluetoothSocket::UnconnectedState) {
+ if (q->state() != QBluetoothSocket::SocketState::UnconnectedState) {
qCWarning(QT_BT_ANDROID) << "QBluetoothSocketPrivateAndroid::connectToService called on busy socket";
errorString = QBluetoothSocket::tr("Trying to connect while connection is in progress");
- q->setSocketError(QBluetoothSocket::OperationError);
+ q->setSocketError(QBluetoothSocket::SocketError::OperationError);
return;
}
@@ -545,13 +374,13 @@ void QBluetoothSocketPrivateAndroid::connectToService(
qCWarning(QT_BT_ANDROID) << "QBluetoothSocketPrivateAndroid::connectToService cannot "
"connect with 'UnknownProtocol' (type provided by given service)";
errorString = QBluetoothSocket::tr("Socket type not supported");
- q->setSocketError(QBluetoothSocket::UnsupportedProtocolError);
+ q->setSocketError(QBluetoothSocket::SocketError::UnsupportedProtocolError);
return;
}
if (!ensureNativeSocket(q->socketType())) {
errorString = QBluetoothSocket::tr("Socket type not supported");
- q->setSocketError(QBluetoothSocket::UnsupportedProtocolError);
+ q->setSocketError(QBluetoothSocket::SocketError::UnsupportedProtocolError);
return;
}
connectToServiceHelper(address, uuid, openMode);
@@ -567,14 +396,14 @@ void QBluetoothSocketPrivateAndroid::connectToService(
Q_Q(QBluetoothSocket);
errorString = tr("Connecting to port is not supported");
- q->setSocketError(QBluetoothSocket::ServiceNotFoundError);
+ q->setSocketError(QBluetoothSocket::SocketError::ServiceNotFoundError);
qCWarning(QT_BT_ANDROID) << "Connecting to port is not supported";
}
-void QBluetoothSocketPrivateAndroid::socketConnectSuccess(const QAndroidJniObject &socket)
+void QBluetoothSocketPrivateAndroid::socketConnectSuccess(const QJniObject &socket)
{
Q_Q(QBluetoothSocket);
- QAndroidJniEnvironment env;
+ QJniEnvironment env;
// test we didn't get a success from a previous connect
// which was cleaned up late
@@ -586,54 +415,53 @@ void QBluetoothSocketPrivateAndroid::socketConnectSuccess(const QAndroidJniObjec
inputThread = 0;
}
- inputStream = socketObject.callObjectMethod("getInputStream", "()Ljava/io/InputStream;");
- outputStream = socketObject.callObjectMethod("getOutputStream", "()Ljava/io/OutputStream;");
+ inputStream = socketObject.callMethod<QtJniTypes::InputStream>("getInputStream");
+ outputStream = socketObject.callMethod<QtJniTypes::OutputStream>("getOutputStream");
- if (env->ExceptionCheck() || !inputStream.isValid() || !outputStream.isValid()) {
- env->ExceptionDescribe();
- env->ExceptionClear();
+ if (!inputStream.isValid() || !outputStream.isValid()) {
emit closeJavaSocket();
- socketObject = inputStream = outputStream = remoteDevice = QAndroidJniObject();
+ socketObject = inputStream = outputStream = remoteDevice = QJniObject();
errorString = QBluetoothSocket::tr("Obtaining streams for service failed");
- q->setSocketError(QBluetoothSocket::NetworkError);
- q->setSocketState(QBluetoothSocket::UnconnectedState);
+ q->setSocketError(QBluetoothSocket::SocketError::NetworkError);
+ q->setSocketState(QBluetoothSocket::SocketState::UnconnectedState);
return;
}
inputThread = new InputStreamThread(this);
QObject::connect(inputThread, SIGNAL(dataAvailable()),
q, SIGNAL(readyRead()), Qt::QueuedConnection);
- QObject::connect(inputThread, SIGNAL(error(int)),
- this, SLOT(inputThreadError(int)), Qt::QueuedConnection);
+ QObject::connect(inputThread, SIGNAL(errorOccurred(int)), this, SLOT(inputThreadError(int)),
+ Qt::QueuedConnection);
if (!inputThread->run()) {
//close socket again
emit closeJavaSocket();
- socketObject = inputStream = outputStream = remoteDevice = QAndroidJniObject();
+ socketObject = inputStream = outputStream = remoteDevice = QJniObject();
delete inputThread;
inputThread = 0;
errorString = QBluetoothSocket::tr("Input stream thread cannot be started");
- q->setSocketError(QBluetoothSocket::NetworkError);
- q->setSocketState(QBluetoothSocket::UnconnectedState);
+ q->setSocketError(QBluetoothSocket::SocketError::NetworkError);
+ q->setSocketState(QBluetoothSocket::SocketState::UnconnectedState);
return;
}
// only unbuffered behavior supported at this stage
q->setOpenMode(QIODevice::ReadWrite|QIODevice::Unbuffered);
- q->setSocketState(QBluetoothSocket::ConnectedState);
+ q->setSocketState(QBluetoothSocket::SocketState::ConnectedState);
}
void QBluetoothSocketPrivateAndroid::defaultSocketConnectFailed(
- const QAndroidJniObject &socket, const QAndroidJniObject &targetUuid,
+ const QJniObject &socket, const QJniObject &targetUuid,
const QBluetoothUuid &qtTargetUuid)
{
+ Q_UNUSED(targetUuid);
Q_Q(QBluetoothSocket);
// test we didn't get a fail from a previous connect
@@ -641,26 +469,17 @@ void QBluetoothSocketPrivateAndroid::defaultSocketConnectFailed(
if (socket != socketObject)
return;
- bool success = false;
- if (QtAndroid::androidSdkVersion() <= 22)
- success = fallBackConnect(targetUuid, FALLBACK_CHANNEL);
- else if (useReverseUuidWorkAroundConnect) // version 23+ has Android bug (see QTBUG-61392)
- success = fallBackReversedConnect(qtTargetUuid);
-
- if (!success) {
+ if (!useReverseUuidWorkAroundConnect || !fallBackReversedConnect(qtTargetUuid)) {
errorString = QBluetoothSocket::tr("Connection to service failed");
- socketObject = remoteDevice = QAndroidJniObject();
- q->setSocketError(QBluetoothSocket::ServiceNotFoundError);
- q->setSocketState(QBluetoothSocket::UnconnectedState);
-
- QAndroidJniEnvironment env;
- env->ExceptionClear(); // just in case
- qCWarning(QT_BT_ANDROID) << "Workaround failed";
+ socketObject = remoteDevice = QJniObject();
+ q->setSocketError(QBluetoothSocket::SocketError::ServiceNotFoundError);
+ q->setSocketState(QBluetoothSocket::SocketState::UnconnectedState);
+ qCWarning(QT_BT_ANDROID) << "Socket connect workaround failed";
}
}
void QBluetoothSocketPrivateAndroid::fallbackSocketConnectFailed(
- const QAndroidJniObject &socket, const QAndroidJniObject &targetUuid)
+ const QJniObject &socket, const QJniObject &targetUuid)
{
Q_UNUSED(targetUuid);
Q_Q(QBluetoothSocket);
@@ -672,19 +491,19 @@ void QBluetoothSocketPrivateAndroid::fallbackSocketConnectFailed(
qCWarning(QT_BT_ANDROID) << "Socket connect via workaround failed.";
errorString = QBluetoothSocket::tr("Connection to service failed");
- socketObject = remoteDevice = QAndroidJniObject();
+ socketObject = remoteDevice = QJniObject();
- q->setSocketError(QBluetoothSocket::ServiceNotFoundError);
- q->setSocketState(QBluetoothSocket::UnconnectedState);
+ q->setSocketError(QBluetoothSocket::SocketError::ServiceNotFoundError);
+ q->setSocketState(QBluetoothSocket::SocketState::UnconnectedState);
}
void QBluetoothSocketPrivateAndroid::abort()
{
- if (state == QBluetoothSocket::UnconnectedState)
+ if (state == QBluetoothSocket::SocketState::UnconnectedState)
return;
if (socketObject.isValid()) {
- QAndroidJniEnvironment env;
+ QJniEnvironment env;
/*
* BluetoothSocket.close() triggers an abort of the input stream
@@ -699,7 +518,7 @@ void QBluetoothSocketPrivateAndroid::abort()
emit closeJavaSocket();
- inputStream = outputStream = socketObject = remoteDevice = QAndroidJniObject();
+ inputStream = outputStream = socketObject = remoteDevice = QJniObject();
if (inputThread) {
// inputThread exists hence we had a successful connect
@@ -716,7 +535,7 @@ void QBluetoothSocketPrivateAndroid::abort()
// Unconnected (now) in advance
Q_Q(QBluetoothSocket);
q->setOpenMode(QIODevice::NotOpen);
- q->setSocketState(QBluetoothSocket::UnconnectedState);
+ q->setSocketState(QBluetoothSocket::SocketState::UnconnectedState);
emit q->readChannelFinished();
}
}
@@ -724,8 +543,12 @@ void QBluetoothSocketPrivateAndroid::abort()
QString QBluetoothSocketPrivateAndroid::localName() const
{
- if (adapter.isValid())
- return adapter.callObjectMethod<jstring>("getName").toString();
+ if (!ensureAndroidPermission(QBluetoothPermission::Access)) {
+ qCWarning(QT_BT_ANDROID) << "Bluetooth socket localName() failed due to"
+ "missing permissions";
+ } else if (adapter.isValid()) {
+ return adapter.callMethod<jstring>("getName").toString();
+ }
return QString();
}
@@ -733,8 +556,13 @@ QString QBluetoothSocketPrivateAndroid::localName() const
QBluetoothAddress QBluetoothSocketPrivateAndroid::localAddress() const
{
QString result;
- if (adapter.isValid())
- result = adapter.callObjectMethod("getAddress", "()Ljava/lang/String;").toString();
+
+ if (!ensureAndroidPermission(QBluetoothPermission::Access)) {
+ qCWarning(QT_BT_ANDROID) << "Bluetooth socket localAddress() failed due to"
+ "missing permissions";
+ } else if (adapter.isValid()) {
+ result = adapter.callMethod<jstring>("getAddress").toString();
+ }
return QBluetoothAddress(result);
}
@@ -750,7 +578,7 @@ QString QBluetoothSocketPrivateAndroid::peerName() const
if (!remoteDevice.isValid())
return QString();
- return remoteDevice.callObjectMethod("getName", "()Ljava/lang/String;").toString();
+ return remoteDevice.callMethod<jstring>("getName").toString();
}
QBluetoothAddress QBluetoothSocketPrivateAndroid::peerAddress() const
@@ -758,9 +586,7 @@ QBluetoothAddress QBluetoothSocketPrivateAndroid::peerAddress() const
if (!remoteDevice.isValid())
return QBluetoothAddress();
- const QString address = remoteDevice.callObjectMethod("getAddress",
- "()Ljava/lang/String;").toString();
-
+ const QString address = remoteDevice.callMethod<jstring>("getAddress").toString();
return QBluetoothAddress(address);
}
@@ -774,25 +600,27 @@ qint64 QBluetoothSocketPrivateAndroid::writeData(const char *data, qint64 maxSiz
{
//TODO implement buffered behavior (so far only unbuffered)
Q_Q(QBluetoothSocket);
- if (state != QBluetoothSocket::ConnectedState || !outputStream.isValid()) {
+ if (state != QBluetoothSocket::SocketState::ConnectedState || !outputStream.isValid()) {
qCWarning(QT_BT_ANDROID) << "Socket::writeData: " << state << outputStream.isValid();
errorString = QBluetoothSocket::tr("Cannot write while not connected");
- q->setSocketError(QBluetoothSocket::OperationError);
+ q->setSocketError(QBluetoothSocket::SocketError::OperationError);
return -1;
}
- QAndroidJniEnvironment env;
+ QJniEnvironment env;
jbyteArray nativeData = env->NewByteArray((qint32)maxSize);
env->SetByteArrayRegion(nativeData, 0, (qint32)maxSize, reinterpret_cast<const jbyte*>(data));
- outputStream.callMethod<void>("write", "([BII)V", nativeData, 0, (qint32)maxSize);
+ auto methodId = env.findMethod(outputStream.objectClass(),
+ "write",
+ "([BII)V");
+ if (methodId)
+ env->CallVoidMethod(outputStream.object(), methodId, nativeData, 0, (qint32)maxSize);
env->DeleteLocalRef(nativeData);
- if (env->ExceptionCheck()) {
+ if (!methodId || env.checkAndClearExceptions()) {
qCWarning(QT_BT_ANDROID) << "Error while writing";
- env->ExceptionDescribe();
- env->ExceptionClear();
errorString = QBluetoothSocket::tr("Error during write on socket.");
- q->setSocketError(QBluetoothSocket::NetworkError);
+ q->setSocketError(QBluetoothSocket::SocketError::NetworkError);
return -1;
}
@@ -803,10 +631,10 @@ qint64 QBluetoothSocketPrivateAndroid::writeData(const char *data, qint64 maxSiz
qint64 QBluetoothSocketPrivateAndroid::readData(char *data, qint64 maxSize)
{
Q_Q(QBluetoothSocket);
- if (state != QBluetoothSocket::ConnectedState || !inputThread) {
+ if (state != QBluetoothSocket::SocketState::ConnectedState || !inputThread) {
qCWarning(QT_BT_ANDROID) << "Socket::readData: " << state << inputThread ;
errorString = QBluetoothSocket::tr("Cannot read while not connected");
- q->setSocketError(QBluetoothSocket::OperationError);
+ q->setSocketError(QBluetoothSocket::SocketError::OperationError);
return -1;
}
@@ -819,7 +647,7 @@ void QBluetoothSocketPrivateAndroid::inputThreadError(int errorCode)
if (errorCode != -1) { //magic error which is expected and can be ignored
errorString = QBluetoothSocket::tr("Network error during read");
- q->setSocketError(QBluetoothSocket::NetworkError);
+ q->setSocketError(QBluetoothSocket::SocketError::NetworkError);
}
//finally we can delete the InputStreamThread
@@ -834,7 +662,7 @@ void QBluetoothSocketPrivateAndroid::inputThreadError(int errorCode)
emit closeJavaSocket();
- inputStream = outputStream = remoteDevice = socketObject = QAndroidJniObject();
+ inputStream = outputStream = remoteDevice = socketObject = QJniObject();
if (inputThread) {
// deleted already above (client->deleteLater())
inputThread = 0;
@@ -842,7 +670,7 @@ void QBluetoothSocketPrivateAndroid::inputThreadError(int errorCode)
}
q->setOpenMode(QIODevice::NotOpen);
- q->setSocketState(QBluetoothSocket::UnconnectedState);
+ q->setSocketState(QBluetoothSocket::SocketState::UnconnectedState);
emit q->readChannelFinished();
}
@@ -859,19 +687,19 @@ bool QBluetoothSocketPrivateAndroid::setSocketDescriptor(int socketDescriptor, Q
QBluetoothSocket::SocketState socketState, QBluetoothSocket::OpenMode openMode)
{
Q_UNUSED(socketDescriptor);
- Q_UNUSED(socketType)
+ Q_UNUSED(socketType);
Q_UNUSED(socketState);
Q_UNUSED(openMode);
qCWarning(QT_BT_ANDROID) << "No socket descriptor support on Android.";
return false;
}
-bool QBluetoothSocketPrivateAndroid::setSocketDescriptor(const QAndroidJniObject &socket, QBluetoothServiceInfo::Protocol socketType_,
+bool QBluetoothSocketPrivateAndroid::setSocketDescriptor(const QJniObject &socket, QBluetoothServiceInfo::Protocol socketType_,
QBluetoothSocket::SocketState socketState, QBluetoothSocket::OpenMode openMode)
{
Q_Q(QBluetoothSocket);
- if (q->state() != QBluetoothSocket::UnconnectedState || !socket.isValid())
+ if (q->state() != QBluetoothSocket::SocketState::UnconnectedState || !socket.isValid())
return false;
if (!ensureNativeSocket(socketType_))
@@ -879,31 +707,24 @@ bool QBluetoothSocketPrivateAndroid::setSocketDescriptor(const QAndroidJniObject
socketObject = socket;
- QAndroidJniEnvironment env;
- inputStream = socketObject.callObjectMethod("getInputStream", "()Ljava/io/InputStream;");
- outputStream = socketObject.callObjectMethod("getOutputStream", "()Ljava/io/OutputStream;");
+ inputStream = socketObject.callMethod<QtJniTypes::InputStream>("getInputStream");
+ outputStream = socketObject.callMethod<QtJniTypes::OutputStream>("getOutputStream");
- if (env->ExceptionCheck() || !inputStream.isValid() || !outputStream.isValid()) {
- env->ExceptionDescribe();
- env->ExceptionClear();
+ if (!inputStream.isValid() || !outputStream.isValid()) {
//close socket again
socketObject.callMethod<void>("close");
- if (env->ExceptionCheck()) {
- env->ExceptionDescribe();
- env->ExceptionClear();
- }
- socketObject = inputStream = outputStream = remoteDevice = QAndroidJniObject();
+ socketObject = inputStream = outputStream = remoteDevice = QJniObject();
errorString = QBluetoothSocket::tr("Obtaining streams for service failed");
- q->setSocketError(QBluetoothSocket::NetworkError);
- q->setSocketState(QBluetoothSocket::UnconnectedState);
+ q->setSocketError(QBluetoothSocket::SocketError::NetworkError);
+ q->setSocketState(QBluetoothSocket::SocketState::UnconnectedState);
return false;
}
- remoteDevice = socketObject.callObjectMethod("getRemoteDevice", "()Landroid/bluetooth/BluetoothDevice;");
+ remoteDevice = socketObject.callMethod<QtJniTypes::BluetoothDevice>("getRemoteDevice");
if (inputThread) {
inputThread->deleteLater();
@@ -912,8 +733,8 @@ bool QBluetoothSocketPrivateAndroid::setSocketDescriptor(const QAndroidJniObject
inputThread = new InputStreamThread(this);
QObject::connect(inputThread, SIGNAL(dataAvailable()),
q, SIGNAL(readyRead()), Qt::QueuedConnection);
- QObject::connect(inputThread, SIGNAL(error(int)),
- this, SLOT(inputThreadError(int)), Qt::QueuedConnection);
+ QObject::connect(inputThread, SIGNAL(errorOccurred(int)), this, SLOT(inputThreadError(int)),
+ Qt::QueuedConnection);
inputThread->run();
// WorkerThread manages all sockets for us
@@ -921,7 +742,7 @@ bool QBluetoothSocketPrivateAndroid::setSocketDescriptor(const QAndroidJniObject
// server socket listener (see QBluetoothServer)
// Therefore we only use WorkerThread to potentially close it later on
WorkerThread *workerThread = new WorkerThread();
- workerThread->setupWorker(this, socketObject, QAndroidJniObject(), !USE_FALLBACK);
+ workerThread->setupWorker(this, socketObject, QJniObject(), !USE_FALLBACK);
workerThread->start();
q->setOpenMode(openMode | QIODevice::Unbuffered);
@@ -952,9 +773,6 @@ qint64 QBluetoothSocketPrivateAndroid::bytesToWrite() const
*/
QBluetoothUuid QBluetoothSocketPrivateAndroid::reverseUuid(const QBluetoothUuid &serviceUuid)
{
- if (QtAndroid::androidSdkVersion() < 23)
- return serviceUuid;
-
if (serviceUuid.isNull())
return QBluetoothUuid();
@@ -963,8 +781,8 @@ QBluetoothUuid QBluetoothSocketPrivateAndroid::reverseUuid(const QBluetoothUuid
if (isBaseUuid)
return serviceUuid;
- const quint128 original = serviceUuid.toUInt128();
- quint128 reversed;
+ const QUuid::Id128Bytes original = serviceUuid.toBytes();
+ QUuid::Id128Bytes reversed;
for (int i = 0; i < 16; i++)
reversed.data[15-i] = original.data[i];
return QBluetoothUuid{reversed};
diff --git a/src/bluetooth/qbluetoothsocket_android_p.h b/src/bluetooth/qbluetoothsocket_android_p.h
index 042e1bcd..a2cbbdaa 100644
--- a/src/bluetooth/qbluetoothsocket_android_p.h
+++ b/src/bluetooth/qbluetoothsocket_android_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QBLUETOOTHSOCKET_ANDROID_P_H
@@ -54,7 +18,7 @@
#include "qbluetoothsocketbase_p.h"
-#include <QtAndroidExtras/QAndroidJniObject>
+#include <QtCore/QJniObject>
#include <QtCore/QPointer>
#include "android/inputstreamthread_p.h"
#include <jni.h>
@@ -81,7 +45,6 @@ public:
void connectToService(const QBluetoothAddress &address, quint16 port,
QIODevice::OpenMode openMode) override;
- bool fallBackConnect(QAndroidJniObject uuid, int channel);
bool fallBackReversedConnect(const QBluetoothUuid &uuid);
bool ensureNativeSocket(QBluetoothServiceInfo::Protocol type) override;
@@ -100,12 +63,12 @@ public:
qint64 writeData(const char *data, qint64 maxSize) override;
qint64 readData(char *data, qint64 maxSize) override;
- bool setSocketDescriptor(const QAndroidJniObject &socket, QBluetoothServiceInfo::Protocol socketType,
- QBluetoothSocket::SocketState socketState = QBluetoothSocket::ConnectedState,
+ bool setSocketDescriptor(const QJniObject &socket, QBluetoothServiceInfo::Protocol socketType,
+ QBluetoothSocket::SocketState socketState = QBluetoothSocket::SocketState::ConnectedState,
QBluetoothSocket::OpenMode openMode = QBluetoothSocket::ReadWrite) override;
bool setSocketDescriptor(int socketDescriptor, QBluetoothServiceInfo::Protocol socketType,
- QBluetoothSocket::SocketState socketState = QBluetoothSocket::ConnectedState,
+ QBluetoothSocket::SocketState socketState = QBluetoothSocket::SocketState::ConnectedState,
QBluetoothSocket::OpenMode openMode = QBluetoothSocket::ReadWrite) override;
qint64 bytesAvailable() const override;
@@ -114,20 +77,20 @@ public:
static QBluetoothUuid reverseUuid(const QBluetoothUuid &serviceUuid);
- QAndroidJniObject adapter;
- QAndroidJniObject socketObject;
- QAndroidJniObject remoteDevice;
- QAndroidJniObject inputStream;
- QAndroidJniObject outputStream;
+ QJniObject adapter;
+ QJniObject socketObject;
+ QJniObject remoteDevice;
+ QJniObject inputStream;
+ QJniObject outputStream;
InputStreamThread *inputThread;
public slots:
- void socketConnectSuccess(const QAndroidJniObject &socket);
- void defaultSocketConnectFailed(const QAndroidJniObject & socket,
- const QAndroidJniObject &targetUuid,
+ void socketConnectSuccess(const QJniObject &socket);
+ void defaultSocketConnectFailed(const QJniObject & socket,
+ const QJniObject &targetUuid,
const QBluetoothUuid &qtTargetUuid);
- void fallbackSocketConnectFailed(const QAndroidJniObject &socket,
- const QAndroidJniObject &targetUuid);
+ void fallbackSocketConnectFailed(const QJniObject &socket,
+ const QJniObject &targetUuid);
void inputThreadError(int errorCode);
signals:
diff --git a/src/bluetooth/qbluetoothsocket_bluez.cpp b/src/bluetooth/qbluetoothsocket_bluez.cpp
index 25f07bb3..7e45f299 100644
--- a/src/bluetooth/qbluetoothsocket_bluez.cpp
+++ b/src/bluetooth/qbluetoothsocket_bluez.cpp
@@ -1,49 +1,10 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qbluetoothsocket.h"
#include "qbluetoothsocket_bluez_p.h"
#include "qbluetoothdeviceinfo.h"
-#include "bluez/manager_p.h"
-#include "bluez/adapter_p.h"
-#include "bluez/device_p.h"
#include "bluez/objectmanager_p.h"
#include <QtBluetooth/QBluetoothLocalDevice>
#include "bluez/bluez_data_p.h"
@@ -66,7 +27,7 @@ Q_DECLARE_LOGGING_CATEGORY(QT_BT_BLUEZ)
QBluetoothSocketPrivateBluez::QBluetoothSocketPrivateBluez()
: QBluetoothSocketBasePrivate()
{
- secFlags = QBluetooth::Authorization;
+ secFlags = QBluetooth::Security::Authorization;
}
QBluetoothSocketPrivateBluez::~QBluetoothSocketPrivateBluez()
@@ -75,6 +36,10 @@ QBluetoothSocketPrivateBluez::~QBluetoothSocketPrivateBluez()
readNotifier = nullptr;
delete connectWriteNotifier;
connectWriteNotifier = nullptr;
+
+ // If the socket wasn't closed/aborted make sure we free the socket file descriptor
+ if (socket != -1)
+ QT_CLOSE(socket);
}
bool QBluetoothSocketPrivateBluez::ensureNativeSocket(QBluetoothServiceInfo::Protocol type)
@@ -111,9 +76,9 @@ bool QBluetoothSocketPrivateBluez::ensureNativeSocket(QBluetoothServiceInfo::Pro
Q_Q(QBluetoothSocket);
readNotifier = new QSocketNotifier(socket, QSocketNotifier::Read);
- QObject::connect(readNotifier, SIGNAL(activated(int)), this, SLOT(_q_readNotify()));
+ QObject::connect(readNotifier, SIGNAL(activated(QSocketDescriptor)), this, SLOT(_q_readNotify()));
connectWriteNotifier = new QSocketNotifier(socket, QSocketNotifier::Write, q);
- QObject::connect(connectWriteNotifier, SIGNAL(activated(int)), this, SLOT(_q_writeNotify()));
+ QObject::connect(connectWriteNotifier, SIGNAL(activated(QSocketDescriptor)), this, SLOT(_q_writeNotify()));
connectWriteNotifier->setEnabled(false);
readNotifier->setEnabled(false);
@@ -129,20 +94,20 @@ void QBluetoothSocketPrivateBluez::connectToServiceHelper(const QBluetoothAddres
if (socket == -1 && !ensureNativeSocket(socketType)) {
errorString = QBluetoothSocket::tr("Unknown socket error");
- q->setSocketError(QBluetoothSocket::UnknownSocketError);
+ q->setSocketError(QBluetoothSocket::SocketError::UnknownSocketError);
return;
}
// apply preferred security level
- // ignore QBluetooth::Authentication -> not used anymore by kernel
+ // ignore QBluetooth::Security::Authentication -> not used anymore by kernel
struct bt_security security;
memset(&security, 0, sizeof(security));
- if (secFlags & QBluetooth::Authorization)
+ if (secFlags & QBluetooth::Security::Authorization)
security.level = BT_SECURITY_LOW;
- if (secFlags & QBluetooth::Encryption)
+ if (secFlags & QBluetooth::Security::Encryption)
security.level = BT_SECURITY_MEDIUM;
- if (secFlags & QBluetooth::Secure)
+ if (secFlags & QBluetooth::Security::Secure)
security.level = BT_SECURITY_HIGH;
if (setsockopt(socket, SOL_BLUETOOTH, BT_SECURITY,
@@ -150,7 +115,7 @@ void QBluetoothSocketPrivateBluez::connectToServiceHelper(const QBluetoothAddres
qCWarning(QT_BT_BLUEZ) << "Failed to set socket option, closing socket for safety" << errno;
qCWarning(QT_BT_BLUEZ) << "Error: " << qt_error_string(errno);
errorString = QBluetoothSocket::tr("Cannot set connection security level");
- q->setSocketError(QBluetoothSocket::UnknownSocketError);
+ q->setSocketError(QBluetoothSocket::SocketError::UnknownSocketError);
return;
}
@@ -199,11 +164,11 @@ void QBluetoothSocketPrivateBluez::connectToServiceHelper(const QBluetoothAddres
if (result >= 0 || (result == -1 && errno == EINPROGRESS)) {
connecting = true;
- q->setSocketState(QBluetoothSocket::ConnectingState);
+ q->setSocketState(QBluetoothSocket::SocketState::ConnectingState);
q->setOpenMode(openMode);
} else {
errorString = qt_error_string(errno);
- q->setSocketError(QBluetoothSocket::UnknownSocketError);
+ q->setSocketError(QBluetoothSocket::SocketError::UnknownSocketError);
}
}
@@ -212,11 +177,11 @@ void QBluetoothSocketPrivateBluez::connectToService(
{
Q_Q(QBluetoothSocket);
- if (q->state() != QBluetoothSocket::UnconnectedState
- && q->state() != QBluetoothSocket::ServiceLookupState) {
+ if (q->state() != QBluetoothSocket::SocketState::UnconnectedState
+ && q->state() != QBluetoothSocket::SocketState::ServiceLookupState) {
qCWarning(QT_BT_BLUEZ) << "QBluetoothSocketPrivateBluez::connectToService called on busy socket";
errorString = QBluetoothSocket::tr("Trying to connect while connection is in progress");
- q->setSocketError(QBluetoothSocket::OperationError);
+ q->setSocketError(QBluetoothSocket::SocketError::OperationError);
return;
}
@@ -226,7 +191,7 @@ void QBluetoothSocketPrivateBluez::connectToService(
qCWarning(QT_BT_BLUEZ) << "QBluetoothSocket::connectToService cannot "
"connect with 'UnknownProtocol' (type provided by given service)";
errorString = QBluetoothSocket::tr("Socket type not supported");
- q->setSocketError(QBluetoothSocket::UnsupportedProtocolError);
+ q->setSocketError(QBluetoothSocket::SocketError::UnsupportedProtocolError);
return;
}
@@ -235,7 +200,7 @@ void QBluetoothSocketPrivateBluez::connectToService(
if (!ensureNativeSocket(QBluetoothServiceInfo::L2capProtocol)) {
errorString = QBluetoothSocket::tr("Unknown socket error");
- q->setSocketError(QBluetoothSocket::UnknownSocketError);
+ q->setSocketError(QBluetoothSocket::SocketError::UnknownSocketError);
return;
}
connectToServiceHelper(service.device().address(), service.protocolServiceMultiplexer(),
@@ -245,14 +210,14 @@ void QBluetoothSocketPrivateBluez::connectToService(
if (!ensureNativeSocket(QBluetoothServiceInfo::RfcommProtocol)) {
errorString = QBluetoothSocket::tr("Unknown socket error");
- q->setSocketError(QBluetoothSocket::UnknownSocketError);
+ q->setSocketError(QBluetoothSocket::SocketError::UnknownSocketError);
return;
}
connectToServiceHelper(service.device().address(), service.serverChannel(), openMode);
} else {
// try doing service discovery to see if we can find the socket
if (service.serviceUuid().isNull()
- && !service.serviceClassUuids().contains(QBluetoothUuid::SerialPort)) {
+ && !service.serviceClassUuids().contains(QBluetoothUuid::ServiceClassUuid::SerialPort)) {
qCWarning(QT_BT_BLUEZ) << "No port, no PSM, and no UUID provided. Unable to connect";
return;
}
@@ -267,10 +232,10 @@ void QBluetoothSocketPrivateBluez::connectToService(
{
Q_Q(QBluetoothSocket);
- if (q->state() != QBluetoothSocket::UnconnectedState) {
+ if (q->state() != QBluetoothSocket::SocketState::UnconnectedState) {
qCWarning(QT_BT_BLUEZ) << "QBluetoothSocketPrivateBluez::connectToService called on busy socket";
errorString = QBluetoothSocket::tr("Trying to connect while connection is in progress");
- q->setSocketError(QBluetoothSocket::OperationError);
+ q->setSocketError(QBluetoothSocket::SocketError::OperationError);
return;
}
@@ -278,7 +243,7 @@ void QBluetoothSocketPrivateBluez::connectToService(
qCWarning(QT_BT_BLUEZ) << "QBluetoothSocketPrivateBluez::connectToService cannot "
"connect with 'UnknownProtocol' (type provided by given service)";
errorString = QBluetoothSocket::tr("Socket type not supported");
- q->setSocketError(QBluetoothSocket::UnsupportedProtocolError);
+ q->setSocketError(QBluetoothSocket::SocketError::UnsupportedProtocolError);
return;
}
@@ -298,14 +263,14 @@ void QBluetoothSocketPrivateBluez::connectToService(
qCWarning(QT_BT_BLUEZ) << "QBluetoothSocketPrivateBluez::connectToService cannot "
"connect with 'UnknownProtocol' (type provided by given service)";
errorString = QBluetoothSocket::tr("Socket type not supported");
- q->setSocketError(QBluetoothSocket::UnsupportedProtocolError);
+ q->setSocketError(QBluetoothSocket::SocketError::UnsupportedProtocolError);
return;
}
- if (q->state() != QBluetoothSocket::UnconnectedState) {
+ if (q->state() != QBluetoothSocket::SocketState::UnconnectedState) {
qCWarning(QT_BT_BLUEZ) << "QBluetoothSocketPrivateBluez::connectToService called on busy socket";
errorString = QBluetoothSocket::tr("Trying to connect while connection is in progress");
- q->setSocketError(QBluetoothSocket::OperationError);
+ q->setSocketError(QBluetoothSocket::SocketError::OperationError);
return;
}
connectToServiceHelper(address, port, openMode);
@@ -314,17 +279,17 @@ void QBluetoothSocketPrivateBluez::connectToService(
void QBluetoothSocketPrivateBluez::_q_writeNotify()
{
Q_Q(QBluetoothSocket);
- if(connecting && state == QBluetoothSocket::ConnectingState){
+ if (connecting && state == QBluetoothSocket::SocketState::ConnectingState){
int errorno, len;
len = sizeof(errorno);
::getsockopt(socket, SOL_SOCKET, SO_ERROR, &errorno, (socklen_t*)&len);
if(errorno) {
errorString = qt_error_string(errorno);
- q->setSocketError(QBluetoothSocket::UnknownSocketError);
+ q->setSocketError(QBluetoothSocket::SocketError::UnknownSocketError);
return;
}
- q->setSocketState(QBluetoothSocket::ConnectedState);
+ q->setSocketState(QBluetoothSocket::SocketState::ConnectedState);
connectWriteNotifier->setEnabled(false);
connecting = false;
@@ -337,18 +302,17 @@ void QBluetoothSocketPrivateBluez::_q_writeNotify()
char buf[1024];
- int size = txBuffer.read(buf, 1024);
- int writtenBytes = qt_safe_write(socket, buf, size);
+ const auto size = txBuffer.read(buf, 1024);
+ const auto writtenBytes = qt_safe_write(socket, buf, size);
if (writtenBytes < 0) {
switch (errno) {
case EAGAIN:
- writtenBytes = 0;
txBuffer.ungetBlock(buf, size);
break;
default:
// every other case returns error
errorString = QBluetoothSocket::tr("Network Error: %1").arg(qt_error_string(errno)) ;
- q->setSocketError(QBluetoothSocket::NetworkError);
+ q->setSocketError(QBluetoothSocket::SocketError::NetworkError);
break;
}
} else {
@@ -364,7 +328,7 @@ void QBluetoothSocketPrivateBluez::_q_writeNotify()
if (txBuffer.size()) {
connectWriteNotifier->setEnabled(true);
}
- else if (state == QBluetoothSocket::ClosingState) {
+ else if (state == QBluetoothSocket::SocketState::ClosingState) {
connectWriteNotifier->setEnabled(false);
this->close();
}
@@ -374,10 +338,10 @@ void QBluetoothSocketPrivateBluez::_q_writeNotify()
void QBluetoothSocketPrivateBluez::_q_readNotify()
{
Q_Q(QBluetoothSocket);
- char *writePointer = buffer.reserve(QPRIVATELINEARBUFFER_BUFFERSIZE);
+ char *writePointer = rxBuffer.reserve(QPRIVATELINEARBUFFER_BUFFERSIZE);
// qint64 readFromDevice = q->readData(writePointer, QPRIVATELINEARBUFFER_BUFFERSIZE);
- int readFromDevice = ::read(socket, writePointer, QPRIVATELINEARBUFFER_BUFFERSIZE);
- buffer.chop(QPRIVATELINEARBUFFER_BUFFERSIZE - (readFromDevice < 0 ? 0 : readFromDevice));
+ const auto readFromDevice = ::read(socket, writePointer, QPRIVATELINEARBUFFER_BUFFERSIZE);
+ rxBuffer.chop(QPRIVATELINEARBUFFER_BUFFERSIZE - (readFromDevice < 0 ? 0 : readFromDevice));
if(readFromDevice <= 0){
int errsv = errno;
readNotifier->setEnabled(false);
@@ -385,11 +349,11 @@ void QBluetoothSocketPrivateBluez::_q_readNotify()
errorString = qt_error_string(errsv);
qCWarning(QT_BT_BLUEZ) << Q_FUNC_INFO << socket << "error:" << readFromDevice << errorString;
if (errsv == EHOSTDOWN)
- q->setSocketError(QBluetoothSocket::HostNotFoundError);
+ q->setSocketError(QBluetoothSocket::SocketError::HostNotFoundError);
else if (errsv == ECONNRESET)
- q->setSocketError(QBluetoothSocket::RemoteHostClosedError);
+ q->setSocketError(QBluetoothSocket::SocketError::RemoteHostClosedError);
else
- q->setSocketError(QBluetoothSocket::UnknownSocketError);
+ q->setSocketError(QBluetoothSocket::SocketError::UnknownSocketError);
q->disconnectFromService();
}
@@ -414,9 +378,8 @@ void QBluetoothSocketPrivateBluez::abort()
Q_Q(QBluetoothSocket);
q->setOpenMode(QIODevice::NotOpen);
- q->setSocketState(QBluetoothSocket::UnconnectedState);
+ q->setSocketState(QBluetoothSocket::SocketState::UnconnectedState);
emit q->readChannelFinished();
- emit q->disconnected();
}
QString QBluetoothSocketPrivateBluez::localName() const
@@ -493,66 +456,32 @@ QString QBluetoothSocketPrivateBluez::peerName() const
}
const QString peerAddress = QBluetoothAddress(bdaddr).toString();
- const QString localAdapter = localAddress().toString();
-
- if (isBluez5()) {
- OrgFreedesktopDBusObjectManagerInterface manager(QStringLiteral("org.bluez"),
- QStringLiteral("/"),
- QDBusConnection::systemBus());
- QDBusPendingReply<ManagedObjectList> reply = manager.GetManagedObjects();
- reply.waitForFinished();
- if (reply.isError())
- return QString();
-
- ManagedObjectList managedObjectList = reply.value();
- for (ManagedObjectList::const_iterator it = managedObjectList.constBegin(); it != managedObjectList.constEnd(); ++it) {
- const InterfaceList &ifaceList = it.value();
- for (InterfaceList::const_iterator jt = ifaceList.constBegin(); jt != ifaceList.constEnd(); ++jt) {
- const QString &iface = jt.key();
- const QVariantMap &ifaceValues = jt.value();
-
- if (iface == QStringLiteral("org.bluez.Device1")) {
- if (ifaceValues.value(QStringLiteral("Address")).toString() == peerAddress)
- return ifaceValues.value(QStringLiteral("Alias")).toString();
- }
- }
- }
+ initializeBluez5();
+ OrgFreedesktopDBusObjectManagerInterface manager(
+ QStringLiteral("org.bluez"), QStringLiteral("/"), QDBusConnection::systemBus());
+ QDBusPendingReply<ManagedObjectList> reply = manager.GetManagedObjects();
+ reply.waitForFinished();
+ if (reply.isError())
return QString();
- } else {
- OrgBluezManagerInterface manager(QStringLiteral("org.bluez"), QStringLiteral("/"),
- QDBusConnection::systemBus());
-
- QDBusPendingReply<QDBusObjectPath> reply = manager.FindAdapter(localAdapter);
- reply.waitForFinished();
- if (reply.isError())
- return QString();
- OrgBluezAdapterInterface adapter(QStringLiteral("org.bluez"), reply.value().path(),
- QDBusConnection::systemBus());
+ ManagedObjectList managedObjectList = reply.value();
+ for (ManagedObjectList::const_iterator it = managedObjectList.constBegin();
+ it != managedObjectList.constEnd(); ++it) {
+ const InterfaceList &ifaceList = it.value();
- QDBusPendingReply<QDBusObjectPath> deviceObjectPath = adapter.FindDevice(peerAddress);
- deviceObjectPath.waitForFinished();
- if (deviceObjectPath.isError()) {
- if (deviceObjectPath.error().name() != QStringLiteral("org.bluez.Error.DoesNotExist"))
- return QString();
+ for (InterfaceList::const_iterator jt = ifaceList.constBegin(); jt != ifaceList.constEnd();
+ ++jt) {
+ const QString &iface = jt.key();
+ const QVariantMap &ifaceValues = jt.value();
- deviceObjectPath = adapter.CreateDevice(peerAddress);
- deviceObjectPath.waitForFinished();
- if (deviceObjectPath.isError())
- return QString();
+ if (iface == QStringLiteral("org.bluez.Device1")) {
+ if (ifaceValues.value(QStringLiteral("Address")).toString() == peerAddress)
+ return ifaceValues.value(QStringLiteral("Alias")).toString();
+ }
}
-
- OrgBluezDeviceInterface device(QStringLiteral("org.bluez"), deviceObjectPath.value().path(),
- QDBusConnection::systemBus());
-
- QDBusPendingReply<QVariantMap> properties = device.GetProperties();
- properties.waitForFinished();
- if (properties.isError())
- return QString();
-
- return properties.value().value(QStringLiteral("Alias")).toString();
}
+ return QString();
}
QBluetoothAddress QBluetoothSocketPrivateBluez::peerAddress() const
@@ -597,14 +526,14 @@ qint64 QBluetoothSocketPrivateBluez::writeData(const char *data, qint64 maxSize)
{
Q_Q(QBluetoothSocket);
- if (state != QBluetoothSocket::ConnectedState) {
+ if (state != QBluetoothSocket::SocketState::ConnectedState) {
errorString = QBluetoothSocket::tr("Cannot write while not connected");
- q->setSocketError(QBluetoothSocket::OperationError);
+ q->setSocketError(QBluetoothSocket::SocketError::OperationError);
return -1;
}
if (q->openMode() & QIODevice::Unbuffered) {
- int sz = ::qt_safe_write(socket, data, maxSize);
+ auto sz = ::qt_safe_write(socket, data, maxSize);
if (sz < 0) {
switch (errno) {
case EAGAIN:
@@ -612,7 +541,7 @@ qint64 QBluetoothSocketPrivateBluez::writeData(const char *data, qint64 maxSize)
break;
default:
errorString = QBluetoothSocket::tr("Network Error: %1").arg(qt_error_string(errno));
- q->setSocketError(QBluetoothSocket::NetworkError);
+ q->setSocketError(QBluetoothSocket::SocketError::NetworkError);
}
}
@@ -642,22 +571,22 @@ qint64 QBluetoothSocketPrivateBluez::readData(char *data, qint64 maxSize)
{
Q_Q(QBluetoothSocket);
- if (state != QBluetoothSocket::ConnectedState) {
+ if (state != QBluetoothSocket::SocketState::ConnectedState) {
errorString = QBluetoothSocket::tr("Cannot read while not connected");
- q->setSocketError(QBluetoothSocket::OperationError);
+ q->setSocketError(QBluetoothSocket::SocketError::OperationError);
return -1;
}
- if (!buffer.isEmpty()) {
- int i = buffer.read(data, maxSize);
- return i;
- }
+ if (!rxBuffer.isEmpty())
+ return rxBuffer.read(data, maxSize);
return 0;
}
void QBluetoothSocketPrivateBluez::close()
{
+ // If we have pending data on the write buffer, wait until it has been written,
+ // after which this close() will be called again
if (txBuffer.size() > 0)
connectWriteNotifier->setEnabled(true);
else
@@ -685,19 +614,19 @@ bool QBluetoothSocketPrivateBluez::setSocketDescriptor(int socketDescriptor, QBl
fcntl(socket, F_SETFL, flags | O_NONBLOCK);
readNotifier = new QSocketNotifier(socket, QSocketNotifier::Read);
- QObject::connect(readNotifier, SIGNAL(activated(int)), this, SLOT(_q_readNotify()));
+ QObject::connect(readNotifier, SIGNAL(activated(QSocketDescriptor)), this, SLOT(_q_readNotify()));
connectWriteNotifier = new QSocketNotifier(socket, QSocketNotifier::Write, q);
- QObject::connect(connectWriteNotifier, SIGNAL(activated(int)), this, SLOT(_q_writeNotify()));
+ QObject::connect(connectWriteNotifier, SIGNAL(activated(QSocketDescriptor)), this, SLOT(_q_writeNotify()));
- q->setSocketState(socketState);
q->setOpenMode(openMode);
+ q->setSocketState(socketState);
return true;
}
qint64 QBluetoothSocketPrivateBluez::bytesAvailable() const
{
- return buffer.size();
+ return rxBuffer.size();
}
qint64 QBluetoothSocketPrivateBluez::bytesToWrite() const
@@ -707,7 +636,9 @@ qint64 QBluetoothSocketPrivateBluez::bytesToWrite() const
bool QBluetoothSocketPrivateBluez::canReadLine() const
{
- return buffer.canReadLine();
+ return rxBuffer.canReadLine();
}
QT_END_NAMESPACE
+
+#include "moc_qbluetoothsocket_bluez_p.cpp"
diff --git a/src/bluetooth/qbluetoothsocket_bluez_p.h b/src/bluetooth/qbluetoothsocket_bluez_p.h
index 67c04b3d..4f679b77 100644
--- a/src/bluetooth/qbluetoothsocket_bluez_p.h
+++ b/src/bluetooth/qbluetoothsocket_bluez_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QBLUETOOTHSOCKET_BLUEZ_H
#define QBLUETOOTHSOCKET_BLUEZ_H
@@ -91,7 +55,7 @@ public:
qint64 readData(char *data, qint64 maxSize) override;
bool setSocketDescriptor(int socketDescriptor, QBluetoothServiceInfo::Protocol socketType,
- QBluetoothSocket::SocketState socketState = QBluetoothSocket::ConnectedState,
+ QBluetoothSocket::SocketState socketState = QBluetoothSocket::SocketState::ConnectedState,
QBluetoothSocket::OpenMode openMode = QBluetoothSocket::ReadWrite) override;
qint64 bytesAvailable() const override;
diff --git a/src/bluetooth/qbluetoothsocket_bluezdbus.cpp b/src/bluetooth/qbluetoothsocket_bluezdbus.cpp
index d3fc13e4..8006a457 100644
--- a/src/bluetooth/qbluetoothsocket_bluezdbus.cpp
+++ b/src/bluetooth/qbluetoothsocket_bluezdbus.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qbluetoothsocket.h"
#include "qbluetoothsocket_bluezdbus_p.h"
@@ -61,19 +25,13 @@
QT_BEGIN_NAMESPACE
-Q_DECLARE_LOGGING_CATEGORY(QT_BT_BLUEZ)
+using namespace Qt::StringLiterals;
-static const QLatin1String profilePathTemplate("/qt/btsocket/%1%2/%3");
+Q_DECLARE_LOGGING_CATEGORY(QT_BT_BLUEZ)
QBluetoothSocketPrivateBluezDBus::QBluetoothSocketPrivateBluezDBus()
{
- secFlags = QBluetooth::NoSecurity;
-
- profileManager = new OrgBluezProfileManager1Interface(
- QStringLiteral("org.bluez"),
- QStringLiteral("/org/bluez"),
- QDBusConnection::systemBus(),
- this);
+ secFlags = QBluetooth::Security::NoSecurity;
}
QBluetoothSocketPrivateBluezDBus::~QBluetoothSocketPrivateBluezDBus()
@@ -120,8 +78,6 @@ static QString findRemoteDevicePath(const QBluetoothAddress &address)
if (reply.isError())
return QString();
- QString remoteDevicePath;
-
ManagedObjectList objectList = reply.value();
for (ManagedObjectList::const_iterator it = objectList.constBegin();
it != objectList.constEnd(); ++it) {
@@ -161,9 +117,17 @@ void QBluetoothSocketPrivateBluezDBus::connectToServiceHelper(
bool success = false;
profileUuid = uuid.toString(QUuid::WithoutBraces);
+ if (!profileManager) {
+ profileManager = new OrgBluezProfileManager1Interface(
+ QStringLiteral("org.bluez"),
+ QStringLiteral("/org/bluez"),
+ QDBusConnection::systemBus(),
+ this);
+ }
+
if (profileContext) {
qCDebug(QT_BT_BLUEZ) << "Profile context still active. close socket first.";
- q->setSocketError(QBluetoothSocket::UnknownSocketError);
+ q->setSocketError(QBluetoothSocket::SocketError::UnknownSocketError);
return;
}
@@ -176,7 +140,7 @@ void QBluetoothSocketPrivateBluezDBus::connectToServiceHelper(
// profile registration might fail in case other service uses same path
// try 10 times and otherwise abort
- profilePath = QString(profilePathTemplate).
+ profilePath = u"/qt/btsocket/%1%2/%3"_s.
arg(sanitizeNameForDBus(QCoreApplication::applicationName())).
arg(QCoreApplication::applicationPid()).
arg(QRandomGenerator::global()->generate());
@@ -193,7 +157,7 @@ void QBluetoothSocketPrivateBluezDBus::connectToServiceHelper(
profileContext = nullptr;
errorString = QBluetoothSocket::tr("Cannot export profile on DBus");
- q->setSocketError(QBluetoothSocket::UnknownSocketError);
+ q->setSocketError(QBluetoothSocket::SocketError::UnknownSocketError);
return;
}
@@ -220,7 +184,7 @@ void QBluetoothSocketPrivateBluezDBus::connectToServiceHelper(
QDBusConnection::systemBus().unregisterObject(profilePath);
errorString = QBluetoothSocket::tr("Cannot register profile on DBus");
- q->setSocketError(QBluetoothSocket::UnknownSocketError);
+ q->setSocketError(QBluetoothSocket::SocketError::UnknownSocketError);
return;
}
@@ -231,25 +195,53 @@ void QBluetoothSocketPrivateBluezDBus::connectToServiceHelper(
clearSocket();
errorString = QBluetoothSocket::tr("Cannot find remote device");
- q->setSocketError(QBluetoothSocket::HostNotFoundError);
+ q->setSocketError(QBluetoothSocket::SocketError::HostNotFoundError);
return;
}
OrgBluezDevice1Interface device(QStringLiteral("org.bluez"), remoteDevicePath,
QDBusConnection::systemBus());
reply = device.ConnectProfile(profileUuid);
+ QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this);
+ connect(watcher, &QDBusPendingCallWatcher::finished,
+ this, &QBluetoothSocketPrivateBluezDBus::connectToServiceReplyHandler);
+
+ q->setOpenMode(openMode);
+ q->setSocketState(QBluetoothSocket::SocketState::ConnectingState);
+}
+
+void QBluetoothSocketPrivateBluezDBus::connectToServiceReplyHandler(
+ QDBusPendingCallWatcher *watcher)
+{
+ Q_Q(QBluetoothSocket);
+
+ QDBusPendingReply<> reply = *watcher;
if (reply.isError()) {
- qCWarning(QT_BT_BLUEZ) << "Cannot connect to profile/service:" << uuid;
+ qCWarning(QT_BT_BLUEZ) << "Cannot connect to profile/service.";
clearSocket();
errorString = QBluetoothSocket::tr("Cannot connect to remote profile");
- q->setSocketError(QBluetoothSocket::HostNotFoundError);
- return;
+ q->setSocketError(QBluetoothSocket::SocketError::HostNotFoundError);
}
+ watcher->deleteLater();
- q->setOpenMode(openMode);
- q->setSocketState(QBluetoothSocket::ConnectingState);
+ // QTBUG-82413, unregisterProfile at profileUuid,
+ // so it can be registered for new devices connecting to the same profile UUID.
+ if (profileManager) {
+ qCDebug(QT_BT_BLUEZ) << "Unregistering client profile on" << profilePath
+ << "in connectToServiceReplyHandler() callback.";
+
+ QDBusPendingReply<> reply = profileManager->UnregisterProfile(QDBusObjectPath(profilePath));
+ reply.waitForFinished();
+ if (reply.isError())
+ qCWarning(QT_BT_BLUEZ) << "Unregister profile:" << reply.error().message();
+
+ QDBusConnection::systemBus().unregisterObject(profilePath);
+
+ delete profileManager;
+ profileManager = nullptr;
+ }
}
void QBluetoothSocketPrivateBluezDBus::connectToService(
@@ -261,18 +253,22 @@ void QBluetoothSocketPrivateBluezDBus::connectToService(
targetService = service.serviceUuid();
if (targetService.isNull()) {
// Do we have serialport service class?
- if (service.serviceClassUuids().contains(QBluetoothUuid::SerialPort))
- targetService = QBluetoothUuid::SerialPort;
+ if (service.serviceClassUuids().contains(QBluetoothUuid::ServiceClassUuid::SerialPort))
+ targetService = QBluetoothUuid::ServiceClassUuid::SerialPort;
}
if (targetService.isNull()) {
qCWarning(QT_BT_BLUEZ) << "Cannot find appropriate serviceUuid"
<< "or SerialPort service class uuid";
errorString = QBluetoothSocket::tr("Missing serviceUuid or Serial Port service class uuid");
- q->setSocketError(QBluetoothSocket::OperationError);
+ q->setSocketError(QBluetoothSocket::SocketError::UnsupportedProtocolError);
return;
}
+ if (service.socketProtocol() != QBluetoothServiceInfo::Protocol::UnknownProtocol)
+ socketType = service.socketProtocol();
+ qCDebug(QT_BT_BLUEZ) << "Socket protocol used:" << socketType;
+
connectToService(service.device().address(), targetService, openMode);
}
@@ -284,7 +280,7 @@ void QBluetoothSocketPrivateBluezDBus::connectToService(
if (address.isNull()) {
qCWarning(QT_BT_BLUEZ) << "Invalid address to remote address passed.";
errorString = QBluetoothSocket::tr("Invalid Bluetooth address passed to connectToService()");
- q->setSocketError(QBluetoothSocket::OperationError);
+ q->setSocketError(QBluetoothSocket::SocketError::UnsupportedProtocolError);
return;
}
@@ -292,14 +288,14 @@ void QBluetoothSocketPrivateBluezDBus::connectToService(
qCWarning(QT_BT_BLUEZ) << "Cannot find appropriate serviceUuid"
<< "or SerialPort service class uuid";
errorString = QBluetoothSocket::tr("Missing serviceUuid or Serial Port service class uuid");
- q->setSocketError(QBluetoothSocket::OperationError);
+ q->setSocketError(QBluetoothSocket::SocketError::UnsupportedProtocolError);
return;
}
- if (q->state() != QBluetoothSocket::UnconnectedState) {
+ if (q->state() != QBluetoothSocket::SocketState::UnconnectedState) {
qCWarning(QT_BT_BLUEZ) << "QBluetoothSocketPrivateBluezDBus::connectToService called on busy socket";
errorString = QBluetoothSocket::tr("Trying to connect while connection is in progress");
- q->setSocketError(QBluetoothSocket::OperationError);
+ q->setSocketError(QBluetoothSocket::SocketError::OperationError);
return;
}
@@ -307,13 +303,13 @@ void QBluetoothSocketPrivateBluezDBus::connectToService(
qCWarning(QT_BT_BLUEZ) << "QBluetoothSocketPrivateBluezDBus::connectToService cannot "
"connect with 'UnknownProtocol' (type provided by given service)";
errorString = QBluetoothSocket::tr("Socket type not supported");
- q->setSocketError(QBluetoothSocket::UnsupportedProtocolError);
+ q->setSocketError(QBluetoothSocket::SocketError::UnsupportedProtocolError);
return;
}
if (!ensureNativeSocket(q->socketType())) {
errorString = QBluetoothSocket::tr("Socket type not supported");
- q->setSocketError(QBluetoothSocket::UnsupportedProtocolError);
+ q->setSocketError(QBluetoothSocket::SocketError::UnsupportedProtocolError);
return;
}
connectToServiceHelper(address, uuid, openMode);
@@ -329,7 +325,7 @@ void QBluetoothSocketPrivateBluezDBus::connectToService(
Q_Q(QBluetoothSocket);
errorString = tr("Connecting to port is not supported via Bluez DBus");
- q->setSocketError(QBluetoothSocket::ServiceNotFoundError);
+ q->setSocketError(QBluetoothSocket::SocketError::ServiceNotFoundError);
qCWarning(QT_BT_BLUEZ) << "Connecting to port is not supported (Uuid required)";
}
@@ -343,7 +339,7 @@ void QBluetoothSocketPrivateBluezDBus::abort()
clearSocket();
q->setOpenMode(QIODevice::NotOpen);
- q->setSocketState(QBluetoothSocket::UnconnectedState);
+ q->setSocketState(QBluetoothSocket::SocketState::UnconnectedState);
emit q->readChannelFinished();
}
}
@@ -451,9 +447,9 @@ qint64 QBluetoothSocketPrivateBluezDBus::writeData(const char *data, qint64 maxS
Q_Q(QBluetoothSocket);
- if (state != QBluetoothSocket::ConnectedState) {
+ if (state != QBluetoothSocket::SocketState::ConnectedState) {
errorString = QBluetoothSocket::tr("Cannot write while not connected");
- q->setSocketError(QBluetoothSocket::OperationError);
+ q->setSocketError(QBluetoothSocket::SocketError::OperationError);
return -1;
}
@@ -470,9 +466,9 @@ qint64 QBluetoothSocketPrivateBluezDBus::readData(char *data, qint64 maxSize)
Q_Q(QBluetoothSocket);
- if (state != QBluetoothSocket::ConnectedState) {
+ if (state != QBluetoothSocket::SocketState::ConnectedState) {
errorString = QBluetoothSocket::tr("Cannot read while not connected");
- q->setSocketError(QBluetoothSocket::OperationError);
+ q->setSocketError(QBluetoothSocket::SocketError::OperationError);
return -1;
}
@@ -491,7 +487,7 @@ bool QBluetoothSocketPrivateBluezDBus::setSocketDescriptor(int socketDescriptor,
QBluetoothSocket::SocketState socketState, QBluetoothSocket::OpenMode openMode)
{
Q_UNUSED(socketDescriptor);
- Q_UNUSED(socketType)
+ Q_UNUSED(socketType);
Q_UNUSED(socketState);
Q_UNUSED(openMode);
return false;
@@ -530,7 +526,7 @@ void QBluetoothSocketPrivateBluezDBus::remoteConnected(const QDBusUnixFileDescri
bool success = localSocket->setSocketDescriptor(
descriptor, QLocalSocket::ConnectedState, q->openMode());
if (!success || !localSocket->isValid()) {
- q->setSocketState(QBluetoothSocket::UnconnectedState);
+ q->setSocketState(QBluetoothSocket::SocketState::UnconnectedState);
delete localSocket;
localSocket = nullptr;
} else {
@@ -542,7 +538,7 @@ void QBluetoothSocketPrivateBluezDBus::remoteConnected(const QDBusUnixFileDescri
q, &QBluetoothSocket::bytesWritten);
socket = descriptor;
- q->setSocketState(QBluetoothSocket::ConnectedState);
+ q->setSocketState(QBluetoothSocket::SocketState::ConnectedState);
}
}
@@ -552,12 +548,12 @@ void QBluetoothSocketPrivateBluezDBus::socketStateChanged(QLocalSocket::LocalSoc
switch (newState) {
case QLocalSocket::ClosingState:
- q->setSocketState(QBluetoothSocket::ClosingState);
+ q->setSocketState(QBluetoothSocket::SocketState::ClosingState);
break;
case QLocalSocket::UnconnectedState:
clearSocket();
q->setOpenMode(QIODevice::NotOpen);
- q->setSocketState(QBluetoothSocket::UnconnectedState);
+ q->setSocketState(QBluetoothSocket::SocketState::UnconnectedState);
emit q->readChannelFinished();
break;
default:
@@ -584,7 +580,7 @@ void QBluetoothSocketPrivateBluezDBus::clearSocket()
socket = -1;
- if (q->state() == QBluetoothSocket::ConnectedState) {
+ if (q->state() == QBluetoothSocket::SocketState::ConnectedState) {
OrgBluezDevice1Interface device(QStringLiteral("org.bluez"), remoteDevicePath,
QDBusConnection::systemBus());
auto reply = device.DisconnectProfile(profileUuid);
@@ -595,20 +591,30 @@ void QBluetoothSocketPrivateBluezDBus::clearSocket()
}
}
- QDBusPendingReply<> reply = profileManager->UnregisterProfile(QDBusObjectPath(profilePath));
- reply.waitForFinished();
- if (reply.isError())
- qCWarning(QT_BT_BLUEZ) << "Unregister profile:" << reply.error().message();
-
- QDBusConnection::systemBus().unregisterObject(profilePath);
-
if (profileContext) {
delete profileContext;
profileContext = nullptr;
}
+ if (profileManager) {
+ qCDebug(QT_BT_BLUEZ) << "Unregistering client profile on" << profilePath
+ << "in clearSocket().";
+
+ QDBusPendingReply<> reply = profileManager->UnregisterProfile(QDBusObjectPath(profilePath));
+ reply.waitForFinished();
+ if (reply.isError())
+ qCWarning(QT_BT_BLUEZ) << "Unregister profile:" << reply.error().message();
+
+ QDBusConnection::systemBus().unregisterObject(profilePath);
+
+ delete profileManager;
+ profileManager = nullptr;
+ }
+
remoteDevicePath.clear();
profileUuid.clear();
profilePath.clear();
}
QT_END_NAMESPACE
+
+#include "moc_qbluetoothsocket_bluezdbus_p.cpp"
diff --git a/src/bluetooth/qbluetoothsocket_bluezdbus_p.h b/src/bluetooth/qbluetoothsocket_bluezdbus_p.h
index 4d1a272e..ad2191fb 100644
--- a/src/bluetooth/qbluetoothsocket_bluezdbus_p.h
+++ b/src/bluetooth/qbluetoothsocket_bluezdbus_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QBLUETOOTHSOCKET_BLUEZDBUS_H
#define QBLUETOOTHSOCKET_BLUEZDBUS_H
@@ -56,6 +20,7 @@
#include <QtDBus/qdbusunixfiledescriptor.h>
#include <QtNetwork/qlocalsocket.h>
+#include <QDBusPendingCallWatcher>
class OrgBluezProfileManager1Interface;
@@ -103,13 +68,16 @@ public:
qint64 readData(char *data, qint64 maxSize) override;
bool setSocketDescriptor(int socketDescriptor, QBluetoothServiceInfo::Protocol socketType,
- QBluetoothSocket::SocketState socketState = QBluetoothSocket::ConnectedState,
+ QBluetoothSocket::SocketState socketState = QBluetoothSocket::SocketState::ConnectedState,
QBluetoothSocket::OpenMode openMode = QBluetoothSocket::ReadWrite) override;
qint64 bytesAvailable() const override;
bool canReadLine() const override;
qint64 bytesToWrite() const override;
+public slots:
+ void connectToServiceReplyHandler(QDBusPendingCallWatcher *);
+
private:
void remoteConnected(const QDBusUnixFileDescriptor &fd);
void socketStateChanged(QLocalSocket::LocalSocketState newState);
diff --git a/src/bluetooth/qbluetoothsocket_dummy.cpp b/src/bluetooth/qbluetoothsocket_dummy.cpp
index 82da46c2..efe670b0 100644
--- a/src/bluetooth/qbluetoothsocket_dummy.cpp
+++ b/src/bluetooth/qbluetoothsocket_dummy.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qbluetoothsocket.h"
#include "qbluetoothsocket_dummy_p.h"
@@ -47,7 +11,7 @@ QT_BEGIN_NAMESPACE
QBluetoothSocketPrivateDummy::QBluetoothSocketPrivateDummy()
{
- secFlags = QBluetooth::NoSecurity;
+ secFlags = QBluetooth::Security::NoSecurity;
#ifndef QT_IOS_BLUETOOTH
printDummyWarning();
#endif
@@ -80,7 +44,7 @@ void QBluetoothSocketPrivateDummy::connectToService(
qWarning() << "Using non-functional QBluetoothSocketPrivateDummy";
errorString = QBluetoothSocket::tr("Socket type not supported");
- q->setSocketError(QBluetoothSocket::UnsupportedProtocolError);
+ q->setSocketError(QBluetoothSocket::SocketError::UnsupportedProtocolError);
}
void QBluetoothSocketPrivateDummy::connectToService(
@@ -94,7 +58,7 @@ void QBluetoothSocketPrivateDummy::connectToService(
qWarning() << "Using non-functional QBluetoothSocketPrivateDummy";
errorString = QBluetoothSocket::tr("Socket type not supported");
- q->setSocketError(QBluetoothSocket::UnsupportedProtocolError);
+ q->setSocketError(QBluetoothSocket::SocketError::UnsupportedProtocolError);
}
void QBluetoothSocketPrivateDummy::connectToService(
@@ -108,7 +72,7 @@ void QBluetoothSocketPrivateDummy::connectToService(
qWarning() << "Using non-functional QBluetoothSocketPrivateDummy";
errorString = QBluetoothSocket::tr("Socket type not supported");
- q->setSocketError(QBluetoothSocket::UnsupportedProtocolError);
+ q->setSocketError(QBluetoothSocket::SocketError::UnsupportedProtocolError);
}
void QBluetoothSocketPrivateDummy::abort()
@@ -152,9 +116,9 @@ qint64 QBluetoothSocketPrivateDummy::writeData(const char *data, qint64 maxSize)
Q_Q(QBluetoothSocket);
- if (state != QBluetoothSocket::ConnectedState) {
+ if (state != QBluetoothSocket::SocketState::ConnectedState) {
errorString = QBluetoothSocket::tr("Cannot write while not connected");
- q->setSocketError(QBluetoothSocket::OperationError);
+ q->setSocketError(QBluetoothSocket::SocketError::OperationError);
return -1;
}
return -1;
@@ -167,9 +131,9 @@ qint64 QBluetoothSocketPrivateDummy::readData(char *data, qint64 maxSize)
Q_Q(QBluetoothSocket);
- if (state != QBluetoothSocket::ConnectedState) {
+ if (state != QBluetoothSocket::SocketState::ConnectedState) {
errorString = QBluetoothSocket::tr("Cannot read while not connected");
- q->setSocketError(QBluetoothSocket::OperationError);
+ q->setSocketError(QBluetoothSocket::SocketError::OperationError);
return -1;
}
@@ -184,7 +148,7 @@ bool QBluetoothSocketPrivateDummy::setSocketDescriptor(int socketDescriptor, QBl
QBluetoothSocket::SocketState socketState, QBluetoothSocket::OpenMode openMode)
{
Q_UNUSED(socketDescriptor);
- Q_UNUSED(socketType)
+ Q_UNUSED(socketType);
Q_UNUSED(socketState);
Q_UNUSED(openMode);
return false;
diff --git a/src/bluetooth/qbluetoothsocket_dummy_p.h b/src/bluetooth/qbluetoothsocket_dummy_p.h
index 78a2049b..3780441a 100644
--- a/src/bluetooth/qbluetoothsocket_dummy_p.h
+++ b/src/bluetooth/qbluetoothsocket_dummy_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QBLUETOOTHSOCKET_DUMMY_H
#define QBLUETOOTHSOCKET_DUMMY_H
@@ -94,7 +58,7 @@ public:
qint64 readData(char *data, qint64 maxSize) override;
bool setSocketDescriptor(int socketDescriptor, QBluetoothServiceInfo::Protocol socketType,
- QBluetoothSocket::SocketState socketState = QBluetoothSocket::ConnectedState,
+ QBluetoothSocket::SocketState socketState = QBluetoothSocket::SocketState::ConnectedState,
QBluetoothSocket::OpenMode openMode = QBluetoothSocket::ReadWrite) override;
qint64 bytesAvailable() const override;
diff --git a/src/bluetooth/qbluetoothsocket_macos.mm b/src/bluetooth/qbluetoothsocket_macos.mm
index 9c01d0dd..aabf1791 100644
--- a/src/bluetooth/qbluetoothsocket_macos.mm
+++ b/src/bluetooth/qbluetoothsocket_macos.mm
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qbluetoothservicediscoveryagent.h"
// The order is important (the first header contains
@@ -53,6 +17,7 @@
#include "qbluetoothsocket.h"
#include <QtCore/qloggingcategory.h>
+#include <QtCore/qcoreapplication.h>
#include <QtCore/qmetaobject.h>
#include <algorithm>
@@ -63,22 +28,20 @@ QT_BEGIN_NAMESPACE
namespace {
using DarwinBluetooth::RetainPolicy;
-using ObjCL2CAPChannel = QT_MANGLE_NAMESPACE(DarwinBTL2CAPChannel);
-using ObjCRFCOMMChannel = QT_MANGLE_NAMESPACE(DarwinBTRFCOMMChannel);
} // unnamed namespace
-QBluetoothSocketPrivate::QBluetoothSocketPrivate()
+QBluetoothSocketPrivateDarwin::QBluetoothSocketPrivateDarwin()
: writeChunk(std::numeric_limits<UInt16>::max())
{
q_ptr = nullptr;
}
-QBluetoothSocketPrivate::~QBluetoothSocketPrivate()
+QBluetoothSocketPrivateDarwin::~QBluetoothSocketPrivateDarwin()
{
}
-bool QBluetoothSocketPrivate::ensureNativeSocket(QBluetoothServiceInfo::Protocol type)
+bool QBluetoothSocketPrivateDarwin::ensureNativeSocket(QBluetoothServiceInfo::Protocol type)
{
// For now - very simplistic, we don't call it in this file, public class
// only calls it in a ctor, setting the protocol RFCOMM (in case of Android)
@@ -88,34 +51,34 @@ bool QBluetoothSocketPrivate::ensureNativeSocket(QBluetoothServiceInfo::Protocol
return type != QBluetoothServiceInfo::UnknownProtocol;
}
-QString QBluetoothSocketPrivate::localName() const
+QString QBluetoothSocketPrivateDarwin::localName() const
{
const QBluetoothLocalDevice device;
return device.name();
}
-QBluetoothAddress QBluetoothSocketPrivate::localAddress() const
+QBluetoothAddress QBluetoothSocketPrivateDarwin::localAddress() const
{
const QBluetoothLocalDevice device;
return device.address();
}
-quint16 QBluetoothSocketPrivate::localPort() const
+quint16 QBluetoothSocketPrivateDarwin::localPort() const
{
return 0;
}
-QString QBluetoothSocketPrivate::peerName() const
+QString QBluetoothSocketPrivateDarwin::peerName() const
{
QT_BT_MAC_AUTORELEASEPOOL;
NSString *nsName = nil;
if (socketType == QBluetoothServiceInfo::RfcommProtocol) {
if (rfcommChannel)
- nsName = [rfcommChannel.getAs<ObjCRFCOMMChannel>() peerName];
+ nsName = [rfcommChannel.getAs<DarwinBTRFCOMMChannel>() peerName];
} else if (socketType == QBluetoothServiceInfo::L2capProtocol) {
if (l2capChannel)
- nsName = [l2capChannel.getAs<ObjCL2CAPChannel>() peerName];
+ nsName = [l2capChannel.getAs<DarwinBTL2CAPChannel>() peerName];
}
if (nsName)
@@ -124,34 +87,34 @@ QString QBluetoothSocketPrivate::peerName() const
return QString();
}
-QBluetoothAddress QBluetoothSocketPrivate::peerAddress() const
+QBluetoothAddress QBluetoothSocketPrivateDarwin::peerAddress() const
{
BluetoothDeviceAddress addr = {};
if (socketType == QBluetoothServiceInfo::RfcommProtocol) {
if (rfcommChannel)
- addr = [rfcommChannel.getAs<ObjCRFCOMMChannel>() peerAddress];
+ addr = [rfcommChannel.getAs<DarwinBTRFCOMMChannel>() peerAddress];
} else if (socketType == QBluetoothServiceInfo::L2capProtocol) {
if (l2capChannel)
- addr = [l2capChannel.getAs<ObjCL2CAPChannel>() peerAddress];
+ addr = [l2capChannel.getAs<DarwinBTL2CAPChannel>() peerAddress];
}
return DarwinBluetooth::qt_address(&addr);
}
-quint16 QBluetoothSocketPrivate::peerPort() const
+quint16 QBluetoothSocketPrivateDarwin::peerPort() const
{
if (socketType == QBluetoothServiceInfo::RfcommProtocol) {
if (rfcommChannel)
- return [rfcommChannel.getAs<ObjCRFCOMMChannel>() getChannelID];
+ return [rfcommChannel.getAs<DarwinBTRFCOMMChannel>() getChannelID];
} else if (socketType == QBluetoothServiceInfo::L2capProtocol) {
if (l2capChannel)
- return [l2capChannel.getAs<ObjCL2CAPChannel>() getPSM];
+ return [l2capChannel.getAs<DarwinBTL2CAPChannel>() getPSM];
}
return 0;
}
-void QBluetoothSocketPrivate::abort()
+void QBluetoothSocketPrivateDarwin::abort()
{
// Can never be called while we're in connectToService:
Q_ASSERT_X(!isConnecting, Q_FUNC_INFO, "internal inconsistency - "
@@ -164,13 +127,12 @@ void QBluetoothSocketPrivate::abort()
Q_ASSERT(q_ptr);
- q_ptr->setSocketState(QBluetoothSocket::UnconnectedState);
+ q_ptr->setSocketState(QBluetoothSocket::SocketState::UnconnectedState);
emit q_ptr->readChannelFinished();
- emit q_ptr->disconnected();
}
-void QBluetoothSocketPrivate::close()
+void QBluetoothSocketPrivateDarwin::close()
{
// Can never be called while we're in connectToService:
Q_ASSERT_X(!isConnecting, Q_FUNC_INFO, "internal inconsistency - "
@@ -181,14 +143,14 @@ void QBluetoothSocketPrivate::close()
}
-qint64 QBluetoothSocketPrivate::writeData(const char *data, qint64 maxSize)
+qint64 QBluetoothSocketPrivateDarwin::writeData(const char *data, qint64 maxSize)
{
Q_ASSERT_X(data, Q_FUNC_INFO, "invalid data (null)");
Q_ASSERT_X(maxSize > 0, Q_FUNC_INFO, "invalid data size");
- if (state != QBluetoothSocket::ConnectedState) {
+ if (state != QBluetoothSocket::SocketState::ConnectedState) {
errorString = QCoreApplication::translate(SOCKET, SOC_NOWRITE);
- q_ptr->setSocketError(QBluetoothSocket::OperationError);
+ q_ptr->setSocketError(QBluetoothSocket::SocketError::OperationError);
return -1;
}
@@ -204,69 +166,69 @@ qint64 QBluetoothSocketPrivate::writeData(const char *data, qint64 maxSize)
return maxSize;
}
-qint64 QBluetoothSocketPrivate::readData(char *data, qint64 maxSize)
+qint64 QBluetoothSocketPrivateDarwin::readData(char *data, qint64 maxSize)
{
if (!data)
return 0;
- if (state != QBluetoothSocket::ConnectedState) {
+ if (state != QBluetoothSocket::SocketState::ConnectedState) {
errorString = QCoreApplication::translate(SOCKET, SOC_NOREAD);
- q_ptr->setSocketError(QBluetoothSocket::OperationError);
+ q_ptr->setSocketError(QBluetoothSocket::SocketError::OperationError);
return -1;
}
- if (!buffer.isEmpty())
- return buffer.read(data, int(maxSize));
+ if (!rxBuffer.isEmpty())
+ return rxBuffer.read(data, int(maxSize));
return 0;
}
-qint64 QBluetoothSocketPrivate::bytesAvailable() const
+qint64 QBluetoothSocketPrivateDarwin::bytesAvailable() const
{
- return buffer.size();
+ return rxBuffer.size();
}
-bool QBluetoothSocketPrivate::canReadLine() const
+bool QBluetoothSocketPrivateDarwin::canReadLine() const
{
- return buffer.canReadLine();
+ return rxBuffer.canReadLine();
}
-qint64 QBluetoothSocketPrivate::bytesToWrite() const
+qint64 QBluetoothSocketPrivateDarwin::bytesToWrite() const
{
return txBuffer.size();
}
-bool QBluetoothSocketPrivate::setSocketDescriptor(int socketDescriptor, QBluetoothServiceInfo::Protocol socketType,
+bool QBluetoothSocketPrivateDarwin::setSocketDescriptor(int socketDescriptor, QBluetoothServiceInfo::Protocol socketType,
QBluetoothSocket::SocketState socketState, QIODevice::OpenMode openMode)
{
- Q_UNUSED(socketDescriptor)
- Q_UNUSED(socketType)
- Q_UNUSED(socketState)
- Q_UNUSED(openMode)
+ Q_UNUSED(socketDescriptor);
+ Q_UNUSED(socketType);
+ Q_UNUSED(socketState);
+ Q_UNUSED(openMode);
qCWarning(QT_BT_DARWIN) << "setting a socket descriptor is not supported by IOBluetooth";
// Noop on macOS.
- return true;
+ return false;
}
-void QBluetoothSocketPrivate::connectToServiceHelper(const QBluetoothAddress &address, quint16 port,
+void QBluetoothSocketPrivateDarwin::connectToServiceHelper(const QBluetoothAddress &address, quint16 port,
QIODevice::OpenMode openMode)
{
- Q_UNUSED(address)
- Q_UNUSED(port)
- Q_UNUSED(openMode)
+ Q_UNUSED(address);
+ Q_UNUSED(port);
+ Q_UNUSED(openMode);
}
-void QBluetoothSocketPrivate::connectToService(const QBluetoothServiceInfo &service, QIODevice::OpenMode openMode)
+void QBluetoothSocketPrivateDarwin::connectToService(const QBluetoothServiceInfo &service, QIODevice::OpenMode openMode)
{
Q_ASSERT(q_ptr);
DarwinBluetooth::qt_test_iobluetooth_runloop();
- if (state!= QBluetoothSocket::UnconnectedState && state != QBluetoothSocket::ServiceLookupState) {
+ if (state!= QBluetoothSocket::SocketState::UnconnectedState && state != QBluetoothSocket::SocketState::ServiceLookupState) {
qCWarning(QT_BT_DARWIN) << "called on a busy socket";
errorString = QCoreApplication::translate(SOCKET, SOC_CONNECT_IN_PROGRESS);
- q_ptr->setSocketError(QBluetoothSocket::OperationError);
+ q_ptr->setSocketError(QBluetoothSocket::SocketError::OperationError);
return;
}
@@ -274,7 +236,7 @@ void QBluetoothSocketPrivate::connectToService(const QBluetoothServiceInfo &serv
if (service.socketProtocol() == QBluetoothServiceInfo::UnknownProtocol) {
qCWarning(QT_BT_DARWIN) << Q_FUNC_INFO << "cannot connect with 'UnknownProtocol' type";
errorString = QCoreApplication::translate(SOCKET, SOC_NETWORK_ERROR);
- q_ptr->setSocketError(QBluetoothSocket::UnsupportedProtocolError);
+ q_ptr->setSocketError(QBluetoothSocket::SocketError::UnsupportedProtocolError);
return;
}
@@ -300,7 +262,7 @@ void QBluetoothSocketPrivate::connectToService(const QBluetoothServiceInfo &serv
}
}
-void QBluetoothSocketPrivate::connectToService(const QBluetoothAddress &address, const QBluetoothUuid &uuid,
+void QBluetoothSocketPrivateDarwin::connectToService(const QBluetoothAddress &address, const QBluetoothUuid &uuid,
QIODevice::OpenMode openMode)
{
Q_ASSERT(q_ptr);
@@ -311,14 +273,14 @@ void QBluetoothSocketPrivate::connectToService(const QBluetoothAddress &address,
if (socketType == QBluetoothServiceInfo::UnknownProtocol) {
qCWarning(QT_BT_DARWIN) << Q_FUNC_INFO << "cannot connect with 'UnknownProtocol' type";
errorString = QCoreApplication::translate(SOCKET, SOC_NETWORK_ERROR);
- q_ptr->setSocketError(QBluetoothSocket::UnsupportedProtocolError);
+ q_ptr->setSocketError(QBluetoothSocket::SocketError::UnsupportedProtocolError);
return;
}
- if (state != QBluetoothSocket::UnconnectedState) {
+ if (state != QBluetoothSocket::SocketState::UnconnectedState) {
qCWarning(QT_BT_DARWIN) << "called on a busy socket";
errorString = QCoreApplication::translate(SOCKET, SOC_CONNECT_IN_PROGRESS);
- q_ptr->setSocketError(QBluetoothSocket::OperationError);
+ q_ptr->setSocketError(QBluetoothSocket::SocketError::OperationError);
return;
}
@@ -329,7 +291,7 @@ void QBluetoothSocketPrivate::connectToService(const QBluetoothAddress &address,
q_ptr->doDeviceDiscovery(service, openMode);
}
-void QBluetoothSocketPrivate::connectToService(const QBluetoothAddress &address, quint16 port,
+void QBluetoothSocketPrivateDarwin::connectToService(const QBluetoothAddress &address, quint16 port,
QIODevice::OpenMode mode)
{
Q_ASSERT(q_ptr);
@@ -339,18 +301,18 @@ void QBluetoothSocketPrivate::connectToService(const QBluetoothAddress &address,
if (socketType == QBluetoothServiceInfo::UnknownProtocol) {
qCWarning(QT_BT_DARWIN) << Q_FUNC_INFO << "cannot connect with 'UnknownProtocol' type";
errorString = QCoreApplication::translate(SOCKET, SOC_NETWORK_ERROR);
- q_ptr->setSocketError(QBluetoothSocket::UnsupportedProtocolError);
+ q_ptr->setSocketError(QBluetoothSocket::SocketError::UnsupportedProtocolError);
return;
}
- Q_ASSERT_X(state == QBluetoothSocket::ServiceLookupState || state == QBluetoothSocket::UnconnectedState,
+ Q_ASSERT_X(state == QBluetoothSocket::SocketState::ServiceLookupState || state == QBluetoothSocket::SocketState::UnconnectedState,
Q_FUNC_INFO, "invalid state");
q_ptr->setOpenMode(mode);
- socketError = QBluetoothSocket::NoSocketError;
+ socketError = QBluetoothSocket::SocketError::NoSocketError;
errorString.clear();
- buffer.clear();
+ rxBuffer.clear();
txBuffer.clear();
IOReturn status = kIOReturnError;
@@ -359,7 +321,7 @@ void QBluetoothSocketPrivate::connectToService(const QBluetoothAddress &address,
const QBluetoothSocket::SocketState oldState = state;
// To prevent other connectToService calls (from QBluetoothSocket):
// and also avoid signals in delegate callbacks.
- state = QBluetoothSocket::ConnectingState;
+ state = QBluetoothSocket::SocketState::ConnectingState;
// We're still inside this function:
isConnecting = true;
@@ -367,15 +329,15 @@ void QBluetoothSocketPrivate::connectToService(const QBluetoothAddress &address,
openMode = mode;
if (socketType == QBluetoothServiceInfo::RfcommProtocol) {
- rfcommChannel.reset([[ObjCRFCOMMChannel alloc] initWithDelegate:this], RetainPolicy::noInitialRetain);
+ rfcommChannel.reset([[DarwinBTRFCOMMChannel alloc] initWithDelegate:this], RetainPolicy::noInitialRetain);
if (rfcommChannel)
- status = [rfcommChannel.getAs<ObjCRFCOMMChannel>() connectAsyncToDevice:address withChannelID:port];
+ status = [rfcommChannel.getAs<DarwinBTRFCOMMChannel>() connectAsyncToDevice:address withChannelID:port];
else
status = kIOReturnNoMemory;
} else if (socketType == QBluetoothServiceInfo::L2capProtocol) {
- l2capChannel.reset([[ObjCL2CAPChannel alloc] initWithDelegate:this], RetainPolicy::noInitialRetain);
+ l2capChannel.reset([[DarwinBTL2CAPChannel alloc] initWithDelegate:this], RetainPolicy::noInitialRetain);
if (l2capChannel)
- status = [l2capChannel.getAs<ObjCL2CAPChannel>() connectAsyncToDevice:address withPSM:port];
+ status = [l2capChannel.getAs<DarwinBTL2CAPChannel>() connectAsyncToDevice:address withPSM:port];
else
status = kIOReturnNoMemory;
}
@@ -385,37 +347,36 @@ void QBluetoothSocketPrivate::connectToService(const QBluetoothAddress &address,
// QBluetoothSocket will change the state and also emit
// a signal later if required.
- if (status == kIOReturnSuccess && socketError == QBluetoothSocket::NoSocketError) {
- if (state == QBluetoothSocket::ConnectedState) {
+ if (status == kIOReturnSuccess && socketError == QBluetoothSocket::SocketError::NoSocketError) {
+ if (state == QBluetoothSocket::SocketState::ConnectedState) {
// Callback 'channelOpenComplete' fired before
// connectToService finished:
state = oldState;
// Connected, setOpenMode on a QBluetoothSocket.
q_ptr->setOpenMode(openMode);
- q_ptr->setSocketState(QBluetoothSocket::ConnectedState);
- emit q_ptr->connected();
- if (buffer.size()) // We also have some data already ...
+ q_ptr->setSocketState(QBluetoothSocket::SocketState::ConnectedState);
+ if (rxBuffer.size()) // We also have some data already ...
emit q_ptr->readyRead();
- } else if (state == QBluetoothSocket::UnconnectedState) {
+ } else if (state == QBluetoothSocket::SocketState::UnconnectedState) {
// Even if we have some data, we can not read it if
// state != ConnectedState.
- buffer.clear();
+ rxBuffer.clear();
state = oldState;
- q_ptr->setSocketError(QBluetoothSocket::UnknownSocketError);
+ q_ptr->setSocketError(QBluetoothSocket::SocketError::UnknownSocketError);
} else {
// No error and we're connecting ...
state = oldState;
- q_ptr->setSocketState(QBluetoothSocket::ConnectingState);
+ q_ptr->setSocketState(QBluetoothSocket::SocketState::ConnectingState);
}
} else {
state = oldState;
if (status != kIOReturnSuccess)
errorString = DarwinBluetooth::qt_error_string(status);
- q_ptr->setSocketError(QBluetoothSocket::UnknownSocketError);
+ q_ptr->setSocketError(QBluetoothSocket::SocketError::UnknownSocketError);
}
}
-void QBluetoothSocketPrivate::_q_writeNotify()
+void QBluetoothSocketPrivateDarwin::_q_writeNotify()
{
Q_ASSERT_X(socketType == QBluetoothServiceInfo::L2capProtocol
|| socketType == QBluetoothServiceInfo::RfcommProtocol,
@@ -427,29 +388,29 @@ void QBluetoothSocketPrivate::_q_writeNotify()
if (txBuffer.size()) {
const bool isL2CAP = socketType == QBluetoothServiceInfo::L2capProtocol;
writeChunk.resize(isL2CAP ? std::numeric_limits<UInt16>::max() :
- [rfcommChannel.getAs<ObjCRFCOMMChannel>() getMTU]);
+ [rfcommChannel.getAs<DarwinBTRFCOMMChannel>() getMTU]);
- const int size = txBuffer.read(writeChunk.data(), writeChunk.size());
+ const auto size = txBuffer.read(writeChunk.data(), writeChunk.size());
IOReturn status = kIOReturnError;
if (!isL2CAP)
- status = [rfcommChannel.getAs<ObjCRFCOMMChannel>() writeAsync:writeChunk.data() length:UInt16(size)];
+ status = [rfcommChannel.getAs<DarwinBTRFCOMMChannel>() writeAsync:writeChunk.data() length:UInt16(size)];
else
- status = [l2capChannel.getAs<ObjCL2CAPChannel>() writeAsync:writeChunk.data() length:UInt16(size)];
+ status = [l2capChannel.getAs<DarwinBTL2CAPChannel>() writeAsync:writeChunk.data() length:UInt16(size)];
if (status != kIOReturnSuccess) {
errorString = QCoreApplication::translate(SOCKET, SOC_NETWORK_ERROR);
- q_ptr->setSocketError(QBluetoothSocket::NetworkError);
+ q_ptr->setSocketError(QBluetoothSocket::SocketError::NetworkError);
return;
} else {
emit q_ptr->bytesWritten(size);
}
}
- if (!txBuffer.size() && state == QBluetoothSocket::ClosingState)
+ if (!txBuffer.size() && state == QBluetoothSocket::SocketState::ClosingState)
close();
}
-bool QBluetoothSocketPrivate::setRFCOMChannel(void *generic)
+bool QBluetoothSocketPrivateDarwin::setRFCOMChannel(void *generic)
{
// A special case "constructor": on OS X we do not have a real listening socket,
// instead a bluetooth server "listens" for channel open notifications and
@@ -458,23 +419,23 @@ bool QBluetoothSocketPrivate::setRFCOMChannel(void *generic)
// a "socket" from such an external channel (reported by a notification).
auto channel = static_cast<IOBluetoothRFCOMMChannel *>(generic);
// It must be a newborn socket!
- Q_ASSERT_X(socketError == QBluetoothSocket::NoSocketError
- && state == QBluetoothSocket::UnconnectedState && !rfcommChannel && !l2capChannel,
+ Q_ASSERT_X(socketError == QBluetoothSocket::SocketError::NoSocketError
+ && state == QBluetoothSocket::SocketState::UnconnectedState && !rfcommChannel && !l2capChannel,
Q_FUNC_INFO, "unexpected socket state");
openMode = QIODevice::ReadWrite;
- rfcommChannel.reset([[ObjCRFCOMMChannel alloc] initWithDelegate:this channel:channel],
+ rfcommChannel.reset([[DarwinBTRFCOMMChannel alloc] initWithDelegate:this channel:channel],
RetainPolicy::noInitialRetain);
if (rfcommChannel) {// We do not handle errors, up to an external user.
q_ptr->setOpenMode(QIODevice::ReadWrite);
- state = QBluetoothSocket::ConnectedState;
+ state = QBluetoothSocket::SocketState::ConnectedState;
socketType = QBluetoothServiceInfo::RfcommProtocol;
}
return rfcommChannel;
}
-bool QBluetoothSocketPrivate::setL2CAPChannel(void *generic)
+bool QBluetoothSocketPrivateDarwin::setL2CAPChannel(void *generic)
{
// A special case "constructor": on OS X we do not have a real listening socket,
// instead a bluetooth server "listens" for channel open notifications and
@@ -484,52 +445,51 @@ bool QBluetoothSocketPrivate::setL2CAPChannel(void *generic)
auto channel = static_cast<IOBluetoothL2CAPChannel *>(generic);
// It must be a newborn socket!
- Q_ASSERT_X(socketError == QBluetoothSocket::NoSocketError
- && state == QBluetoothSocket::UnconnectedState && !l2capChannel && !rfcommChannel,
+ Q_ASSERT_X(socketError == QBluetoothSocket::SocketError::NoSocketError
+ && state == QBluetoothSocket::SocketState::UnconnectedState && !l2capChannel && !rfcommChannel,
Q_FUNC_INFO, "unexpected socket state");
openMode = QIODevice::ReadWrite;
- l2capChannel.reset([[ObjCL2CAPChannel alloc] initWithDelegate:this channel:channel], RetainPolicy::noInitialRetain);
+ l2capChannel.reset([[DarwinBTL2CAPChannel alloc] initWithDelegate:this channel:channel], RetainPolicy::noInitialRetain);
if (l2capChannel) {// We do not handle errors, up to an external user.
q_ptr->setOpenMode(QIODevice::ReadWrite);
- state = QBluetoothSocket::ConnectedState;
+ state = QBluetoothSocket::SocketState::ConnectedState;
socketType = QBluetoothServiceInfo::L2capProtocol;
}
return l2capChannel;
}
-void QBluetoothSocketPrivate::setChannelError(IOReturn errorCode)
+void QBluetoothSocketPrivateDarwin::setChannelError(IOReturn errorCode)
{
- Q_UNUSED(errorCode)
+ Q_UNUSED(errorCode);
Q_ASSERT_X(q_ptr, Q_FUNC_INFO, "invalid q_ptr (null)");
if (isConnecting) {
// The delegate's method was called while we are still in
// connectToService ... will emit a moment later.
- socketError = QBluetoothSocket::UnknownSocketError;
+ socketError = QBluetoothSocket::SocketError::UnknownSocketError;
} else {
- q_ptr->setSocketError(QBluetoothSocket::UnknownSocketError);
+ q_ptr->setSocketError(QBluetoothSocket::SocketError::UnknownSocketError);
}
}
-void QBluetoothSocketPrivate::channelOpenComplete()
+void QBluetoothSocketPrivateDarwin::channelOpenComplete()
{
Q_ASSERT_X(q_ptr, Q_FUNC_INFO, "invalid q_ptr (null)");
if (!isConnecting) {
- q_ptr->setSocketState(QBluetoothSocket::ConnectedState);
q_ptr->setOpenMode(openMode);
- emit q_ptr->connected();
+ q_ptr->setSocketState(QBluetoothSocket::SocketState::ConnectedState);
} else {
- state = QBluetoothSocket::ConnectedState;
+ state = QBluetoothSocket::SocketState::ConnectedState;
// We are still in connectToService, it'll care
// about signals!
}
}
-void QBluetoothSocketPrivate::channelClosed()
+void QBluetoothSocketPrivateDarwin::channelClosed()
{
Q_ASSERT_X(q_ptr, Q_FUNC_INFO, "invalid q_ptr (null)");
@@ -537,25 +497,24 @@ void QBluetoothSocketPrivate::channelClosed()
// (thus close/abort probably will not work).
if (!isConnecting) {
- q_ptr->setSocketState(QBluetoothSocket::UnconnectedState);
q_ptr->setOpenMode(QIODevice::NotOpen);
+ q_ptr->setSocketState(QBluetoothSocket::SocketState::UnconnectedState);
emit q_ptr->readChannelFinished();
- emit q_ptr->disconnected();
} else {
- state = QBluetoothSocket::UnconnectedState;
+ state = QBluetoothSocket::SocketState::UnconnectedState;
// We are still in connectToService and do not want
// to emit any signals yet.
}
}
-void QBluetoothSocketPrivate::readChannelData(void *data, std::size_t size)
+void QBluetoothSocketPrivateDarwin::readChannelData(void *data, std::size_t size)
{
Q_ASSERT_X(data, Q_FUNC_INFO, "invalid data (null)");
Q_ASSERT_X(size, Q_FUNC_INFO, "invalid data size (0)");
Q_ASSERT_X(q_ptr, Q_FUNC_INFO, "invalid q_ptr (null)");
const char *src = static_cast<char *>(data);
- char *dst = buffer.reserve(int(size));
+ char *dst = rxBuffer.reserve(int(size));
std::copy(src, src + size, dst);
if (!isConnecting) {
@@ -564,7 +523,7 @@ void QBluetoothSocketPrivate::readChannelData(void *data, std::size_t size)
} // else connectToService must check and emit readyRead!
}
-void QBluetoothSocketPrivate::writeComplete()
+void QBluetoothSocketPrivateDarwin::writeComplete()
{
_q_writeNotify();
}
diff --git a/src/bluetooth/qbluetoothsocket_macos_p.h b/src/bluetooth/qbluetoothsocket_macos_p.h
index 93cfbe4c..139bca85 100644
--- a/src/bluetooth/qbluetoothsocket_macos_p.h
+++ b/src/bluetooth/qbluetoothsocket_macos_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QBLUETOOTHSOCKET_OSX_P_H
#define QBLUETOOTHSOCKET_OSX_P_H
@@ -66,25 +30,25 @@
#include <QtCore/qbytearray.h>
#include "qprivatelinearbuffer_p.h"
-#include <QtCore/qscopedpointer.h>
-#include <QtCore/qiodevice.h>
#include <QtCore/qglobal.h>
-#include <QtCore/qobject.h>
-#include <QtCore/qstring.h>
-#include <QtCore/qvector.h>
+#include <QtCore/QIODevice>
+#include <QtCore/QList>
+#include <QtCore/QObject>
+#include <QtCore/QScopedPointer>
+#include <QtCore/QString>
QT_BEGIN_NAMESPACE
class QBluetoothAddress;
-class QBluetoothSocketPrivate : public QBluetoothSocketBasePrivate, public DarwinBluetooth::ChannelDelegate
+class QBluetoothSocketPrivateDarwin : public QBluetoothSocketBasePrivate, public DarwinBluetooth::ChannelDelegate
{
friend class QBluetoothSocket;
friend class QBluetoothServer;
public:
- QBluetoothSocketPrivate();
- ~QBluetoothSocketPrivate();
+ QBluetoothSocketPrivateDarwin();
+ ~QBluetoothSocketPrivateDarwin();
//
bool ensureNativeSocket(QBluetoothServiceInfo::Protocol type) override;
@@ -135,7 +99,7 @@ private:
void readChannelData(void *data, std::size_t size) override;
void writeComplete() override;
- QVector<char> writeChunk;
+ QList<char> writeChunk;
using L2CAPChannel = DarwinBluetooth::ScopedPointer;
L2CAPChannel l2capChannel;
diff --git a/src/bluetooth/qbluetoothsocket_win.cpp b/src/bluetooth/qbluetoothsocket_win.cpp
deleted file mode 100644
index 83855323..00000000
--- a/src/bluetooth/qbluetoothsocket_win.cpp
+++ /dev/null
@@ -1,597 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qbluetoothsocket.h"
-#include "qbluetoothsocket_win_p.h"
-
-#include <QtCore/qloggingcategory.h>
-
-#include <QtBluetooth/qbluetoothdeviceinfo.h>
-#include <QtBluetooth/QBluetoothLocalDevice>
-#include <QtCore/QSocketNotifier>
-
-#include <winsock2.h>
-#include <ws2bth.h>
-#include <bluetoothapis.h>
-
-QT_BEGIN_NAMESPACE
-
-Q_DECLARE_LOGGING_CATEGORY(QT_BT_WINDOWS)
-
-QBluetoothSocketPrivateWin::QBluetoothSocketPrivateWin()
- : QBluetoothSocketBasePrivate()
-{
- WSAData wsadata = {};
- ::WSAStartup(MAKEWORD(2, 0), &wsadata);
-}
-
-QBluetoothSocketPrivateWin::~QBluetoothSocketPrivateWin()
-{
- abort();
-}
-
-bool QBluetoothSocketPrivateWin::ensureNativeSocket(QBluetoothServiceInfo::Protocol type)
-{
- Q_Q(QBluetoothSocket);
-
- if (static_cast<SOCKET>(socket) != INVALID_SOCKET) {
- if (socketType == type)
- return true;
- abort();
- }
- socketType = type;
-
- if (type != QBluetoothServiceInfo::RfcommProtocol) {
- socket = int(INVALID_SOCKET);
- errorString = QBluetoothSocket::tr("Unsupported protocol. Win32 only supports RFCOMM sockets");
- q->setSocketError(QBluetoothSocket::UnsupportedProtocolError);
- return false;
- }
-
- socket = ::socket(AF_BTH, SOCK_STREAM, BTHPROTO_RFCOMM);
-
- if (static_cast<SOCKET>(socket) == INVALID_SOCKET) {
- const int error = ::WSAGetLastError();
- qCWarning(QT_BT_WINDOWS) << "Failed to create socket:" << error << qt_error_string(error);
- errorString = QBluetoothSocket::tr("Failed to create socket");
- q->setSocketError(QBluetoothSocket::UnknownSocketError);
- return false;
- }
-
- if (!createNotifiers())
- return false;
-
- return true;
-}
-
-void QBluetoothSocketPrivateWin::connectToServiceHelper(const QBluetoothAddress &address, quint16 port, QIODevice::OpenMode openMode)
-{
- Q_Q(QBluetoothSocket);
-
- if (static_cast<SOCKET>(socket) == INVALID_SOCKET && !ensureNativeSocket(socketType))
- return;
-
- if (!configureSecurity())
- return;
-
- SOCKADDR_BTH addr = {};
- addr.addressFamily = AF_BTH;
- addr.port = port;
- addr.btAddr = address.toUInt64();
-
- switch (socketType) {
- case QBluetoothServiceInfo::RfcommProtocol:
- addr.serviceClassId = RFCOMM_PROTOCOL_UUID;
- break;
- default:
- errorString = QBluetoothSocket::tr("Socket type not handled: %1").arg(socketType);
- q->setSocketError(QBluetoothSocket::UnsupportedProtocolError);
- return;
- }
-
- connectWriteNotifier->setEnabled(true);
- readNotifier->setEnabled(true);
- exceptNotifier->setEnabled(true);
-
- const int result = ::connect(socket, reinterpret_cast<sockaddr *>(&addr), sizeof(addr));
-
- const int error = ::WSAGetLastError();
- if (result != SOCKET_ERROR || error == WSAEWOULDBLOCK) {
- q->setSocketState(QBluetoothSocket::ConnectingState);
- q->setOpenMode(openMode);
- } else {
- errorString = qt_error_string(error);
- q->setSocketError(QBluetoothSocket::UnknownSocketError);
- }
-}
-
-void QBluetoothSocketPrivateWin::connectToService(
- const QBluetoothServiceInfo &service, QIODevice::OpenMode openMode)
-{
- Q_Q(QBluetoothSocket);
-
- if (q->state() != QBluetoothSocket::UnconnectedState
- && q->state() != QBluetoothSocket::ServiceLookupState) {
- //qCWarning(QT_BT_WINDOWS) << "QBluetoothSocketPrivateWIN::connectToService called on busy socket";
- errorString = QBluetoothSocket::tr("Trying to connect while connection is in progress");
- q->setSocketError(QBluetoothSocket::OperationError);
- return;
- }
-
- // we are checking the service protocol and not socketType()
- // socketType will change in ensureNativeSocket()
- if (service.socketProtocol() != QBluetoothServiceInfo::RfcommProtocol) {
- qCWarning(QT_BT_WINDOWS) << "QBluetoothSocket::connectToService called with unsupported protocol";
- errorString = QBluetoothSocket::tr("Socket type not supported");
- q->setSocketError(QBluetoothSocket::UnsupportedProtocolError);
- return;
- }
-
- if (service.serverChannel() > 0) {
- if (!ensureNativeSocket(QBluetoothServiceInfo::RfcommProtocol)) {
- errorString = QBluetoothSocket::tr("Unknown socket error");
- q->setSocketError(QBluetoothSocket::UnknownSocketError);
- return;
- }
- connectToServiceHelper(service.device().address(), service.serverChannel(), openMode);
- } else {
- // try doing service discovery to see if we can find the socket
- if (service.serviceUuid().isNull()
- && !service.serviceClassUuids().contains(QBluetoothUuid::SerialPort)) {
- qCWarning(QT_BT_WINDOWS) << "No port, no PSM, and no UUID provided. Unable to connect";
- return;
- }
- qCDebug(QT_BT_WINDOWS) << "Need a port/psm, doing discovery";
- q->doDeviceDiscovery(service, openMode);
- }
-}
-
-void QBluetoothSocketPrivateWin::_q_writeNotify()
-{
- Q_Q(QBluetoothSocket);
-
- if (state == QBluetoothSocket::ConnectingState) {
- q->setSocketState(QBluetoothSocket::ConnectedState);
- connectWriteNotifier->setEnabled(false);
- } else {
- if (txBuffer.isEmpty()) {
- connectWriteNotifier->setEnabled(false);
- return;
- }
-
- char buf[1024];
- const int size = txBuffer.read(&buf[0], sizeof(buf));
- const int writtenBytes = ::send(socket, &buf[0], size, 0);
- if (writtenBytes == SOCKET_ERROR) {
- // every other case returns error
- const int error = ::WSAGetLastError();
- errorString = QBluetoothSocket::tr("Network Error: %1").arg(qt_error_string(error));
- q->setSocketError(QBluetoothSocket::NetworkError);
- } else if (writtenBytes <= size) {
- // add remainder back to buffer
- const char *remainder = &buf[writtenBytes];
- txBuffer.ungetBlock(remainder, size - writtenBytes);
- if (writtenBytes > 0)
- emit q->bytesWritten(writtenBytes);
- } else {
- errorString = QBluetoothSocket::tr("Logic error: more bytes sent than passed to ::send");
- q->setSocketError(QBluetoothSocket::NetworkError);
- }
-
- if (!txBuffer.isEmpty()) {
- connectWriteNotifier->setEnabled(true);
- } else if (state == QBluetoothSocket::ClosingState) {
- connectWriteNotifier->setEnabled(false);
- this->close();
- }
- }
-}
-
-void QBluetoothSocketPrivateWin::_q_readNotify()
-{
- Q_Q(QBluetoothSocket);
-
- char *writePointer = buffer.reserve(QPRIVATELINEARBUFFER_BUFFERSIZE);
- const int bytesRead = ::recv(socket, writePointer, QPRIVATELINEARBUFFER_BUFFERSIZE, 0);
- if (bytesRead == SOCKET_ERROR) {
- const int error = ::WSAGetLastError();
- buffer.chop(QPRIVATELINEARBUFFER_BUFFERSIZE);
- readNotifier->setEnabled(false);
- connectWriteNotifier->setEnabled(false);
- errorString = qt_error_string(error);
- qCWarning(QT_BT_WINDOWS) << Q_FUNC_INFO << socket << "error:" << error << errorString;
- switch (error) {
- case WSAEHOSTDOWN:
- q->setSocketError(QBluetoothSocket::HostNotFoundError);
- break;
- case WSAECONNRESET:
- q->setSocketError(QBluetoothSocket::RemoteHostClosedError);
- break;
- default:
- q->setSocketError(QBluetoothSocket::UnknownSocketError);
- break;
- }
-
- q->disconnectFromService();
- } else if (bytesRead == 0) {
- q->setSocketError(QBluetoothSocket::RemoteHostClosedError);
- q->setSocketState(QBluetoothSocket::UnconnectedState);
- } else {
- const int unusedBytes = QPRIVATELINEARBUFFER_BUFFERSIZE - bytesRead;
- buffer.chop(unusedBytes);
- if (bytesRead > 0)
- emit q->readyRead();
- }
-}
-
-void QBluetoothSocketPrivateWin::_q_exceptNotify()
-{
- Q_Q(QBluetoothSocket);
-
- const int error = ::WSAGetLastError();
- errorString = qt_error_string(error);
- q->setSocketError(QBluetoothSocket::UnknownSocketError);
-
- if (state == QBluetoothSocket::ConnectingState)
- abort();
-}
-
-void QBluetoothSocketPrivateWin::connectToService(
- const QBluetoothAddress &address, const QBluetoothUuid &uuid,
- QIODevice::OpenMode openMode)
-{
- Q_Q(QBluetoothSocket);
-
- if (q->state() != QBluetoothSocket::UnconnectedState) {
- qCWarning(QT_BT_WINDOWS) << "QBluetoothSocketPrivateWin::connectToService called on busy socket";
- errorString = QBluetoothSocket::tr("Trying to connect while connection is in progress");
- q->setSocketError(QBluetoothSocket::OperationError);
- return;
- }
-
- if (q->socketType() == QBluetoothServiceInfo::UnknownProtocol) {
- qCWarning(QT_BT_WINDOWS) << "QBluetoothSocketPrivateWin::connectToService cannot "
- "connect with 'UnknownProtocol' (type provided by given service)";
- errorString = QBluetoothSocket::tr("Socket type not supported");
- q->setSocketError(QBluetoothSocket::UnsupportedProtocolError);
- return;
- }
-
- QBluetoothServiceInfo service;
- QBluetoothDeviceInfo device(address, QString(), QBluetoothDeviceInfo::MiscellaneousDevice);
- service.setDevice(device);
- service.setServiceUuid(uuid);
- q->doDeviceDiscovery(service, openMode);
-}
-
-void QBluetoothSocketPrivateWin::connectToService(
- const QBluetoothAddress &address, quint16 port, QIODevice::OpenMode openMode)
-{
- Q_Q(QBluetoothSocket);
-
- if (q->socketType() == QBluetoothServiceInfo::UnknownProtocol) {
- qCWarning(QT_BT_WINDOWS) << "QBluetoothSocketPrivateWin::connectToService cannot "
- "connect with 'UnknownProtocol' (type provided by given service)";
- errorString = QBluetoothSocket::tr("Socket type not supported");
- q->setSocketError(QBluetoothSocket::UnsupportedProtocolError);
- return;
- }
-
- if (q->state() != QBluetoothSocket::UnconnectedState) {
- qCWarning(QT_BT_WINDOWS) << "QBluetoothSocketPrivateWin::connectToService called on busy socket";
- errorString = QBluetoothSocket::tr("Trying to connect while connection is in progress");
- q->setSocketError(QBluetoothSocket::OperationError);
- return;
- }
-
- q->setOpenMode(openMode);
- connectToServiceHelper(address, port, openMode);
-}
-
-void QBluetoothSocketPrivateWin::abort()
-{
- delete readNotifier;
- readNotifier = nullptr;
- delete connectWriteNotifier;
- connectWriteNotifier = nullptr;
- delete exceptNotifier;
- exceptNotifier = nullptr;
-
- // We don't transition through Closing for abort, so
- // we don't call disconnectFromService or QBluetoothSocket::close
- ::closesocket(socket);
- socket = int(INVALID_SOCKET);
-
- Q_Q(QBluetoothSocket);
-
- const bool wasConnected = q->state() == QBluetoothSocket::ConnectedState;
- q->setSocketState(QBluetoothSocket::UnconnectedState);
- if (wasConnected) {
- q->setOpenMode(QIODevice::NotOpen);
- emit q->readChannelFinished();
- }
-}
-
-QString QBluetoothSocketPrivateWin::localName() const
-{
- const QBluetoothAddress localAddr = localAddress();
- if (localAddr == QBluetoothAddress())
- return {};
- const QBluetoothLocalDevice device(localAddr);
- return device.name();
-}
-
-QBluetoothAddress QBluetoothSocketPrivateWin::localAddress() const
-{
- if (static_cast<SOCKET>(socket) == INVALID_SOCKET)
- return {};
- SOCKADDR_BTH localAddr = {};
- int localAddrLength = sizeof(localAddr);
- const int localResult = ::getsockname(socket, reinterpret_cast<sockaddr *>(&localAddr), &localAddrLength);
- if (localResult == SOCKET_ERROR) {
- const int error = ::WSAGetLastError();
- qCWarning(QT_BT_WINDOWS) << "Error getting local address" << error << qt_error_string(error);
- return {};
- }
- return QBluetoothAddress(localAddr.btAddr);
-}
-
-quint16 QBluetoothSocketPrivateWin::localPort() const
-{
- if (static_cast<SOCKET>(socket) == INVALID_SOCKET)
- return {};
- SOCKADDR_BTH localAddr = {};
- int localAddrLength = sizeof(localAddr);
- const int localResult = ::getsockname(socket, reinterpret_cast<sockaddr *>(&localAddr), &localAddrLength);
- if (localResult == SOCKET_ERROR) {
- const int error = ::WSAGetLastError();
- qCWarning(QT_BT_WINDOWS) << "Error getting local port" << error << qt_error_string(error);
- return {};
- }
- return localAddr.port;
-}
-
-QString QBluetoothSocketPrivateWin::peerName() const
-{
- const QBluetoothAddress peerAddr = peerAddress();
- if (peerAddr == QBluetoothAddress())
- return {};
- BLUETOOTH_DEVICE_INFO bdi = {};
- bdi.dwSize = sizeof(bdi);
- bdi.Address.ullLong = peerAddr.toUInt64();
- const DWORD res = ::BluetoothGetDeviceInfo(nullptr, &bdi);
- if (res != ERROR_SUCCESS) {
- qCWarning(QT_BT_WINDOWS) << "Error calling BluetoothGetDeviceInfo" << res << qt_error_string(res);
- return {};
- }
- return QString::fromWCharArray(&bdi.szName[0]);
-}
-
-QBluetoothAddress QBluetoothSocketPrivateWin::peerAddress() const
-{
- if (static_cast<SOCKET>(socket) == INVALID_SOCKET)
- return {};
- SOCKADDR_BTH peerAddr = {};
- int peerAddrLength = sizeof(peerAddr);
- const int peerResult = ::getpeername(socket, reinterpret_cast<sockaddr *>(&peerAddr), &peerAddrLength);
- if (peerResult == SOCKET_ERROR) {
- const int error = ::WSAGetLastError();
- qCWarning(QT_BT_WINDOWS) << "Error getting peer address and port" << error << qt_error_string(error);
- return {};
- }
- return QBluetoothAddress(peerAddr.btAddr);
-}
-
-quint16 QBluetoothSocketPrivateWin::peerPort() const
-{
- if (static_cast<SOCKET>(socket) == INVALID_SOCKET)
- return {};
- SOCKADDR_BTH peerAddr = {};
- int peerAddrLength = sizeof(peerAddr);
- const int peerResult = ::getpeername(socket, reinterpret_cast<sockaddr *>(&peerAddr), &peerAddrLength);
- if (peerResult == SOCKET_ERROR) {
- const int error = ::WSAGetLastError();
- qCWarning(QT_BT_WINDOWS) << "Error getting peer address and port" << error << qt_error_string(error);
- return {};
- }
- return peerAddr.port;
-}
-
-qint64 QBluetoothSocketPrivateWin::writeData(const char *data, qint64 maxSize)
-{
- Q_Q(QBluetoothSocket);
-
- if (state != QBluetoothSocket::ConnectedState) {
- errorString = QBluetoothSocket::tr("Cannot write while not connected");
- q->setSocketError(QBluetoothSocket::OperationError);
- return -1;
- }
-
- if (q->openMode() & QIODevice::Unbuffered) {
- const int bytesWritten = ::send(socket, data, maxSize, 0);
-
- if (bytesWritten == SOCKET_ERROR) {
- const int error = ::WSAGetLastError();
- errorString = QBluetoothSocket::tr("Network Error: %1").arg(qt_error_string(error));
- q->setSocketError(QBluetoothSocket::NetworkError);
- }
-
- if (bytesWritten > 0)
- emit q->bytesWritten(bytesWritten);
-
- return bytesWritten;
- } else {
-
- if (!connectWriteNotifier)
- return -1;
-
- if (txBuffer.isEmpty()) {
- connectWriteNotifier->setEnabled(true);
- QMetaObject::invokeMethod(this, "_q_writeNotify", Qt::QueuedConnection);
- }
-
- char *txbuf = txBuffer.reserve(maxSize);
- ::memcpy(txbuf, data, maxSize);
-
- return maxSize;
- }
-}
-
-qint64 QBluetoothSocketPrivateWin::readData(char *data, qint64 maxSize)
-{
- Q_Q(QBluetoothSocket);
-
- if (state != QBluetoothSocket::ConnectedState) {
- errorString = QBluetoothSocket::tr("Cannot read while not connected");
- q->setSocketError(QBluetoothSocket::OperationError);
- return -1;
- }
-
- const int bytesRead = buffer.read(data, maxSize);
- return bytesRead;
-}
-
-void QBluetoothSocketPrivateWin::close()
-{
- if (txBuffer.isEmpty())
- abort();
- else
- connectWriteNotifier->setEnabled(true);
-}
-
-bool QBluetoothSocketPrivateWin::setSocketDescriptor(int socketDescriptor,
- QBluetoothServiceInfo::Protocol protocol,
- QBluetoothSocket::SocketState socketState,
- QBluetoothSocket::OpenMode openMode)
-{
- Q_Q(QBluetoothSocket);
-
- abort();
-
- socketType = protocol;
- socket = socketDescriptor;
-
- if (!createNotifiers())
- return false;
- q->setSocketState(socketState);
- q->setOpenMode(openMode);
- if (socketState == QBluetoothSocket::ConnectedState) {
- connectWriteNotifier->setEnabled(true);
- readNotifier->setEnabled(true);
- exceptNotifier->setEnabled(true);
- }
-
- return true;
-}
-
-qint64 QBluetoothSocketPrivateWin::bytesAvailable() const
-{
- return buffer.size();
-}
-
-bool QBluetoothSocketPrivateWin::canReadLine() const
-{
- return buffer.canReadLine();
-}
-
-qint64 QBluetoothSocketPrivateWin::bytesToWrite() const
-{
- return txBuffer.size();
-}
-
-bool QBluetoothSocketPrivateWin::createNotifiers()
-{
- Q_Q(QBluetoothSocket);
-
- ULONG mode = 1; // 1 to enable non-blocking socket
- const int result = ::ioctlsocket(socket, FIONBIO, &mode);
-
- if (result == SOCKET_ERROR) {
- const int error = ::WSAGetLastError();
- errorString = qt_error_string(error);
- q->setSocketError(QBluetoothSocket::UnknownSocketError);
- qCWarning(QT_BT_WINDOWS) << "Error setting socket to non-blocking" << error << errorString;
- abort();
- return false;
- }
- readNotifier = new QSocketNotifier(socket, QSocketNotifier::Read);
- QObject::connect(readNotifier, &QSocketNotifier::activated, this, &QBluetoothSocketPrivateWin::_q_readNotify);
- connectWriteNotifier = new QSocketNotifier(socket, QSocketNotifier::Write, q);
- QObject::connect(connectWriteNotifier, &QSocketNotifier::activated, this, &QBluetoothSocketPrivateWin::_q_writeNotify);
- exceptNotifier = new QSocketNotifier(socket, QSocketNotifier::Exception, q);
- QObject::connect(exceptNotifier, &QSocketNotifier::activated, this, &QBluetoothSocketPrivateWin::_q_exceptNotify);
-
- connectWriteNotifier->setEnabled(false);
- readNotifier->setEnabled(false);
- exceptNotifier->setEnabled(false);
- return true;
-}
-
-bool QBluetoothSocketPrivateWin::configureSecurity()
-{
- Q_Q(QBluetoothSocket);
-
- if (secFlags & QBluetooth::Authorization) {
- ULONG authenticate = TRUE;
- const int result = ::setsockopt(socket, SOL_RFCOMM, SO_BTH_AUTHENTICATE, reinterpret_cast<const char*>(&authenticate), sizeof(authenticate));
- if (result == SOCKET_ERROR) {
- const int error = ::WSAGetLastError();
- qCWarning(QT_BT_WINDOWS) << "Failed to set socket option, closing socket for safety" << error;
- qCWarning(QT_BT_WINDOWS) << "Error: " << qt_error_string(error);
- errorString = QBluetoothSocket::tr("Cannot set connection security level");
- q->setSocketError(QBluetoothSocket::UnknownSocketError);
- return false;
- }
- }
-
- if (secFlags & QBluetooth::Encryption) {
- ULONG encrypt = TRUE;
- const int result = ::setsockopt(socket, SOL_RFCOMM, SO_BTH_ENCRYPT, reinterpret_cast<const char*>(&encrypt), sizeof(encrypt));
- if (result == SOCKET_ERROR) {
- const int error = ::WSAGetLastError();
- qCWarning(QT_BT_WINDOWS) << "Failed to set socket option, closing socket for safety" << error;
- qCWarning(QT_BT_WINDOWS) << "Error: " << qt_error_string(error);
- errorString = QBluetoothSocket::tr("Cannot set connection security level");
- q->setSocketError(QBluetoothSocket::UnknownSocketError);
- return false;
- }
- }
- return true;
-}
-QT_END_NAMESPACE
diff --git a/src/bluetooth/qbluetoothsocket_win_p.h b/src/bluetooth/qbluetoothsocket_win_p.h
deleted file mode 100644
index 77f4842e..00000000
--- a/src/bluetooth/qbluetoothsocket_win_p.h
+++ /dev/null
@@ -1,118 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QBLUETOOTHSOCKET_WIN_H
-#define QBLUETOOTHSOCKET_WIN_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include "qbluetoothsocket.h"
-#include "qbluetoothsocketbase_p.h"
-#include <QtGlobal>
-
-QT_BEGIN_NAMESPACE
-
-class QBluetoothSocketPrivateWin final : public QBluetoothSocketBasePrivate
-{
- Q_OBJECT
- friend class QBluetoothServerPrivate;
-
-public:
- QBluetoothSocketPrivateWin();
- ~QBluetoothSocketPrivateWin() override;
-
- void connectToServiceHelper(const QBluetoothAddress &address,
- quint16 port,
- QIODevice::OpenMode openMode) override;
-
- void connectToService(const QBluetoothServiceInfo &service,
- QIODevice::OpenMode openMode) override;
- void connectToService(const QBluetoothAddress &address, const QBluetoothUuid &uuid,
- QIODevice::OpenMode openMode) override;
- void connectToService(const QBluetoothAddress &address, quint16 port,
- QIODevice::OpenMode openMode) override;
-
- bool ensureNativeSocket(QBluetoothServiceInfo::Protocol type) override;
-
- QString localName() const override;
- QBluetoothAddress localAddress() const override;
- quint16 localPort() const override;
-
- QString peerName() const override;
- QBluetoothAddress peerAddress() const override;
- quint16 peerPort() const override;
-
- void abort() override;
- void close() override;
-
- qint64 writeData(const char *data, qint64 maxSize) override;
- qint64 readData(char *data, qint64 maxSize) override;
-
- bool setSocketDescriptor(int socketDescriptor, QBluetoothServiceInfo::Protocol socketType,
- QBluetoothSocket::SocketState socketState = QBluetoothSocket::ConnectedState,
- QBluetoothSocket::OpenMode openMode = QBluetoothSocket::ReadWrite) override;
-
- qint64 bytesAvailable() const override;
- bool canReadLine() const override;
- qint64 bytesToWrite() const override;
-
-private slots:
- void _q_readNotify();
- void _q_writeNotify();
- void _q_exceptNotify();
-
-private:
- bool createNotifiers();
- bool configureSecurity();
-
- QSocketNotifier *exceptNotifier = nullptr;
-};
-
-QT_END_NAMESPACE
-
-#endif // QBLUETOOTHSOCKET_WIN_H
diff --git a/src/bluetooth/qbluetoothsocket_winrt.cpp b/src/bluetooth/qbluetoothsocket_winrt.cpp
index 48b14757..1d98f4fc 100644
--- a/src/bluetooth/qbluetoothsocket_winrt.cpp
+++ b/src/bluetooth/qbluetoothsocket_winrt.cpp
@@ -1,55 +1,15 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qbluetoothsocket_winrt_p.h"
-
-#ifdef CLASSIC_APP_BUILD
-#define Q_OS_WINRT
-#endif
-#include <qfunctions_winrt.h>
-
-#include <private/qeventdispatcher_winrt_p.h>
+#include "qbluetoothutils_winrt_p.h"
#include <QtBluetooth/QBluetoothLocalDevice>
#include <QtBluetooth/qbluetoothdeviceinfo.h>
#include <QtBluetooth/qbluetoothserviceinfo.h>
#include <QtCore/qloggingcategory.h>
+#include <QtCore/QPointer>
+#include <QtCore/private/qfunctions_winrt_p.h>
#include <robuffer.h>
#include <windows.devices.bluetooth.h>
@@ -72,7 +32,7 @@ typedef IAsyncOperationWithProgress<IBuffer *, UINT32> IAsyncBufferOperation;
QT_BEGIN_NAMESPACE
-Q_DECLARE_LOGGING_CATEGORY(QT_BT_WINRT)
+Q_DECLARE_LOGGING_CATEGORY(QT_BT_WINDOWS)
struct SocketGlobal
{
@@ -101,25 +61,25 @@ static inline QString qt_QStringFromHString(const HString &string)
static qint64 writeIOStream(ComPtr<IOutputStream> stream, const char *data, qint64 len)
{
- ComPtr<IBuffer> buffer;
+ ComPtr<IBuffer> tempBuffer;
if (len > UINT32_MAX) {
- qCWarning(QT_BT_WINRT) << "writeIOStream can only write up to" << UINT32_MAX << "bytes.";
+ qCWarning(QT_BT_WINDOWS) << "writeIOStream can only write up to" << UINT32_MAX << "bytes.";
len = UINT32_MAX;
}
quint32 ulen = static_cast<quint32>(len);
- HRESULT hr = g->bufferFactory->Create(ulen, &buffer);
+ HRESULT hr = g->bufferFactory->Create(ulen, &tempBuffer);
Q_ASSERT_SUCCEEDED(hr);
- hr = buffer->put_Length(ulen);
+ hr = tempBuffer->put_Length(ulen);
Q_ASSERT_SUCCEEDED(hr);
ComPtr<Windows::Storage::Streams::IBufferByteAccess> byteArrayAccess;
- hr = buffer.As(&byteArrayAccess);
+ hr = tempBuffer.As(&byteArrayAccess);
Q_ASSERT_SUCCEEDED(hr);
byte *bytes;
hr = byteArrayAccess->Buffer(&bytes);
Q_ASSERT_SUCCEEDED(hr);
memcpy(bytes, data, ulen);
ComPtr<IAsyncOperationWithProgress<UINT32, UINT32>> op;
- hr = stream->WriteAsync(buffer.Get(), &op);
+ hr = stream->WriteAsync(tempBuffer.Get(), &op);
RETURN_IF_FAILED("Failed to write to stream", return -1);
UINT32 bytesWritten;
hr = QWinRTFunctions::await(op, &bytesWritten);
@@ -141,20 +101,6 @@ public:
void close()
{
m_shuttingDown = true;
- if (Q_UNLIKELY(m_initialReadOp)) {
- onReadyRead(m_initialReadOp.Get(), Canceled);
- ComPtr<IAsyncInfo> info;
- HRESULT hr = m_initialReadOp.As(&info);
- Q_ASSERT_SUCCEEDED(hr);
- if (info) {
- hr = info->Cancel();
- Q_ASSERT_SUCCEEDED(hr);
- hr = info->Close();
- Q_ASSERT_SUCCEEDED(hr);
- }
- m_initialReadOp.Reset();
- }
-
if (m_readOp) {
onReadyRead(m_readOp.Get(), Canceled);
ComPtr<IAsyncInfo> info;
@@ -171,14 +117,13 @@ public:
}
signals:
- void newDataReceived(const QVector<QByteArray> &data);
+ void newDataReceived(const QList<QByteArray> &data);
void socketErrorOccured(QBluetoothSocket::SocketError error);
public slots:
Q_INVOKABLE void notifyAboutNewData()
{
- QMutexLocker locker(&m_mutex);
- const QVector<QByteArray> newData = std::move(m_pendingData);
+ const QList<QByteArray> newData = std::move(m_pendingData);
m_pendingData.clear();
emit newDataReceived(newData);
}
@@ -186,21 +131,22 @@ public slots:
public:
void startReading()
{
- HRESULT hr;
- hr = QEventDispatcherWinRT::runOnXamlThread([this]()
- {
- ComPtr<IBuffer> buffer;
- HRESULT hr = g->bufferFactory->Create(READ_BUFFER_SIZE, &buffer);
- Q_ASSERT_SUCCEEDED(hr);
- ComPtr<IInputStream> stream;
- hr = m_socket->get_InputStream(&stream);
- Q_ASSERT_SUCCEEDED(hr);
- hr = stream->ReadAsync(buffer.Get(), READ_BUFFER_SIZE, InputStreamOptions_Partial, m_initialReadOp.GetAddressOf());
- Q_ASSERT_SUCCEEDED(hr);
- hr = m_initialReadOp->put_Completed(Callback<SocketReadCompletedHandler>(this, &SocketWorker::onReadyRead).Get());
- Q_ASSERT_SUCCEEDED(hr);
- return S_OK;
- });
+ ComPtr<IBuffer> tempBuffer;
+ HRESULT hr = g->bufferFactory->Create(READ_BUFFER_SIZE, &tempBuffer);
+ Q_ASSERT_SUCCEEDED(hr);
+ ComPtr<IInputStream> stream;
+ hr = m_socket->get_InputStream(&stream);
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = stream->ReadAsync(tempBuffer.Get(), READ_BUFFER_SIZE, InputStreamOptions_Partial, m_readOp.GetAddressOf());
+ Q_ASSERT_SUCCEEDED(hr);
+ QPointer<SocketWorker> thisPtr(this);
+ hr = m_readOp->put_Completed(
+ Callback<SocketReadCompletedHandler>([thisPtr](IAsyncBufferOperation *asyncInfo,
+ AsyncStatus status) {
+ if (thisPtr)
+ return thisPtr->onReadyRead(asyncInfo, status);
+ return S_OK;
+ }).Get());
Q_ASSERT_SUCCEEDED(hr);
}
@@ -209,35 +155,32 @@ public:
if (m_shuttingDown)
return S_OK;
- if (asyncInfo == m_initialReadOp.Get()) {
- m_initialReadOp.Reset();
- } else if (asyncInfo == m_readOp.Get()) {
+ if (asyncInfo == m_readOp.Get())
m_readOp.Reset();
- } else {
+ else
Q_ASSERT(false);
- }
// A read in UnconnectedState will close the socket and return -1 and thus tell the caller,
// that the connection was closed. The socket cannot be closed here, as the subsequent read
// might fail then.
if (status == Error || status == Canceled) {
- emit socketErrorOccured(QBluetoothSocket::NetworkError);
+ emit socketErrorOccured(QBluetoothSocket::SocketError::NetworkError);
return S_OK;
}
- ComPtr<IBuffer> buffer;
- HRESULT hr = asyncInfo->GetResults(&buffer);
+ ComPtr<IBuffer> tempBuffer;
+ HRESULT hr = asyncInfo->GetResults(&tempBuffer);
if (FAILED(hr)) {
qErrnoWarning(hr, "Failed to get read results buffer");
- emit socketErrorOccured(QBluetoothSocket::UnknownSocketError);
+ emit socketErrorOccured(QBluetoothSocket::SocketError::UnknownSocketError);
return S_OK;
}
UINT32 bufferLength;
- hr = buffer->get_Length(&bufferLength);
+ hr = tempBuffer->get_Length(&bufferLength);
if (FAILED(hr)) {
qErrnoWarning(hr, "Failed to get buffer length");
- emit socketErrorOccured(QBluetoothSocket::UnknownSocketError);
+ emit socketErrorOccured(QBluetoothSocket::SocketError::UnknownSocketError);
return S_OK;
}
// A zero sized buffer length signals, that the remote host closed the connection. The socket
@@ -245,71 +188,72 @@ public:
// the closing of the socket won't be communicated to the caller. So only the error is set. The
// actual socket close happens inside of read.
if (!bufferLength) {
- emit socketErrorOccured(QBluetoothSocket::RemoteHostClosedError);
+ emit socketErrorOccured(QBluetoothSocket::SocketError::RemoteHostClosedError);
return S_OK;
}
ComPtr<Windows::Storage::Streams::IBufferByteAccess> byteArrayAccess;
- hr = buffer.As(&byteArrayAccess);
+ hr = tempBuffer.As(&byteArrayAccess);
if (FAILED(hr)) {
qErrnoWarning(hr, "Failed to get cast buffer");
- emit socketErrorOccured(QBluetoothSocket::UnknownSocketError);
+ emit socketErrorOccured(QBluetoothSocket::SocketError::UnknownSocketError);
return S_OK;
}
byte *data;
hr = byteArrayAccess->Buffer(&data);
if (FAILED(hr)) {
qErrnoWarning(hr, "Failed to access buffer data");
- emit socketErrorOccured(QBluetoothSocket::UnknownSocketError);
+ emit socketErrorOccured(QBluetoothSocket::SocketError::UnknownSocketError);
return S_OK;
}
QByteArray newData(reinterpret_cast<const char*>(data), int(bufferLength));
- QMutexLocker readLocker(&m_mutex);
if (m_pendingData.isEmpty())
QMetaObject::invokeMethod(this, "notifyAboutNewData", Qt::QueuedConnection);
m_pendingData << newData;
- readLocker.unlock();
-
- hr = QEventDispatcherWinRT::runOnXamlThread([buffer, this]() {
- UINT32 readBufferLength;
- ComPtr<IInputStream> stream;
- HRESULT hr = m_socket->get_InputStream(&stream);
- if (FAILED(hr)) {
- qErrnoWarning(hr, "Failed to obtain input stream");
- emit socketErrorOccured(QBluetoothSocket::UnknownSocketError);
- return S_OK;
- }
- // Reuse the stream buffer
- hr = buffer->get_Capacity(&readBufferLength);
- if (FAILED(hr)) {
- qErrnoWarning(hr, "Failed to get buffer capacity");
- emit socketErrorOccured(QBluetoothSocket::UnknownSocketError);
- return S_OK;
- }
- hr = buffer->put_Length(0);
- if (FAILED(hr)) {
- qErrnoWarning(hr, "Failed to set buffer length");
- emit socketErrorOccured(QBluetoothSocket::UnknownSocketError);
- return S_OK;
- }
+ UINT32 readBufferLength;
+ ComPtr<IInputStream> stream;
+ hr = m_socket->get_InputStream(&stream);
+ if (FAILED(hr)) {
+ qErrnoWarning(hr, "Failed to obtain input stream");
+ emit socketErrorOccured(QBluetoothSocket::SocketError::UnknownSocketError);
+ return S_OK;
+ }
- hr = stream->ReadAsync(buffer.Get(), readBufferLength, InputStreamOptions_Partial, &m_readOp);
- if (FAILED(hr)) {
- qErrnoWarning(hr, "onReadyRead(): Could not read into socket stream buffer.");
- emit socketErrorOccured(QBluetoothSocket::UnknownSocketError);
- return S_OK;
- }
- hr = m_readOp->put_Completed(Callback<SocketReadCompletedHandler>(this, &SocketWorker::onReadyRead).Get());
- if (FAILED(hr)) {
- qErrnoWarning(hr, "onReadyRead(): Failed to set socket read callback.");
- emit socketErrorOccured(QBluetoothSocket::UnknownSocketError);
- return S_OK;
- }
+ // Reuse the stream buffer
+ hr = tempBuffer->get_Capacity(&readBufferLength);
+ if (FAILED(hr)) {
+ qErrnoWarning(hr, "Failed to get buffer capacity");
+ emit socketErrorOccured(QBluetoothSocket::SocketError::UnknownSocketError);
return S_OK;
- });
- Q_ASSERT_SUCCEEDED(hr);
+ }
+ hr = tempBuffer->put_Length(0);
+ if (FAILED(hr)) {
+ qErrnoWarning(hr, "Failed to set buffer length");
+ emit socketErrorOccured(QBluetoothSocket::SocketError::UnknownSocketError);
+ return S_OK;
+ }
+
+ hr = stream->ReadAsync(tempBuffer.Get(), readBufferLength, InputStreamOptions_Partial, &m_readOp);
+ if (FAILED(hr)) {
+ qErrnoWarning(hr, "onReadyRead(): Could not read into socket stream buffer.");
+ emit socketErrorOccured(QBluetoothSocket::SocketError::UnknownSocketError);
+ return S_OK;
+ }
+ QPointer<SocketWorker> thisPtr(this);
+ hr = m_readOp->put_Completed(
+ Callback<SocketReadCompletedHandler>([thisPtr](IAsyncBufferOperation *asyncInfo,
+ AsyncStatus status) {
+ if (thisPtr)
+ return thisPtr->onReadyRead(asyncInfo, status);
+ return S_OK;
+ }).Get());
+ if (FAILED(hr)) {
+ qErrnoWarning(hr, "onReadyRead(): Failed to set socket read callback.");
+ emit socketErrorOccured(QBluetoothSocket::SocketError::UnknownSocketError);
+ return S_OK;
+ }
return S_OK;
}
@@ -317,20 +261,17 @@ public:
private:
ComPtr<IStreamSocket> m_socket;
- QVector<QByteArray> m_pendingData;
+ QList<QByteArray> m_pendingData;
bool m_shuttingDown = false;
- // Protects pendingData/pendingDatagrams which are accessed from native callbacks
- QMutex m_mutex;
-
- ComPtr<IAsyncOperationWithProgress<IBuffer *, UINT32>> m_initialReadOp;
ComPtr<IAsyncOperationWithProgress<IBuffer *, UINT32>> m_readOp;
};
QBluetoothSocketPrivateWinRT::QBluetoothSocketPrivateWinRT()
: m_worker(new SocketWorker())
{
- secFlags = QBluetooth::NoSecurity;
+ mainThreadCoInit(this);
+ secFlags = QBluetooth::Security::NoSecurity;
connect(m_worker, &SocketWorker::newDataReceived,
this, &QBluetoothSocketPrivateWinRT::handleNewData, Qt::QueuedConnection);
connect(m_worker, &SocketWorker::socketErrorOccured,
@@ -340,6 +281,7 @@ QBluetoothSocketPrivateWinRT::QBluetoothSocketPrivateWinRT()
QBluetoothSocketPrivateWinRT::~QBluetoothSocketPrivateWinRT()
{
abort();
+ mainThreadCoUninit(this);
}
bool QBluetoothSocketPrivateWinRT::ensureNativeSocket(QBluetoothServiceInfo::Protocol type)
@@ -374,7 +316,7 @@ void QBluetoothSocketPrivateWinRT::connectToService(Microsoft::WRL::ComPtr<IHost
if (socket == -1 && !ensureNativeSocket(socketType)) {
errorString = QBluetoothSocket::tr("Unknown socket error");
- q->setSocketError(QBluetoothSocket::UnknownSocketError);
+ q->setSocketError(QBluetoothSocket::SocketError::UnknownSocketError);
return;
}
@@ -384,21 +326,17 @@ void QBluetoothSocketPrivateWinRT::connectToService(Microsoft::WRL::ComPtr<IHost
if (hr == E_ACCESSDENIED) {
qErrnoWarning(hr, "QBluetoothSocketPrivateWinRT::connectToService: Unable to connect to bluetooth socket."
"Please check your manifest capabilities.");
- q->setSocketState(QBluetoothSocket::UnconnectedState);
+ q->setSocketState(QBluetoothSocket::SocketState::UnconnectedState);
return;
}
Q_ASSERT_SUCCEEDED(hr);
- q->setSocketState(QBluetoothSocket::ConnectingState);
+ q->setSocketState(QBluetoothSocket::SocketState::ConnectingState);
requestedOpenMode = openMode;
- hr = QEventDispatcherWinRT::runOnXamlThread([this]() {
- HRESULT hr;
- hr = m_connectOp->put_Completed(Callback<IAsyncActionCompletedHandler>(
- this, &QBluetoothSocketPrivateWinRT::handleConnectOpFinished).Get());
- RETURN_HR_IF_FAILED("connectToHostByName: Could not register \"connectOp\" callback");
- return S_OK;
- });
- Q_ASSERT_SUCCEEDED(hr);
+ hr = m_connectOp->put_Completed(Callback<IAsyncActionCompletedHandler>(
+ this, &QBluetoothSocketPrivateWinRT::handleConnectOpFinished).Get());
+ RETURN_VOID_IF_FAILED("connectToHostByName: Could not register \"connectOp\" callback");
+ return;
}
void QBluetoothSocketPrivateWinRT::connectToServiceHelper(const QBluetoothAddress &address, quint16 port, QIODevice::OpenMode openMode)
@@ -407,7 +345,7 @@ void QBluetoothSocketPrivateWinRT::connectToServiceHelper(const QBluetoothAddres
if (socket == -1 && !ensureNativeSocket(socketType)) {
errorString = QBluetoothSocket::tr("Unknown socket error");
- q->setSocketError(QBluetoothSocket::UnknownSocketError);
+ q->setSocketError(QBluetoothSocket::SocketError::UnknownSocketError);
return;
}
@@ -429,11 +367,11 @@ void QBluetoothSocketPrivateWinRT::connectToService(
{
Q_Q(QBluetoothSocket);
- if (q->state() != QBluetoothSocket::UnconnectedState
- && q->state() != QBluetoothSocket::ServiceLookupState) {
- qCWarning(QT_BT_WINRT) << "QBluetoothSocket::connectToService called on busy socket";
+ if (q->state() != QBluetoothSocket::SocketState::UnconnectedState
+ && q->state() != QBluetoothSocket::SocketState::ServiceLookupState) {
+ qCWarning(QT_BT_WINDOWS) << "QBluetoothSocket::connectToService called on busy socket";
errorString = QBluetoothSocket::tr("Trying to connect while connection is in progress");
- q->setSocketError(QBluetoothSocket::OperationError);
+ q->setSocketError(QBluetoothSocket::SocketError::OperationError);
return;
}
@@ -441,7 +379,7 @@ void QBluetoothSocketPrivateWinRT::connectToService(
// socketType will change in ensureNativeSocket()
if (service.socketProtocol() != QBluetoothServiceInfo::RfcommProtocol) {
errorString = QBluetoothSocket::tr("Socket type not supported");
- q->setSocketError(QBluetoothSocket::UnsupportedProtocolError);
+ q->setSocketError(QBluetoothSocket::SocketError::UnsupportedProtocolError);
return;
}
@@ -452,7 +390,7 @@ void QBluetoothSocketPrivateWinRT::connectToService(
if (!ensureNativeSocket(QBluetoothServiceInfo::L2capProtocol)) {
errorString = QBluetoothSocket::tr("Unknown socket error");
- q->setSocketError(QBluetoothSocket::UnknownSocketError);
+ q->setSocketError(QBluetoothSocket::SocketError::UnknownSocketError);
return;
}
connectToServiceHelper(service.device().address(),
@@ -461,7 +399,7 @@ void QBluetoothSocketPrivateWinRT::connectToService(
Q_ASSERT(service.socketProtocol() == QBluetoothServiceInfo::RfcommProtocol);
if (!ensureNativeSocket(QBluetoothServiceInfo::RfcommProtocol)) {
errorString = QBluetoothSocket::tr("Unknown socket error");
- q->setSocketError(QBluetoothSocket::UnknownSocketError);
+ q->setSocketError(QBluetoothSocket::SocketError::UnknownSocketError);
return;
}
HStringReference hostNameRef(reinterpret_cast<LPCWSTR>(connectionHostName.utf16()));
@@ -477,7 +415,7 @@ void QBluetoothSocketPrivateWinRT::connectToService(
if (!ensureNativeSocket(QBluetoothServiceInfo::RfcommProtocol)) {
errorString = QBluetoothSocket::tr("Unknown socket error");
- q->setSocketError(QBluetoothSocket::UnknownSocketError);
+ q->setSocketError(QBluetoothSocket::SocketError::UnknownSocketError);
return;
}
connectToServiceHelper(service.device().address(), quint16(service.serverChannel()),
@@ -485,11 +423,11 @@ void QBluetoothSocketPrivateWinRT::connectToService(
} else {
// try doing service discovery to see if we can find the socket
if (service.serviceUuid().isNull()
- && !service.serviceClassUuids().contains(QBluetoothUuid::SerialPort)) {
- qCWarning(QT_BT_WINRT) << "No port, no PSM, and no UUID provided. Unable to connect";
+ && !service.serviceClassUuids().contains(QBluetoothUuid::ServiceClassUuid::SerialPort)) {
+ qCWarning(QT_BT_WINDOWS) << "No port, no PSM, and no UUID provided. Unable to connect";
return;
}
- qCDebug(QT_BT_WINRT) << "Need a port/psm, doing discovery";
+ qCDebug(QT_BT_WINDOWS) << "Need a port/psm, doing discovery";
q->doDeviceDiscovery(service, openMode);
}
}
@@ -499,16 +437,16 @@ void QBluetoothSocketPrivateWinRT::connectToService(
{
Q_Q(QBluetoothSocket);
- if (q->state() != QBluetoothSocket::UnconnectedState) {
- qCWarning(QT_BT_WINRT) << "QBluetoothSocketPrivateWinRT::connectToService called on busy socket";
+ if (q->state() != QBluetoothSocket::SocketState::UnconnectedState) {
+ qCWarning(QT_BT_WINDOWS) << "QBluetoothSocketPrivateWinRT::connectToService called on busy socket";
errorString = QBluetoothSocket::tr("Trying to connect while connection is in progress");
- q->setSocketError(QBluetoothSocket::OperationError);
+ q->setSocketError(QBluetoothSocket::SocketError::OperationError);
return;
}
if (q->socketType() != QBluetoothServiceInfo::RfcommProtocol) {
errorString = QBluetoothSocket::tr("Socket type not supported");
- q->setSocketError(QBluetoothSocket::UnsupportedProtocolError);
+ q->setSocketError(QBluetoothSocket::SocketError::UnsupportedProtocolError);
return;
}
@@ -524,16 +462,16 @@ void QBluetoothSocketPrivateWinRT::connectToService(
{
Q_Q(QBluetoothSocket);
- if (q->state() != QBluetoothSocket::UnconnectedState) {
- qCWarning(QT_BT_WINRT) << "QBluetoothSocketPrivateWinRT::connectToService called on busy socket";
+ if (q->state() != QBluetoothSocket::SocketState::UnconnectedState) {
+ qCWarning(QT_BT_WINDOWS) << "QBluetoothSocketPrivateWinRT::connectToService called on busy socket";
errorString = QBluetoothSocket::tr("Trying to connect while connection is in progress");
- q->setSocketError(QBluetoothSocket::OperationError);
+ q->setSocketError(QBluetoothSocket::SocketError::OperationError);
return;
}
if (q->socketType() != QBluetoothServiceInfo::RfcommProtocol) {
errorString = QBluetoothSocket::tr("Socket type not supported");
- q->setSocketError(QBluetoothSocket::UnsupportedProtocolError);
+ q->setSocketError(QBluetoothSocket::SocketError::UnsupportedProtocolError);
return;
}
@@ -543,7 +481,7 @@ void QBluetoothSocketPrivateWinRT::connectToService(
void QBluetoothSocketPrivateWinRT::abort()
{
Q_Q(QBluetoothSocket);
- if (state == QBluetoothSocket::UnconnectedState)
+ if (state == QBluetoothSocket::SocketState::UnconnectedState)
return;
disconnect(m_worker, &SocketWorker::newDataReceived,
@@ -558,8 +496,8 @@ void QBluetoothSocketPrivateWinRT::abort()
socket = -1;
}
- const bool wasConnected = q->state() == QBluetoothSocket::ConnectedState;
- q->setSocketState(QBluetoothSocket::UnconnectedState);
+ const bool wasConnected = q->state() == QBluetoothSocket::SocketState::ConnectedState;
+ q->setSocketState(QBluetoothSocket::SocketState::UnconnectedState);
if (wasConnected) {
q->setOpenMode(QIODevice::NotOpen);
emit q->readChannelFinished();
@@ -576,6 +514,17 @@ QString QBluetoothSocketPrivateWinRT::localName() const
return device.name();
}
+static QString fromWinApiAddress(HString address)
+{
+ // WinAPI returns address with parentheses around it. We need to remove
+ // them to convert to QBluetoothAddress.
+ QString addressStr(qt_QStringFromHString(address));
+ if (addressStr.startsWith(QLatin1Char('(')) && addressStr.endsWith(QLatin1Char(')'))) {
+ addressStr = addressStr.sliced(1, addressStr.size() - 2);
+ }
+ return addressStr;
+}
+
QBluetoothAddress QBluetoothSocketPrivateWinRT::localAddress() const
{
if (!m_socketObject)
@@ -588,10 +537,13 @@ QBluetoothAddress QBluetoothSocketPrivateWinRT::localAddress() const
ComPtr<IHostName> localHost;
hr = info->get_LocalAddress(&localHost);
Q_ASSERT_SUCCEEDED(hr);
- HString localAddress;
- hr = localHost->get_CanonicalName(localAddress.GetAddressOf());
- Q_ASSERT_SUCCEEDED(hr);
- return QBluetoothAddress(qt_QStringFromHString(localAddress));
+ if (localHost) {
+ HString localAddress;
+ hr = localHost->get_CanonicalName(localAddress.GetAddressOf());
+ Q_ASSERT_SUCCEEDED(hr);
+ return QBluetoothAddress(fromWinApiAddress(std::move(localAddress)));
+ }
+ return QBluetoothAddress();
}
quint16 QBluetoothSocketPrivateWinRT::localPort() const
@@ -609,7 +561,7 @@ quint16 QBluetoothSocketPrivateWinRT::localPort() const
bool ok = true;
const uint port = qt_QStringFromHString(localPortString).toUInt(&ok);
if (!ok || port > UINT16_MAX) {
- qCWarning(QT_BT_WINRT) << "Unexpected local port";
+ qCWarning(QT_BT_WINDOWS) << "Unexpected local port";
return 0;
}
return quint16(port);
@@ -627,10 +579,13 @@ QString QBluetoothSocketPrivateWinRT::peerName() const
ComPtr<IHostName> remoteHost;
hr = info->get_RemoteHostName(&remoteHost);
Q_ASSERT_SUCCEEDED(hr);
- HString remoteHostName;
- hr = remoteHost->get_DisplayName(remoteHostName.GetAddressOf());
- Q_ASSERT_SUCCEEDED(hr);
- return qt_QStringFromHString(remoteHostName);
+ if (remoteHost) {
+ HString remoteHostName;
+ hr = remoteHost->get_DisplayName(remoteHostName.GetAddressOf());
+ Q_ASSERT_SUCCEEDED(hr);
+ return qt_QStringFromHString(remoteHostName);
+ }
+ return {};
}
QBluetoothAddress QBluetoothSocketPrivateWinRT::peerAddress() const
@@ -645,10 +600,13 @@ QBluetoothAddress QBluetoothSocketPrivateWinRT::peerAddress() const
ComPtr<IHostName> remoteHost;
hr = info->get_RemoteAddress(&remoteHost);
Q_ASSERT_SUCCEEDED(hr);
- HString remoteAddress;
- hr = remoteHost->get_CanonicalName(remoteAddress.GetAddressOf());
- Q_ASSERT_SUCCEEDED(hr);
- return QBluetoothAddress(qt_QStringFromHString(remoteAddress));
+ if (remoteHost) {
+ HString remoteAddress;
+ hr = remoteHost->get_CanonicalName(remoteAddress.GetAddressOf());
+ Q_ASSERT_SUCCEEDED(hr);
+ return QBluetoothAddress(fromWinApiAddress(std::move(remoteAddress)));
+ }
+ return QBluetoothAddress();
}
quint16 QBluetoothSocketPrivateWinRT::peerPort() const
@@ -661,12 +619,12 @@ quint16 QBluetoothSocketPrivateWinRT::peerPort() const
hr = m_socketObject->get_Information(&info);
Q_ASSERT_SUCCEEDED(hr);
HString remotePortString;
- hr = info->get_LocalPort(remotePortString.GetAddressOf());
+ hr = info->get_RemotePort(remotePortString.GetAddressOf());
Q_ASSERT_SUCCEEDED(hr);
bool ok = true;
const uint port = qt_QStringFromHString(remotePortString).toUInt(&ok);
if (!ok || port > UINT16_MAX) {
- qCWarning(QT_BT_WINRT) << "Unexpected remote port";
+ qCWarning(QT_BT_WINDOWS) << "Unexpected remote port";
return 0;
}
return quint16(port);
@@ -676,9 +634,9 @@ qint64 QBluetoothSocketPrivateWinRT::writeData(const char *data, qint64 maxSize)
{
Q_Q(QBluetoothSocket);
- if (state != QBluetoothSocket::ConnectedState) {
+ if (state != QBluetoothSocket::SocketState::ConnectedState) {
errorString = QBluetoothSocket::tr("Cannot write while not connected");
- q->setSocketError(QBluetoothSocket::OperationError);
+ q->setSocketError(QBluetoothSocket::SocketError::OperationError);
return -1;
}
@@ -689,9 +647,9 @@ qint64 QBluetoothSocketPrivateWinRT::writeData(const char *data, qint64 maxSize)
qint64 bytesWritten = writeIOStream(stream, data, maxSize);
if (bytesWritten < 0) {
- qCWarning(QT_BT_WINRT) << "Socket::writeData: " << state;
+ qCWarning(QT_BT_WINDOWS) << "Socket::writeData: " << state;
errorString = QBluetoothSocket::tr("Cannot read while not connected");
- q->setSocketError(QBluetoothSocket::OperationError);
+ q->setSocketError(QBluetoothSocket::SocketError::OperationError);
}
emit q->bytesWritten(bytesWritten);
@@ -702,16 +660,16 @@ qint64 QBluetoothSocketPrivateWinRT::readData(char *data, qint64 maxSize)
{
Q_Q(QBluetoothSocket);
- if (state != QBluetoothSocket::ConnectedState) {
+ if (state != QBluetoothSocket::SocketState::ConnectedState) {
errorString = QBluetoothSocket::tr("Cannot read while not connected");
- q->setSocketError(QBluetoothSocket::OperationError);
+ q->setSocketError(QBluetoothSocket::SocketError::OperationError);
return -1;
}
- if (!buffer.isEmpty()) {
+ if (!rxBuffer.isEmpty()) {
if (maxSize > INT_MAX)
maxSize = INT_MAX;
- return buffer.read(data, int(maxSize));
+ return rxBuffer.read(data, int(maxSize));
}
return 0;
@@ -726,10 +684,10 @@ bool QBluetoothSocketPrivateWinRT::setSocketDescriptor(int socketDescriptor, QBl
QBluetoothSocket::SocketState socketState, QBluetoothSocket::OpenMode openMode)
{
Q_UNUSED(socketDescriptor);
- Q_UNUSED(socketType)
+ Q_UNUSED(socketType);
Q_UNUSED(socketState);
Q_UNUSED(openMode);
- qCWarning(QT_BT_WINRT) << "No socket descriptor support on WinRT.";
+ qCWarning(QT_BT_WINDOWS) << "No socket descriptor support on WinRT.";
return false;
}
@@ -744,15 +702,16 @@ bool QBluetoothSocketPrivateWinRT::setSocketDescriptor(ComPtr<IStreamSocket> soc
socket = qintptr(m_socketObject.Get());
m_worker->setSocket(m_socketObject);
q->setSocketState(socketState);
- if (socketState == QBluetoothSocket::ConnectedState)
+ if (socketState == QBluetoothSocket::SocketState::ConnectedState)
m_worker->startReading();
- q->setOpenMode(openMode);
+ // QBluetoothSockets are unbuffered on Windows
+ q->setOpenMode(openMode | QIODevice::Unbuffered);
return true;
}
qint64 QBluetoothSocketPrivateWinRT::bytesAvailable() const
{
- return buffer.size();
+ return rxBuffer.size();
}
qint64 QBluetoothSocketPrivateWinRT::bytesToWrite() const
@@ -762,25 +721,25 @@ qint64 QBluetoothSocketPrivateWinRT::bytesToWrite() const
bool QBluetoothSocketPrivateWinRT::canReadLine() const
{
- return buffer.canReadLine();
+ return rxBuffer.canReadLine();
}
-void QBluetoothSocketPrivateWinRT::handleNewData(const QVector<QByteArray> &data)
+void QBluetoothSocketPrivateWinRT::handleNewData(const QList<QByteArray> &data)
{
// Defer putting the data into the list until the next event loop iteration
// (where the readyRead signal is emitted as well)
QMetaObject::invokeMethod(this, "addToPendingData", Qt::QueuedConnection,
- Q_ARG(QVector<QByteArray>, data));
+ Q_ARG(QList<QByteArray>, data));
}
void QBluetoothSocketPrivateWinRT::handleError(QBluetoothSocket::SocketError error)
{
Q_Q(QBluetoothSocket);
switch (error) {
- case QBluetoothSocket::NetworkError:
+ case QBluetoothSocket::SocketError::NetworkError:
errorString = QBluetoothSocket::tr("Network error");
break;
- case QBluetoothSocket::RemoteHostClosedError:
+ case QBluetoothSocket::SocketError::RemoteHostClosedError:
errorString = QBluetoothSocket::tr("Remote host closed connection");
break;
default:
@@ -788,21 +747,21 @@ void QBluetoothSocketPrivateWinRT::handleError(QBluetoothSocket::SocketError err
}
q->setSocketError(error);
- const bool wasConnected = q->state() == QBluetoothSocket::ConnectedState;
- q->setSocketState(QBluetoothSocket::UnconnectedState);
+ const bool wasConnected = q->state() == QBluetoothSocket::SocketState::ConnectedState;
+ q->setSocketState(QBluetoothSocket::SocketState::UnconnectedState);
if (wasConnected) {
q->setOpenMode(QIODevice::NotOpen);
emit q->readChannelFinished();
}
}
-void QBluetoothSocketPrivateWinRT::addToPendingData(const QVector<QByteArray> &data)
+void QBluetoothSocketPrivateWinRT::addToPendingData(const QList<QByteArray> &data)
{
Q_Q(QBluetoothSocket);
QMutexLocker locker(&m_readMutex);
m_pendingData.append(data);
for (const QByteArray &newData : data) {
- char *writePointer = buffer.reserve(newData.length());
+ char *writePointer = rxBuffer.reserve(newData.length());
memcpy(writePointer, newData.data(), size_t(newData.length()));
}
locker.unlock();
@@ -814,8 +773,8 @@ HRESULT QBluetoothSocketPrivateWinRT::handleConnectOpFinished(ABI::Windows::Foun
Q_Q(QBluetoothSocket);
if (status != Completed || !m_connectOp) { // Protect against a late callback
errorString = QBluetoothSocket::tr("Unknown socket error");
- q->setSocketError(QBluetoothSocket::UnknownSocketError);
- q->setSocketState(QBluetoothSocket::UnconnectedState);
+ q->setSocketError(QBluetoothSocket::SocketError::UnknownSocketError);
+ q->setSocketState(QBluetoothSocket::SocketState::UnconnectedState);
return S_OK;
}
@@ -826,26 +785,26 @@ HRESULT QBluetoothSocketPrivateWinRT::handleConnectOpFinished(ABI::Windows::Foun
// period of time, or established connection failed because connected host has failed to respond.
case HRESULT_FROM_WIN32(WSAETIMEDOUT):
errorString = QBluetoothSocket::tr("Connection timed out");
- q->setSocketError(QBluetoothSocket::NetworkError);
- q->setSocketState(QBluetoothSocket::UnconnectedState);
+ q->setSocketError(QBluetoothSocket::SocketError::NetworkError);
+ q->setSocketState(QBluetoothSocket::SocketState::UnconnectedState);
return S_OK;
// A socket operation was attempted to an unreachable host.
case HRESULT_FROM_WIN32(WSAEHOSTUNREACH):
errorString = QBluetoothSocket::tr("Host not reachable");
- q->setSocketError(QBluetoothSocket::HostNotFoundError);
- q->setSocketState(QBluetoothSocket::UnconnectedState);
+ q->setSocketError(QBluetoothSocket::SocketError::HostNotFoundError);
+ q->setSocketState(QBluetoothSocket::SocketState::UnconnectedState);
return S_OK;
// No connection could be made because the target machine actively refused it.
case HRESULT_FROM_WIN32(WSAECONNREFUSED):
errorString = QBluetoothSocket::tr("Host refused connection");
- q->setSocketError(QBluetoothSocket::HostNotFoundError);
- q->setSocketState(QBluetoothSocket::UnconnectedState);
+ q->setSocketError(QBluetoothSocket::SocketError::HostNotFoundError);
+ q->setSocketState(QBluetoothSocket::SocketState::UnconnectedState);
return S_OK;
default:
if (FAILED(hr)) {
errorString = QBluetoothSocket::tr("Unknown socket error");
- q->setSocketError(QBluetoothSocket::UnknownSocketError);
- q->setSocketState(QBluetoothSocket::UnconnectedState);
+ q->setSocketError(QBluetoothSocket::SocketError::UnknownSocketError);
+ q->setSocketState(QBluetoothSocket::SocketState::UnconnectedState);
return S_OK;
}
}
@@ -864,8 +823,9 @@ HRESULT QBluetoothSocketPrivateWinRT::handleConnectOpFinished(ABI::Windows::Foun
m_connectOp.Reset();
}
- q->setOpenMode(requestedOpenMode);
- q->setSocketState(QBluetoothSocket::ConnectedState);
+ // QBluetoothSockets are unbuffered on Windows
+ q->setOpenMode(requestedOpenMode | QIODevice::Unbuffered);
+ q->setSocketState(QBluetoothSocket::SocketState::ConnectedState);
m_worker->startReading();
return S_OK;
diff --git a/src/bluetooth/qbluetoothsocket_winrt_p.h b/src/bluetooth/qbluetoothsocket_winrt_p.h
index de8b7d67..4ba6c4ff 100644
--- a/src/bluetooth/qbluetoothsocket_winrt_p.h
+++ b/src/bluetooth/qbluetoothsocket_winrt_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QBLUETOOTHSOCKET_WINRT_P_H
#define QBLUETOOTHSOCKET_WINRT_P_H
@@ -110,11 +74,11 @@ public:
bool setSocketDescriptor(Microsoft::WRL::ComPtr<ABI::Windows::Networking::Sockets::IStreamSocket> socket,
QBluetoothServiceInfo::Protocol socketType,
- QBluetoothSocket::SocketState socketState = QBluetoothSocket::ConnectedState,
+ QBluetoothSocket::SocketState socketState = QBluetoothSocket::SocketState::ConnectedState,
QBluetoothSocket::OpenMode openMode = QBluetoothSocket::ReadWrite) override;
bool setSocketDescriptor(int socketDescriptor, QBluetoothServiceInfo::Protocol socketType,
- QBluetoothSocket::SocketState socketState = QBluetoothSocket::ConnectedState,
+ QBluetoothSocket::SocketState socketState = QBluetoothSocket::SocketState::ConnectedState,
QBluetoothSocket::OpenMode openMode = QBluetoothSocket::ReadWrite) override;
qint64 bytesAvailable() const override;
@@ -129,12 +93,12 @@ public:
QMutex m_readMutex;
// Protected by m_readMutex. Written in addToPendingData (native callback)
- QVector<QByteArray> m_pendingData;
+ QList<QByteArray> m_pendingData;
- Q_INVOKABLE void addToPendingData(const QVector<QByteArray> &data);
+ Q_INVOKABLE void addToPendingData(const QList<QByteArray> &data);
private slots:
- void handleNewData(const QVector<QByteArray> &data);
+ void handleNewData(const QList<QByteArray> &data);
void handleError(QBluetoothSocket::SocketError error);
private:
diff --git a/src/bluetooth/qbluetoothsocketbase.cpp b/src/bluetooth/qbluetoothsocketbase.cpp
index 8401a1c3..35cb595c 100644
--- a/src/bluetooth/qbluetoothsocketbase.cpp
+++ b/src/bluetooth/qbluetoothsocketbase.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qbluetoothsocketbase_p.h"
@@ -52,3 +16,5 @@ QBluetoothSocketBasePrivate::~QBluetoothSocketBasePrivate()
}
QT_END_NAMESPACE
+
+#include "moc_qbluetoothsocketbase_p.cpp"
diff --git a/src/bluetooth/qbluetoothsocketbase_p.h b/src/bluetooth/qbluetoothsocketbase_p.h
index d1894e96..3b94cea2 100644
--- a/src/bluetooth/qbluetoothsocketbase_p.h
+++ b/src/bluetooth/qbluetoothsocketbase_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QBLUETOOTHSOCKETBASEPRIVATE_P_H
#define QBLUETOOTHSOCKETBASEPRIVATE_P_H
@@ -56,7 +20,7 @@
#include <QtBluetooth/qbluetoothsocket.h>
#if defined(QT_ANDROID_BLUETOOTH)
-#include <QtAndroidExtras/QAndroidJniObject>
+#include <QtCore/QJniObject>
#endif
#if defined(QT_WINRT_BLUETOOTH)
@@ -118,7 +82,7 @@ public:
virtual qint64 bytesToWrite() const = 0;
virtual bool setSocketDescriptor(int socketDescriptor, QBluetoothServiceInfo::Protocol socketType,
- QBluetoothSocket::SocketState socketState = QBluetoothSocket::ConnectedState,
+ QBluetoothSocket::SocketState socketState = QBluetoothSocket::SocketState::ConnectedState,
QBluetoothSocket::OpenMode openMode = QBluetoothSocket::ReadWrite) = 0;
@@ -137,23 +101,23 @@ public:
QIODevice::OpenMode openMode) = 0;
#ifdef QT_ANDROID_BLUETOOTH
- virtual bool setSocketDescriptor(const QAndroidJniObject &socket, QBluetoothServiceInfo::Protocol socketType,
- QBluetoothSocket::SocketState socketState = QBluetoothSocket::ConnectedState,
+ virtual bool setSocketDescriptor(const QJniObject &socket, QBluetoothServiceInfo::Protocol socketType,
+ QBluetoothSocket::SocketState socketState = QBluetoothSocket::SocketState::ConnectedState,
QBluetoothSocket::OpenMode openMode = QBluetoothSocket::ReadWrite) = 0;
#elif defined(QT_WINRT_BLUETOOTH)
virtual bool setSocketDescriptor(Microsoft::WRL::ComPtr<ABI::Windows::Networking::Sockets::IStreamSocket> socket,
QBluetoothServiceInfo::Protocol socketType,
- QBluetoothSocket::SocketState socketState = QBluetoothSocket::ConnectedState,
+ QBluetoothSocket::SocketState socketState = QBluetoothSocket::SocketState::ConnectedState,
QBluetoothSocket::OpenMode openMode = QBluetoothSocket::ReadWrite) = 0;
#endif
public:
- QPrivateLinearBuffer buffer;
+ QPrivateLinearBuffer rxBuffer;
QPrivateLinearBuffer txBuffer;
int socket = -1;
QBluetoothServiceInfo::Protocol socketType = QBluetoothServiceInfo::UnknownProtocol;
- QBluetoothSocket::SocketState state = QBluetoothSocket::UnconnectedState;
- QBluetoothSocket::SocketError socketError = QBluetoothSocket::NoSocketError;
+ QBluetoothSocket::SocketState state = QBluetoothSocket::SocketState::UnconnectedState;
+ QBluetoothSocket::SocketError socketError = QBluetoothSocket::SocketError::NoSocketError;
QSocketNotifier *readNotifier = nullptr;
QSocketNotifier *connectWriteNotifier = nullptr;
bool connecting = false;
diff --git a/src/bluetooth/qbluetoothtransfermanager.cpp b/src/bluetooth/qbluetoothtransfermanager.cpp
deleted file mode 100644
index 53798e55..00000000
--- a/src/bluetooth/qbluetoothtransfermanager.cpp
+++ /dev/null
@@ -1,136 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qbluetoothtransfermanager.h"
-#include "qbluetoothtransferrequest.h"
-#include "qbluetoothtransferreply.h"
-#if QT_CONFIG(bluez)
-#include "qbluetoothtransferreply_bluez_p.h"
-#elif QT_OSX_BLUETOOTH
-#include "qbluetoothtransferreply_macos_p.h"
-#else
-#if !defined(QT_ANDROID_BLUETOOTH) && !defined(QT_IOS_BLUETOOTH)
-#include "dummy/dummy_helper_p.h"
-#endif
-#endif
-
-QT_BEGIN_NAMESPACE
-
-/*!
- \class QBluetoothTransferManager
- \inmodule QtBluetooth
- \brief The QBluetoothTransferManager class transfers data to another device
- using Object Push Profile (OPP).
-
- \since 5.2
-
- QBluetoothTransferManager uses OBEX to send put commands to remote devices. A typical
- OBEX transfer is initialized as follows:
-
- \snippet doc_src_qtbluetooth.cpp sendfile
-
- Note that this API is not currently supported on Android.
-*/
-
-/*!
- \fn QBluetoothTransferReply *QBluetoothTransferManager::put(const QBluetoothTransferRequest &request, QIODevice *data)
-
- Sends the contents of \a data to the remote device identified by \a request, and returns a new
- QBluetoothTransferReply that can be used to track the request's progress. \a data must remain valid
- until the \l finished() signal is emitted.
-
- The returned \l QBluetoothTransferReply object must be immediately checked for its
- \l {QBluetoothTransferReply::error()}{error()} state. This is required in case
- this function detects an error during the initialization of the
- \l QBluetoothTransferReply. In such cases \l {QBluetoothTransferReply::isFinished()} returns
- \c true as well.
-
- If the platform does not support the Object Push profile, this function will return \c 0.
-*/
-
-
-
-/*!
- \fn void QBluetoothTransferManager::finished(QBluetoothTransferReply *reply)
-
- This signal is emitted when the transfer for \a reply finishes.
-*/
-
-/*!
- Constructs a new QBluetoothTransferManager with \a parent.
-*/
-QBluetoothTransferManager::QBluetoothTransferManager(QObject *parent)
-: QObject(parent)
-{
- qRegisterMetaType<QBluetoothTransferReply*>();
- qRegisterMetaType<QBluetoothTransferReply::TransferError>();
-}
-
-/*!
- Destroys the QBluetoothTransferManager.
-*/
-QBluetoothTransferManager::~QBluetoothTransferManager()
-{
-}
-
-QBluetoothTransferReply *QBluetoothTransferManager::put(const QBluetoothTransferRequest &request,
- QIODevice *data)
-{
-#if QT_CONFIG(bluez)
- QBluetoothTransferReplyBluez *rep = new QBluetoothTransferReplyBluez(data, request, this);
- connect(rep, SIGNAL(finished(QBluetoothTransferReply*)), this, SIGNAL(finished(QBluetoothTransferReply*)));
- return rep;
-#elif QT_OSX_BLUETOOTH
- QBluetoothTransferReply *reply = new QBluetoothTransferReplyOSX(data, request, this);
- connect(reply, SIGNAL(finished(QBluetoothTransferReply*)), this, SIGNAL(finished(QBluetoothTransferReply*)));
- return reply;
-#else
- // Android, iOS, and Win/WinRT have no implementation
-#if !defined(QT_ANDROID_BLUETOOTH) && !defined(QT_IOS_BLUETOOTH) && !defined(QT_WINRT_BLUETOOTH) && !defined(QT_WIN_BLUETOOTH)
- printDummyWarning();
-#endif
- Q_UNUSED(request);
- Q_UNUSED(data);
- return 0;
-#endif
-}
-
-QT_END_NAMESPACE
-
-#include "moc_qbluetoothtransfermanager.cpp"
diff --git a/src/bluetooth/qbluetoothtransfermanager.h b/src/bluetooth/qbluetoothtransfermanager.h
deleted file mode 100644
index 98850392..00000000
--- a/src/bluetooth/qbluetoothtransfermanager.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QBLUETOOTHTRANSFERMANAGER_H
-#define QBLUETOOTHTRANSFERMANAGER_H
-
-#include <QtBluetooth/qtbluetoothglobal.h>
-#include <QtBluetooth/QBluetoothAddress>
-
-#include <QtCore/QObject>
-
-QT_FORWARD_DECLARE_CLASS(QIODevice)
-
-QT_BEGIN_NAMESPACE
-
-class QBluetoothTransferReply;
-class QBluetoothTransferRequest;
-class QBluetoothTranferManagerPrivate;
-
-class Q_BLUETOOTH_EXPORT QBluetoothTransferManager : public QObject
-{
- Q_OBJECT
-
-public:
- explicit QBluetoothTransferManager(QObject *parent = nullptr);
- ~QBluetoothTransferManager();
-
- QBluetoothTransferReply *put(const QBluetoothTransferRequest &request, QIODevice *data);
-
-Q_SIGNALS:
- void finished(QBluetoothTransferReply *reply);
-
-};
-
-QT_END_NAMESPACE
-
-#endif // QBLUETOOTHTRANSFERMANAGER_H
diff --git a/src/bluetooth/qbluetoothtransferreply.cpp b/src/bluetooth/qbluetoothtransferreply.cpp
deleted file mode 100644
index a5da8f8f..00000000
--- a/src/bluetooth/qbluetoothtransferreply.cpp
+++ /dev/null
@@ -1,214 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qbluetoothtransferreply.h"
-#include "qbluetoothtransferreply_p.h"
-#include "qbluetoothaddress.h"
-
-QT_BEGIN_NAMESPACE
-
-/*!
- \class QBluetoothTransferReply
- \inmodule QtBluetooth
- \brief The QBluetoothTransferReply class stores the response for a data
- transfer request.
-
- \since 5.2
-
- In additional to a copy of the QBluetoothTransferRequest object used to create the request,
- QBluetoothTransferReply contains the contents of the reply itself.
-
- After the file transfer has started, QBluetoothTransferReply emits the transferProgress() signal,
- which indicates the progress of the file transfer.
-*/
-
-/*!
- \enum QBluetoothTransferReply::TransferError
-
- This enum describes the type of error that occurred
-
- \value NoError No error.
- \value UnknownError Unknown error, no better enum available.
- \value FileNotFoundError Unable to open the file specified.
- \value HostNotFoundError Unable to connect to the target host.
- \value UserCanceledTransferError User terminated the transfer.
- \value IODeviceNotReadableError File was not open before initiating the sending command.
- \value ResourceBusyError Unable to access the resource..
- \value SessionError An error occurred during the handling of the session. This enum was
- introduced by Qt 5.4.
-*/
-
-
-
-/*!
- \fn QBluetoothTransferReply::abort()
-
- Aborts this reply.
-*/
-void QBluetoothTransferReply::abort()
-{
-}
-
-/*!
- \fn void QBluetoothTransferReply::finished(QBluetoothTransferReply *reply)
-
- This signal is emitted when the transfer is complete for \a reply.
-
- To avoid the loss of signal emissions it is recommend to immidiately connect
- to this signal once a \c QBluetoothTransferReply instance has been created.
-*/
-
-/*!
- \fn void QBluetoothTransferReply::transferProgress(qint64 bytesTransferred, qint64 bytesTotal)
-
- This signal is emitted whenever data is transferred. The \a bytesTransferred parameter contains the total
- number of bytes transferred so far out of \a bytesTotal.
-
-
- To avoid the loss of signal emissions it is recommend to immidiately connect
- to this signal once a QBluetoothTransferReply instance has been created.
-*/
-
-/*!
- \fn void QBluetoothTransferReply::error(QBluetoothTransferReply::TransferError errorType)
- \since 5.4
-
- This signal is emitted whenever an error has occurred. The \a errorType
- parameter indicates the type of error.
-
- To avoid the loss of signal emissions it is recommend to immidiately connect
- to this signal once a QBluetoothTransferReply instance has been created.
-
- \sa error(), errorString()
-*/
-
-/*!
- Constructs a new QBluetoothTransferReply with \a parent.
-*/
-QBluetoothTransferReply::QBluetoothTransferReply(QObject *parent)
- : QObject(parent), d_ptr(new QBluetoothTransferReplyPrivate())
-{
-}
-
-/*!
- Destroys the QBluetoothTransferReply object.
-*/
-QBluetoothTransferReply::~QBluetoothTransferReply()
-{
- delete d_ptr;
-}
-
-/*!
- \fn bool QBluetoothTransferReply::isFinished() const
-
- Returns true if this reply has finished, otherwise false.
-*/
-
-/*!
- \fn bool QBluetoothTransferReply::isRunning() const
-
- Returns true if this reply is running, otherwise false.
-*/
-
-/*!
- Returns the QBluetoothTransferManager that was used to create this QBluetoothTransferReply
- object. Initially, it is also the parent object.
-*/
-QBluetoothTransferManager *QBluetoothTransferReply::manager() const
-{
- Q_D(const QBluetoothTransferReply);
- return d->m_manager;
-}
-
-/*!
- Returns the QBluetoothTransferRequest that was used to create this QBluetoothTransferReply
- object.
-*/
-QBluetoothTransferRequest QBluetoothTransferReply::request() const
-{
- Q_D(const QBluetoothTransferReply);
- return d->m_request;
-}
-
-/*!
- \fn QBluetoothTransferReply::setManager(QBluetoothTransferManager *manager)
-
- Set the reply's manager to the \a manager.
-*/
-
-void QBluetoothTransferReply::setManager(QBluetoothTransferManager *manager)
-{
- Q_D(QBluetoothTransferReply);
- d->m_manager = manager;
-}
-
-/*!
- \fn QBluetoothTransferReply::setRequest(const QBluetoothTransferRequest &request)
-
- Set the reply's request to \a request.
-*/
-void QBluetoothTransferReply::setRequest(const QBluetoothTransferRequest &request)
-{
- Q_D(QBluetoothTransferReply);
- d->m_request = request;
-}
-
-/*!
- \fn TransferError QBluetoothTransferReply::error() const
-
- The error code of the error that occurred.
-
- \sa errorString()
-*/
-
-/*!
- \fn QString QBluetoothTransferReply::errorString() const
-
- String describing the error. Can be displayed to the user.
-
- \sa error()
-*/
-
-QBluetoothTransferReplyPrivate::QBluetoothTransferReplyPrivate()
-{
-}
-
-QT_END_NAMESPACE
-
-#include "moc_qbluetoothtransferreply.cpp"
diff --git a/src/bluetooth/qbluetoothtransferreply.h b/src/bluetooth/qbluetoothtransferreply.h
deleted file mode 100644
index 8f0679f5..00000000
--- a/src/bluetooth/qbluetoothtransferreply.h
+++ /dev/null
@@ -1,107 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QBLUETOOTHTRANSFERREPLY_H
-#define QBLUETOOTHTRANSFERREPLY_H
-
-#include <QtCore/QIODevice>
-
-#include <QtBluetooth/QBluetoothTransferRequest>
-#include <QtBluetooth/QBluetoothTransferManager>
-
-QT_BEGIN_NAMESPACE
-
-class QBluetoothTransferReplyPrivate;
-
-class Q_BLUETOOTH_EXPORT QBluetoothTransferReply : public QObject
-{
- Q_OBJECT
-
-public:
- enum TransferError {
- NoError = 0,
- UnknownError,
- FileNotFoundError,
- HostNotFoundError,
- UserCanceledTransferError,
- IODeviceNotReadableError,
- ResourceBusyError,
- SessionError
- };
- Q_ENUM(TransferError)
-
- ~QBluetoothTransferReply();
-
- virtual bool isFinished() const = 0;
- virtual bool isRunning() const = 0;
-
- QBluetoothTransferManager *manager() const;
-
- virtual TransferError error() const = 0;
- virtual QString errorString() const = 0;
-
- QBluetoothTransferRequest request() const;
-
-public Q_SLOTS:
- void abort();
-
-Q_SIGNALS:
- //TODO Remove QBluetoothTransferReply* parameter in Qt 6
- void finished(QBluetoothTransferReply *);
- void transferProgress(qint64 bytesTransferred, qint64 bytesTotal);
- void error(QBluetoothTransferReply::TransferError lastError);
-
-protected:
- explicit QBluetoothTransferReply(QObject *parent = nullptr);
- void setManager(QBluetoothTransferManager *manager);
- void setRequest(const QBluetoothTransferRequest &request);
-
-protected:
- QBluetoothTransferReplyPrivate *d_ptr;
-
-private:
- Q_DECLARE_PRIVATE(QBluetoothTransferReply)
-
-};
-
-QT_END_NAMESPACE
-
-Q_DECLARE_METATYPE(QBluetoothTransferReply::TransferError)
-
-#endif // QBLUETOOTHTRANSFERREPLY_H
diff --git a/src/bluetooth/qbluetoothtransferreply_bluez.cpp b/src/bluetooth/qbluetoothtransferreply_bluez.cpp
deleted file mode 100644
index 486e6288..00000000
--- a/src/bluetooth/qbluetoothtransferreply_bluez.cpp
+++ /dev/null
@@ -1,474 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-
-#include "qbluetoothtransferreply_bluez_p.h"
-#include "qbluetoothaddress.h"
-
-#include "bluez/obex_client_p.h"
-#include "bluez/obex_agent_p.h"
-#include "bluez/obex_transfer_p.h"
-#include "bluez/bluez5_helper_p.h"
-#include "bluez/obex_client1_bluez5_p.h"
-#include "bluez/obex_objectpush1_bluez5_p.h"
-#include "bluez/obex_transfer1_bluez5_p.h"
-#include "bluez/properties_p.h"
-#include "qbluetoothtransferreply.h"
-
-#include <QtCore/QAtomicInt>
-#include <QtCore/QLoggingCategory>
-#include <QtCore/QVector>
-#include <QFuture>
-#include <QFutureWatcher>
-#include <QtConcurrentRun>
-
-static const QLatin1String agentPath("/qt/agent");
-static QAtomicInt agentPathCounter;
-
-QT_BEGIN_NAMESPACE
-
-Q_DECLARE_LOGGING_CATEGORY(QT_BT_BLUEZ)
-
-QBluetoothTransferReplyBluez::QBluetoothTransferReplyBluez(QIODevice *input, const QBluetoothTransferRequest &request,
- QBluetoothTransferManager *parent)
-: QBluetoothTransferReply(parent),
- m_source(input),
- m_running(false), m_finished(false), m_size(0),
- m_error(QBluetoothTransferReply::NoError), m_errorStr(), m_transfer_path()
-{
- setRequest(request);
- setManager(parent);
-
- if (!input) {
- qCWarning(QT_BT_BLUEZ) << "Invalid input device (null)";
- m_errorStr = QBluetoothTransferReply::tr("Invalid input device (null)");
- m_error = QBluetoothTransferReply::FileNotFoundError;
- m_finished = true;
- return;
- }
-
- if (isBluez5()) {
- m_clientBluez = new OrgBluezObexClient1Interface(QStringLiteral("org.bluez.obex"),
- QStringLiteral("/org/bluez/obex"),
- QDBusConnection::sessionBus(), this);
-
-
- } else {
- m_client = new OrgOpenobexClientInterface(QStringLiteral("org.openobex.client"),
- QStringLiteral("/"),
- QDBusConnection::sessionBus());
-
- m_agent_path = agentPath;
- m_agent_path.append(QStringLiteral("/%1%2/%3").
- arg(sanitizeNameForDBus(QCoreApplication::applicationName())).
- arg(QCoreApplication::applicationPid()).
- arg(agentPathCounter.fetchAndAddOrdered(1)));
-
- m_agent = new AgentAdaptor(this);
-
- if (!QDBusConnection::sessionBus().registerObject(m_agent_path, this))
- qCWarning(QT_BT_BLUEZ) << "Failed creating obex agent dbus objects";
- }
-
- QMetaObject::invokeMethod(this, "start", Qt::QueuedConnection);
- m_running = true;
-}
-
-/*!
- Destroys the QBluetoothTransferReply object.
-*/
-QBluetoothTransferReplyBluez::~QBluetoothTransferReplyBluez()
-{
- QDBusConnection::sessionBus().unregisterObject(m_agent_path);
- delete m_client;
-}
-
-bool QBluetoothTransferReplyBluez::start()
-{
- QFile *file = qobject_cast<QFile *>(m_source);
-
- if(!file){
- m_tempfile = new QTemporaryFile(this );
- m_tempfile->open();
- qCDebug(QT_BT_BLUEZ) << "Not a QFile, making a copy" << m_tempfile->fileName();
- if (!m_source->isReadable()) {
- m_errorStr = QBluetoothTransferReply::tr("QIODevice cannot be read. "
- "Make sure it is open for reading.");
- m_error = QBluetoothTransferReply::IODeviceNotReadableError;
- m_finished = true;
- m_running = false;
-
- emit QBluetoothTransferReply::error(m_error);
- emit finished(this);
- return false;
- }
-
- QFutureWatcher<bool> *watcher = new QFutureWatcher<bool>();
- QObject::connect(watcher, SIGNAL(finished()), this, SLOT(copyDone()));
-
- QFuture<bool> results = QtConcurrent::run(QBluetoothTransferReplyBluez::copyToTempFile, m_tempfile, m_source);
- watcher->setFuture(results);
- }
- else {
- if (!file->exists()) {
- m_errorStr = QBluetoothTransferReply::tr("Source file does not exist");
- m_error = QBluetoothTransferReply::FileNotFoundError;
- m_finished = true;
- m_running = false;
-
- emit QBluetoothTransferReply::error(m_error);
- emit finished(this);
- return false;
- }
- if (request().address().isNull()) {
- m_errorStr = QBluetoothTransferReply::tr("Invalid target address");
- m_error = QBluetoothTransferReply::HostNotFoundError;
- m_finished = true;
- m_running = false;
-
- emit QBluetoothTransferReply::error(m_error);
- emit finished(this);
- return false;
- }
- m_size = file->size();
- startOPP(file->fileName());
- }
- return true;
-}
-
-bool QBluetoothTransferReplyBluez::copyToTempFile(QIODevice *to, QIODevice *from)
-{
- QVector<char> block(4096);
- int size;
-
- while ((size = from->read(block.data(), block.size())) > 0) {
- if (size != to->write(block.data(), size)) {
- return false;
- }
- }
-
- return true;
-}
-
-void QBluetoothTransferReplyBluez::cleanupSession()
-{
- if (!m_objectPushBluez)
- return;
-
- QDBusPendingReply<> reply = m_clientBluez->RemoveSession(QDBusObjectPath(m_objectPushBluez->path()));
- reply.waitForFinished();
- if (reply.isError())
- qCWarning(QT_BT_BLUEZ) << "Abort: Cannot remove obex session";
-
- delete m_objectPushBluez;
- m_objectPushBluez = nullptr;
-}
-
-void QBluetoothTransferReplyBluez::copyDone()
-{
- m_size = m_tempfile->size();
- startOPP(m_tempfile->fileName());
- QObject::sender()->deleteLater();
-}
-
-void QBluetoothTransferReplyBluez::sessionCreated(QDBusPendingCallWatcher *watcher)
-{
- QDBusPendingReply<QDBusObjectPath> reply = *watcher;
- if (reply.isError()) {
- qCWarning(QT_BT_BLUEZ) << "Failed to create obex session:"
- << reply.error().name() << reply.reply().errorMessage();
-
- m_errorStr = QBluetoothTransferReply::tr("Invalid target address");
- m_error = QBluetoothTransferReply::HostNotFoundError;
- m_finished = true;
- m_running = false;
-
- emit QBluetoothTransferReply::error(m_error);
- emit finished(this);
-
- watcher->deleteLater();
- return;
- }
-
- m_objectPushBluez = new OrgBluezObexObjectPush1Interface(QStringLiteral("org.bluez.obex"),
- reply.value().path(),
- QDBusConnection::sessionBus(), this);
- QDBusPendingReply<QDBusObjectPath, QVariantMap> newReply = m_objectPushBluez->SendFile(fileToTranser);
- QDBusPendingCallWatcher *newWatcher = new QDBusPendingCallWatcher(newReply, this);
- connect(newWatcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
- SLOT(sessionStarted(QDBusPendingCallWatcher*)));
- watcher->deleteLater();
-}
-
-void QBluetoothTransferReplyBluez::sessionStarted(QDBusPendingCallWatcher *watcher)
-{
- QDBusPendingReply<QDBusObjectPath, QVariantMap> reply = *watcher;
- if (reply.isError()) {
- qCWarning(QT_BT_BLUEZ) << "Failed to start obex session:"
- << reply.error().name() << reply.reply().errorMessage();
-
- m_errorStr = QBluetoothTransferReply::tr("Push session cannot be started");
- m_error = QBluetoothTransferReply::SessionError;
- m_finished = true;
- m_running = false;
-
- cleanupSession();
-
- emit QBluetoothTransferReply::error(m_error);
- emit finished(this);
-
- watcher->deleteLater();
- return;
- }
-
- const QDBusObjectPath path = reply.argumentAt<0>();
- const QVariantMap map = reply.argumentAt<1>();
- m_transfer_path = path.path();
-
- //watch the transfer
- OrgFreedesktopDBusPropertiesInterface *properties = new OrgFreedesktopDBusPropertiesInterface(
- QStringLiteral("org.bluez.obex"), path.path(),
- QDBusConnection::sessionBus(), this);
- connect(properties, SIGNAL(PropertiesChanged(QString,QVariantMap,QStringList)),
- SLOT(sessionChanged(QString,QVariantMap,QStringList)));
-
- watcher->deleteLater();
-}
-
-void QBluetoothTransferReplyBluez::sessionChanged(const QString &interface,
- const QVariantMap &changed_properties,
- const QStringList &)
-{
- if (changed_properties.contains(QStringLiteral("Transferred"))) {
- emit transferProgress(
- changed_properties.value(QStringLiteral("Transferred")).toULongLong(),
- m_size);
- }
-
- if (changed_properties.contains(QStringLiteral("Status"))) {
- const QString s = changed_properties.
- value(QStringLiteral("Status")).toString();
- if (s == QStringLiteral("complete")
- || s == QStringLiteral("error")) {
-
- m_transfer_path.clear();
- m_finished = true;
- m_running = false;
-
- if (s == QStringLiteral("error")) {
- m_error = QBluetoothTransferReply::UnknownError;
- m_errorStr = tr("Unknown Error");
-
- emit QBluetoothTransferReply::error(m_error);
- } else { // complete
- // allow progress bar to complete
- emit transferProgress(m_size, m_size);
- }
-
- cleanupSession();
-
- emit finished(this);
- } // ignore "active", "queued" & "suspended" status
- }
- qCDebug(QT_BT_BLUEZ) << "Transfer update:" << interface << changed_properties;
-}
-
-void QBluetoothTransferReplyBluez::startOPP(const QString &filename)
-{
- if (m_client) { // Bluez 4
- QVariantMap device;
- QStringList files;
-
- device.insert(QStringLiteral("Destination"), request().address().toString());
- files << filename;
-
- QDBusObjectPath path(m_agent_path);
- QDBusPendingReply<> sendReply = m_client->SendFiles(device, files, path);
-
- QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(sendReply, this);
- connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
- this, SLOT(sendReturned(QDBusPendingCallWatcher*)));
- } else { //Bluez 5
- fileToTranser = filename;
- QVariantMap mapping;
- mapping.insert(QStringLiteral("Target"), QStringLiteral("opp"));
-
- QDBusPendingReply<QDBusObjectPath> reply = m_clientBluez->CreateSession(
- request().address().toString(), mapping);
-
- QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this);
- connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
- SLOT(sessionCreated(QDBusPendingCallWatcher*)));
- }
-}
-
-void QBluetoothTransferReplyBluez::sendReturned(QDBusPendingCallWatcher *watcher)
-{
- QDBusPendingReply<> sendReply = *watcher;
- if(sendReply.isError()){
- m_finished = true;
- m_running = false;
- m_errorStr = sendReply.error().message();
- if (m_errorStr == QStringLiteral("Could not open file for sending")) {
- m_error = QBluetoothTransferReply::FileNotFoundError;
- m_errorStr = tr("Could not open file for sending");
- } else if (m_errorStr == QStringLiteral("The transfer was canceled")) {
- m_error = QBluetoothTransferReply::UserCanceledTransferError;
- m_errorStr = tr("The transfer was canceled");
- } else {
- m_error = QBluetoothTransferReply::UnknownError;
- }
-
- emit QBluetoothTransferReply::error(m_error);
- emit finished(this);
- }
-}
-
-QBluetoothTransferReply::TransferError QBluetoothTransferReplyBluez::error() const
-{
- return m_error;
-}
-
-QString QBluetoothTransferReplyBluez::errorString() const
-{
- return m_errorStr;
-}
-
-void QBluetoothTransferReplyBluez::Complete(const QDBusObjectPath &in0)
-{
- Q_UNUSED(in0);
- m_transfer_path.clear();
- m_finished = true;
- m_running = false;
-}
-
-void QBluetoothTransferReplyBluez::Error(const QDBusObjectPath &in0, const QString &in1)
-{
- Q_UNUSED(in0);
- m_transfer_path.clear();
- m_finished = true;
- m_running = false;
- m_errorStr = in1;
- if (in1 == QStringLiteral("Could not open file for sending")) {
- m_error = QBluetoothTransferReply::FileNotFoundError;
- m_errorStr = tr("Could not open file for sending");
- } else if (in1 == QStringLiteral("Operation canceled")) {
- m_error = QBluetoothTransferReply::UserCanceledTransferError;
- m_errorStr = QBluetoothTransferReply::tr("Operation canceled");
- } else {
- m_error = QBluetoothTransferReply::UnknownError;
- }
-
- emit QBluetoothTransferReply::error(m_error);
- emit finished(this);
-}
-
-void QBluetoothTransferReplyBluez::Progress(const QDBusObjectPath &in0, qulonglong in1)
-{
- Q_UNUSED(in0);
- emit transferProgress(in1, m_size);
-}
-
-void QBluetoothTransferReplyBluez::Release()
-{
- if(m_errorStr.isEmpty())
- emit finished(this);
-}
-
-QString QBluetoothTransferReplyBluez::Request(const QDBusObjectPath &in0)
-{
- m_transfer_path = in0.path();
-
- return QString();
-}
-
-/*!
- Returns true if this reply has finished; otherwise returns false.
-*/
-bool QBluetoothTransferReplyBluez::isFinished() const
-{
- return m_finished;
-}
-
-/*!
- Returns true if this reply is running; otherwise returns false.
-*/
-bool QBluetoothTransferReplyBluez::isRunning() const
-{
- return m_running;
-}
-
-void QBluetoothTransferReplyBluez::abort()
-{
- if (m_transfer_path.isEmpty())
- return;
-
- if (m_client) {
- OrgOpenobexTransferInterface xfer(QStringLiteral("org.openobex.client"),
- m_transfer_path,
- QDBusConnection::sessionBus());
-
- QDBusPendingReply<> reply = xfer.Cancel();
- reply.waitForFinished();
- if (reply.isError())
- qCWarning(QT_BT_BLUEZ) << "Failed to abort transfer" << reply.error().message();
-
- } else if (m_clientBluez) {
- OrgBluezObexTransfer1Interface iface(QStringLiteral("org.bluez.obex"),
- m_transfer_path,
- QDBusConnection::sessionBus());
-
- QDBusPendingReply<> reply = iface.Cancel();
- reply.waitForFinished();
- if (reply.isError())
- qCDebug(QT_BT_BLUEZ) << "Failed to abort transfer" << reply.error().message();
-
- m_error = QBluetoothTransferReply::UserCanceledTransferError;
- m_errorStr = tr("Operation canceled");
-
- cleanupSession();
-
- emit QBluetoothTransferReply::error(m_error);
- emit finished(this);
- }
-}
-
-#include "moc_qbluetoothtransferreply_bluez_p.cpp"
-
-QT_END_NAMESPACE
diff --git a/src/bluetooth/qbluetoothtransferreply_bluez_p.h b/src/bluetooth/qbluetoothtransferreply_bluez_p.h
deleted file mode 100644
index 48a8d4f0..00000000
--- a/src/bluetooth/qbluetoothtransferreply_bluez_p.h
+++ /dev/null
@@ -1,136 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QBLUETOOTHTRANSFERREPLY_BLUEZ_P_H
-#define QBLUETOOTHTRANSFERREPLY_BLUEZ_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <QtCore/QIODevice>
-#include <QtDBus/QtDBus>
-
-#include <QtBluetooth/QBluetoothTransferRequest>
-#include <QtBluetooth/QBluetoothTransferManager>
-
-#include "qbluetoothtransferreply.h"
-
-class OrgOpenobexClientInterface;
-class AgentAdaptor;
-class OrgBluezObexClient1Interface;
-class OrgBluezObexObjectPush1Interface;
-
-QT_BEGIN_NAMESPACE
-
-class Q_BLUETOOTH_EXPORT QBluetoothTransferReplyBluez : public QBluetoothTransferReply
-{
- Q_OBJECT
-
-public:
- explicit QBluetoothTransferReplyBluez(QIODevice *input, const QBluetoothTransferRequest &request,
- QBluetoothTransferManager *parent = nullptr);
- ~QBluetoothTransferReplyBluez();
-
- bool isFinished() const;
- bool isRunning() const;
-
- QBluetoothTransferReply::TransferError error() const;
- QString errorString() const;
-
-private slots:
- bool start();
-
-private:
- void startOPP(const QString &filename);
-
- OrgOpenobexClientInterface *m_client = nullptr;
- AgentAdaptor *m_agent = nullptr;
- OrgBluezObexClient1Interface *m_clientBluez = nullptr;
- OrgBluezObexObjectPush1Interface *m_objectPushBluez = nullptr;
-
-
- QTemporaryFile *m_tempfile = nullptr;
- QIODevice *m_source = nullptr;
-
- bool m_running;
- bool m_finished;
-
- quint64 m_size;
-
- QBluetoothTransferReply::TransferError m_error;
- QString m_errorStr;
-
- QString m_agent_path;
-
- QString m_transfer_path;
- QString fileToTranser;
-
- static bool copyToTempFile(QIODevice *to, QIODevice *from);
- void cleanupSession();
-
-private slots:
- void copyDone();
- void sessionCreated(QDBusPendingCallWatcher *watcher);
- void sessionStarted(QDBusPendingCallWatcher *watcher);
- void sessionChanged(const QString &interface,
- const QVariantMap &changed_properties,
- const QStringList &invalidated_properties);
-
-public slots:
- void abort();
- void Complete(const QDBusObjectPath &in0);
- void Error(const QDBusObjectPath &in0, const QString &in1);
- void Progress(const QDBusObjectPath &in0, qulonglong in1);
- void Release();
- QString Request(const QDBusObjectPath &in0);
- void sendReturned(QDBusPendingCallWatcher*);
-
-};
-
-QT_END_NAMESPACE
-
-#endif // QBLUETOOTHTRANSFERREPLY_H
diff --git a/src/bluetooth/qbluetoothtransferreply_macos.mm b/src/bluetooth/qbluetoothtransferreply_macos.mm
deleted file mode 100644
index d05396b9..00000000
--- a/src/bluetooth/qbluetoothtransferreply_macos.mm
+++ /dev/null
@@ -1,480 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qbluetoothservicediscoveryagent.h"
-#include "qbluetoothtransferreply_macos_p.h"
-#include "darwin/btobexsession_p.h"
-#include "qbluetoothserviceinfo.h"
-#include "darwin/btutility_p.h"
-#include "darwin/uistrings_p.h"
-#include "qbluetoothuuid.h"
-
-
-#include <QtCore/qcoreapplication.h>
-#include <QtCore/qloggingcategory.h>
-#include <QtCore/qtemporaryfile.h>
-#include <QtCore/qmetaobject.h>
-#include <QtCore/qfileinfo.h>
-#include <QtCore/qstring.h>
-#include <QtCore/qdebug.h>
-#include <QtCore/qfile.h>
-#include <QtCore/qdir.h>
-
-QT_BEGIN_NAMESPACE
-
-class QBluetoothTransferReplyOSXPrivate : DarwinBluetooth::OBEXSessionDelegate
-{
- friend class QBluetoothTransferReplyOSX;
-public:
- QBluetoothTransferReplyOSXPrivate(QBluetoothTransferReplyOSX *q, QIODevice *inputStream);
-
- ~QBluetoothTransferReplyOSXPrivate();
-
- bool isActive() const;
- bool startOPP(const QBluetoothAddress &device);
-
- //
- void sendConnect(const QBluetoothAddress &device, quint16 channelID);
- void sendPut();
-
-private:
- // OBEX session delegate:
- void OBEXConnectError(OBEXError errorCode, OBEXOpCode response) override;
- void OBEXConnectSuccess() override;
-
- void OBEXAbortSuccess() override;
-
- void OBEXPutDataSent(quint32 current, quint32 total) override;
- void OBEXPutSuccess() override;
- void OBEXPutError(OBEXError error, OBEXOpCode response) override;
-
- QBluetoothTransferReplyOSX *q_ptr;
-
- QIODevice *inputStream;
-
- QBluetoothTransferReply::TransferError error;
- QString errorString;
-
- // Set requestComplete, error, description, emit error, emit finished.
- // Too many things in one, but not to repeat this code everywhere.
- void setReplyError(QBluetoothTransferReply::TransferError errorCode,
- const QString &errorMessage);
-
- // With a given API, we have to discover a service first
- // since we need a channel ID to work with OBEX session.
- // Also, service discovery agent does not have an interface
- // to test discovery mode, that's why we have this bool here.
- bool minimalScan;
- QScopedPointer<QBluetoothServiceDiscoveryAgent> agent;
-
- // The next step is to create an OBEX session:
- typedef DarwinBluetooth::ObjCScopedPointer<ObjCOBEXSession> OBEXSession;
- OBEXSession session;
-
- // Both success and failure to send - transfer is complete.
- bool requestComplete;
-
- // We need a temporary file to generate an unique name
- // in case inputStream is not a file. QTemporaryFile not
- // only creates a random name, it also guarantees this name
- // is unique. The amount of code to generate such a name
- // is amaizingly huge (and will require global variables)
- // - so a temporary file can help.
- QScopedPointer<QTemporaryFile> temporaryFile;
-};
-
-QBluetoothTransferReplyOSXPrivate::QBluetoothTransferReplyOSXPrivate(QBluetoothTransferReplyOSX *q,
- QIODevice *input)
- : q_ptr(q),
- inputStream(input),
- error(QBluetoothTransferReply::NoError),
- minimalScan(true),
- requestComplete(false)
-{
- Q_ASSERT_X(q, Q_FUNC_INFO, "invalid q_ptr (null)");
-}
-
-QBluetoothTransferReplyOSXPrivate::~QBluetoothTransferReplyOSXPrivate()
-{
- // closeSession will set a delegate to null.
- // The OBEX session will be closed then. If
- // somehow IOBluetooth/OBEX still has a reference to our
- // session, it will not call any of delegate's callbacks.
- if (session)
- [session closeSession];
-}
-
-bool QBluetoothTransferReplyOSXPrivate::isActive() const
-{
- return agent || (session && [session hasActiveRequest]);
-}
-
-bool QBluetoothTransferReplyOSXPrivate::startOPP(const QBluetoothAddress &device)
-{
- Q_ASSERT_X(!isActive(), Q_FUNC_INFO, "already started");
- Q_ASSERT_X(!device.isNull(), Q_FUNC_INFO, "invalid device address");
-
- errorString.clear();
- error = QBluetoothTransferReply::NoError;
-
- agent.reset(new QBluetoothServiceDiscoveryAgent);
-
- agent->setRemoteAddress(device);
- agent->setUuidFilter(QBluetoothUuid(QBluetoothUuid::ObexObjectPush));
-
- QObject::connect(agent.data(), SIGNAL(finished()), q_ptr, SLOT(serviceDiscoveryFinished()));
- QObject::connect(agent.data(), SIGNAL(error(QBluetoothServiceDiscoveryAgent::Error)),
- q_ptr, SLOT(serviceDiscoveryError(QBluetoothServiceDiscoveryAgent::Error)));
-
- minimalScan = true;
- agent->start(QBluetoothServiceDiscoveryAgent::MinimalDiscovery);
-
- // We probably failed already.
- return error == QBluetoothTransferReply::NoError;
-}
-
-void QBluetoothTransferReplyOSXPrivate::sendConnect(const QBluetoothAddress &device, quint16 channelID)
-{
- using namespace DarwinBluetooth;
-
- Q_ASSERT_X(!session, Q_FUNC_INFO, "session is already active");
-
- error = QBluetoothTransferReply::NoError;
- errorString.clear();
-
- if (device.isNull() || !channelID) {
- qCWarning(QT_BT_DARWIN) << "invalid device address or port";
- setReplyError(QBluetoothTransferReply::HostNotFoundError,
- QCoreApplication::translate(TRANSFER_REPLY, TR_INVAL_TARGET));
- return;
- }
-
- OBEXSession newSession([[ObjCOBEXSession alloc] initWithDelegate:this
- remoteDevice:device channelID:channelID],
- RetainPolicy::noInitialRetain);
- if (!newSession) {
- qCWarning(QT_BT_DARWIN) << "failed to allocate DarwinBTOBEXSession object";
-
- setReplyError(QBluetoothTransferReply::UnknownError,
- QCoreApplication::translate(TRANSFER_REPLY, TR_SESSION_NO_START));
- return;
- }
-
- const OBEXError status = [newSession OBEXConnect];
-
- if ((status == kOBEXSuccess || status == kOBEXSessionAlreadyConnectedError)
- && error == QBluetoothTransferReply::NoError) {
- session.swap(newSession);
- if ([session isConnected])
- sendPut();// Connected, send a PUT request.
- } else {
- qCWarning(QT_BT_DARWIN) << "OBEXConnect failed";
-
- if (error == QBluetoothTransferReply::NoError) {
- // The error is not set yet.
- error = QBluetoothTransferReply::SessionError;
- errorString = QCoreApplication::translate(TRANSFER_REPLY, TR_CONNECT_FAILED);
- }
-
- requestComplete = true;
- emit q_ptr->error(error);
- emit q_ptr->finished(q_ptr);
- }
-}
-
-void QBluetoothTransferReplyOSXPrivate::sendPut()
-{
- Q_ASSERT_X(inputStream, Q_FUNC_INFO, "invalid input stream (null)");
- Q_ASSERT_X(session, Q_FUNC_INFO, "invalid OBEX session (nil)");
- Q_ASSERT_X([session isConnected], Q_FUNC_INFO, "not connected");
- Q_ASSERT_X(![session hasActiveRequest], Q_FUNC_INFO,
- "session already has an active request");
-
- QString fileName;
- QFile *const file = qobject_cast<QFile *>(inputStream);
- if (file) {
- if (!file->exists()) {
- setReplyError(QBluetoothTransferReply::FileNotFoundError,
- QCoreApplication::translate(TRANSFER_REPLY, TR_FILE_NOT_EXIST));
- return;
- } else if (!file->isReadable()) {
- file->open(QIODevice::ReadOnly);
- if (!file->isReadable()) {
- setReplyError(QBluetoothTransferReply::IODeviceNotReadableError,
- QCoreApplication::translate(TRANSFER_REPLY, TR_NOT_READ_IODEVICE));
- return;
- }
- }
-
- fileName = file->fileName();
- } else {
- if (!inputStream->isReadable()) {
- setReplyError(QBluetoothTransferReply::IODeviceNotReadableError,
- QCoreApplication::translate(TRANSFER_REPLY, TR_NOT_READ_IODEVICE));
- return;
- }
-
- temporaryFile.reset(new QTemporaryFile);
- temporaryFile->open();
- fileName = temporaryFile->fileName();
- }
-
- const QFileInfo fileInfo(fileName);
- fileName = fileInfo.fileName();
-
- if ([session OBEXPutFile:inputStream withName:fileName] != kOBEXSuccess) {
- // TODO: convert OBEXError into something reasonable?
- setReplyError(QBluetoothTransferReply::SessionError,
- QCoreApplication::translate(TRANSFER_REPLY, TR_SESSION_FAILED));
- }
-}
-
-
-void QBluetoothTransferReplyOSXPrivate::OBEXConnectError(OBEXError errorCode, OBEXOpCode response)
-{
- Q_UNUSED(errorCode)
- Q_UNUSED(response)
-
- if (session) {
- setReplyError(QBluetoothTransferReply::SessionError,
- QCoreApplication::translate(TRANSFER_REPLY, TR_CONNECT_FAILED));
- } else {
- // Else we're still in OBEXConnect, in a call-back
- // and do not want to emit yet (will be done a bit later).
- error = QBluetoothTransferReply::SessionError;
- errorString = QCoreApplication::translate(TRANSFER_REPLY, TR_CONNECT_FAILED);
- requestComplete = true;
- }
-}
-
-void QBluetoothTransferReplyOSXPrivate::OBEXConnectSuccess()
-{
- // Now that OBEX connect succeeded, we can send an OBEX put request.
- if (!session) {
- // We're still in OBEXConnect(), it'll take care of next steps.
- return;
- }
-
- sendPut();
-}
-
-void QBluetoothTransferReplyOSXPrivate::OBEXAbortSuccess()
-{
- // TODO:
-}
-
-void QBluetoothTransferReplyOSXPrivate::OBEXPutDataSent(quint32 current, quint32 total)
-{
- emit q_ptr->transferProgress(current, total);
-}
-
-void QBluetoothTransferReplyOSXPrivate::OBEXPutSuccess()
-{
- requestComplete = true;
- emit q_ptr->finished(q_ptr);
-}
-
-void QBluetoothTransferReplyOSXPrivate::OBEXPutError(OBEXError errorCode, OBEXOpCode responseCode)
-{
- // Error can be reported by errorCode or responseCode
- // (that's how errors are reported in OBEXSession events).
- // errorCode and responseCode are "mutually exclusive".
-
- Q_UNUSED(responseCode)
-
- if (errorCode != kOBEXSuccess) {
- // TODO: errorCode -> TransferError.
- } else {
- // TODO: a response code can give some interesting information,
- // like "forbidden" etc. - convert this into more reasonable error.
- }
-
- setReplyError(QBluetoothTransferReply::SessionError,
- QCoreApplication::translate(TRANSFER_REPLY, TR_SESSION_FAILED));
-}
-
-void QBluetoothTransferReplyOSXPrivate::setReplyError(QBluetoothTransferReply::TransferError errorCode,
- const QString &description)
-{
- // Not to be used to clear an error!
-
- error = errorCode;
- errorString = description;
- requestComplete = true;
- emit q_ptr->error(error);
- emit q_ptr->finished(q_ptr);
-}
-
-
-QBluetoothTransferReplyOSX::QBluetoothTransferReplyOSX(QIODevice *input,
- const QBluetoothTransferRequest &request,
- QBluetoothTransferManager *manager)
- : QBluetoothTransferReply(manager)
-
-{
- Q_UNUSED(input)
-
- setManager(manager);
- setRequest(request);
-
- osx_d_ptr.reset(new QBluetoothTransferReplyOSXPrivate(this, input));
-
- if (input) {
- QMetaObject::invokeMethod(this, "start", Qt::QueuedConnection);
- } else {
- qCWarning(QT_BT_DARWIN) << "invalid input stream (null)";
- osx_d_ptr->requestComplete = true;
- osx_d_ptr->errorString = QCoreApplication::translate(TRANSFER_REPLY, TR_INVALID_DEVICE);
- osx_d_ptr->error = FileNotFoundError;
- QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection,
- Q_ARG(QBluetoothTransferReply::TransferError, FileNotFoundError));
- }
-}
-
-QBluetoothTransferReplyOSX::~QBluetoothTransferReplyOSX()
-{
- // A dtor to make a scoped pointer with incomplete type happy.
-}
-
-QBluetoothTransferReply::TransferError QBluetoothTransferReplyOSX::error() const
-{
- return osx_d_ptr->error;
-}
-
-QString QBluetoothTransferReplyOSX::errorString() const
-{
- return osx_d_ptr->errorString;
-}
-
-bool QBluetoothTransferReplyOSX::isFinished() const
-{
- return osx_d_ptr->requestComplete;
-}
-
-bool QBluetoothTransferReplyOSX::isRunning() const
-{
- return osx_d_ptr->isActive();
-}
-
-bool QBluetoothTransferReplyOSX::abort()
-{
- // Reset a delegate.
- [osx_d_ptr->session closeSession];
- // Should never be called from an OBEX callback!
- osx_d_ptr->session.reset();
-
- // Not setReplyError, we emit finished only!
- osx_d_ptr->requestComplete = true;
- osx_d_ptr->errorString = QCoreApplication::translate(TRANSFER_REPLY, TR_OP_CANCEL);
- osx_d_ptr->error = UserCanceledTransferError;
-
- emit finished(this);
-
- return true;
-}
-
-bool QBluetoothTransferReplyOSX::start()
-{
- // OBEXSession requires a channel ID and we have to find it first,
- // using QBluetoothServiceDiscoveryAgent (singleDevice, OBEX uuid filter, start
- // from MinimalDiscovery mode and continue with FullDiscovery if
- // MinimalDiscovery fails.
-
- if (!osx_d_ptr->isActive()) {
- // Step 0: find a channelID.
- if (request().address().isNull()) {
- qCWarning(QT_BT_DARWIN) << "invalid device address";
- osx_d_ptr->setReplyError(HostNotFoundError,
- QCoreApplication::translate(TRANSFER_REPLY, TR_INVAL_TARGET));
- return false;
- }
-
- return osx_d_ptr->startOPP(request().address());
- } else {
- osx_d_ptr->setReplyError(UnknownError,
- QCoreApplication::translate(TRANSFER_REPLY, TR_IN_PROGRESS));
- return false;
- }
-}
-
-void QBluetoothTransferReplyOSX::serviceDiscoveryFinished()
-{
- Q_ASSERT_X(osx_d_ptr->agent.data(), Q_FUNC_INFO,
- "invalid service discovery agent (null)");
-
- const QList<QBluetoothServiceInfo> services = osx_d_ptr->agent->discoveredServices();
- if (services.size()) {
- // TODO: what if we have several?
- const QBluetoothServiceInfo &foundOBEX = services.front();
- osx_d_ptr->sendConnect(request().address(), foundOBEX.serverChannel());
- } else {
- if (osx_d_ptr->minimalScan) {
- // Try full discovery now.
- osx_d_ptr->minimalScan = false;
- osx_d_ptr->agent->start(QBluetoothServiceDiscoveryAgent::FullDiscovery);
- } else {
- // No service record, no channel ID, no OBEX session.
- osx_d_ptr->setReplyError(HostNotFoundError,
- QCoreApplication::translate(TRANSFER_REPLY, TR_SERVICE_NO_FOUND));
- }
- }
-}
-
-void QBluetoothTransferReplyOSX::serviceDiscoveryError(QBluetoothServiceDiscoveryAgent::Error errorCode)
-{
- Q_ASSERT_X(osx_d_ptr->agent.data(), Q_FUNC_INFO,
- "invalid service discovery agent (null)");
-
- if (errorCode == QBluetoothServiceDiscoveryAgent::PoweredOffError) {
- // There's nothing else we can do.
- osx_d_ptr->setReplyError(UnknownError,
- QCoreApplication::translate(DEV_DISCOVERY, DD_POWERED_OFF));
- return;
- }
-
- if (osx_d_ptr->minimalScan) {// Try again, this time in FullDiscovery mode.
- osx_d_ptr->minimalScan = false;
- osx_d_ptr->agent->start(QBluetoothServiceDiscoveryAgent::FullDiscovery);
- } else {
- osx_d_ptr->setReplyError(HostNotFoundError,
- QCoreApplication::translate(TRANSFER_REPLY, TR_INVAL_TARGET));
- }
-}
-
-QT_END_NAMESPACE
diff --git a/src/bluetooth/qbluetoothtransferreply_macos_p.h b/src/bluetooth/qbluetoothtransferreply_macos_p.h
deleted file mode 100644
index e7b6f683..00000000
--- a/src/bluetooth/qbluetoothtransferreply_macos_p.h
+++ /dev/null
@@ -1,101 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QBLUETOOTHTRANSFERREPLY_OSX_P_H
-#define QBLUETOOTHTRANSFERREPLY_OSX_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include "qbluetoothservicediscoveryagent.h"
-#include "qbluetoothtransferreply.h"
-
-#include <QtCore/qscopedpointer.h>
-#include <QtCore/qglobal.h>
-
-QT_BEGIN_NAMESPACE
-
-class QBluetoothTransferReplyOSXPrivate;
-class QBluetoothServiceInfo;
-class QBluetoothAddress;
-class QIODevice;
-
-class Q_BLUETOOTH_EXPORT QBluetoothTransferReplyOSX : public QBluetoothTransferReply
-{
- Q_OBJECT
-
-public:
- QBluetoothTransferReplyOSX(QIODevice *input, const QBluetoothTransferRequest &request,
- QBluetoothTransferManager *parent);
- ~QBluetoothTransferReplyOSX();
-
- TransferError error() const override;
- QString errorString() const override;
-
- bool isFinished() const override;
- bool isRunning() const override;
-
-Q_SIGNALS:
- void error(QBluetoothTransferReply::TransferError lastError);
-
-public slots:
- bool abort();
-
-private slots:
- bool start();
-
- void serviceDiscoveryFinished();
- void serviceDiscoveryError(QBluetoothServiceDiscoveryAgent::Error error);
-
-private:
- // OS X private data (not to be seen by moc).
- QScopedPointer<QBluetoothTransferReplyOSXPrivate> osx_d_ptr;
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/bluetooth/qbluetoothtransferreply_p.h b/src/bluetooth/qbluetoothtransferreply_p.h
deleted file mode 100644
index 375a89a3..00000000
--- a/src/bluetooth/qbluetoothtransferreply_p.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QBLUETOOTHTRANSFERREPLY_P_H
-#define QBLUETOOTHTRANSFERREPLY_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include "qbluetoothtransferreply.h"
-
-QT_BEGIN_NAMESPACE
-
-class Q_BLUETOOTH_EXPORT QBluetoothTransferReplyPrivate
-{
-public:
- QBluetoothTransferReplyPrivate();
-
- QBluetoothTransferManager *m_manager = nullptr;
-
- QBluetoothTransferRequest m_request;
-};
-
-QT_END_NAMESPACE
-
-#endif // QBLUETOOTHTRANSFERREPLY_H
diff --git a/src/bluetooth/qbluetoothtransferrequest.cpp b/src/bluetooth/qbluetoothtransferrequest.cpp
deleted file mode 100644
index 1138f7d8..00000000
--- a/src/bluetooth/qbluetoothtransferrequest.cpp
+++ /dev/null
@@ -1,184 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qbluetoothtransferrequest.h"
-#include "qbluetoothaddress.h"
-#include "qbluetoothtransferrequest_p.h"
-
-
-QT_BEGIN_NAMESPACE
-
-/*!
- \class QBluetoothTransferRequest
- \inmodule QtBluetooth
- \brief The QBluetoothTransferRequest class stores information about a
- data transfer request.
-
- \since 5.2
-
- QBluetoothTransferRequest is part of the Bluetooth Transfer API and is the class holding the
- information necessary to initiate a transfer over Bluetooth.
-
- \sa QBluetoothTransferReply, QBluetoothTransferManager
-*/
-
-/*!
- \enum QBluetoothTransferRequest::Attribute
-
- Attribute codes for QBluetoothTransferRequest and QBluetoothTransferReply.
-
- \value DescriptionAttribute A textual description of the object being transferred.
- May be displayed in the UI of the remote device.
- \value TimeAttribute Time attribute of the object being transferred.
- \value TypeAttribute MIME type of the object being transferred.
- \value LengthAttribute Length in bytes of the object being transferred.
- \value NameAttribute Name of the object being transferred. May be displayed in the UI of
- the remote device.
-*/
-
-/*!
- Constructs a new Bluetooth transfer request to the device with \a address.
-*/
-QBluetoothTransferRequest::QBluetoothTransferRequest(const QBluetoothAddress &address)
-:d_ptr(new QBluetoothTransferRequestPrivate)
-{
- Q_D(QBluetoothTransferRequest);
-
- d->m_address = address;
-}
-
-/*!
- Constructs a new Bluetooth transfer request that is a copy of \a other.
-*/
-QBluetoothTransferRequest::QBluetoothTransferRequest(const QBluetoothTransferRequest &other)
-:d_ptr(new QBluetoothTransferRequestPrivate)
-{
- *this = other;
-}
-
-/*!
- Destorys the Bluetooth transfer request.
-*/
-QBluetoothTransferRequest::~QBluetoothTransferRequest()
-{
- delete d_ptr;
-}
-
-/*!
- Returns the attribute associated with \a code. If the attribute has not been set, it
- returns \a defaultValue.
-
- \sa setAttribute(), QBluetoothTransferRequest::Attribute
-*/
-QVariant QBluetoothTransferRequest::attribute(Attribute code, const QVariant &defaultValue) const
-{
- Q_D(const QBluetoothTransferRequest);
-
- if (d->m_parameters.contains((int)code)) {
- return d->m_parameters.value((int)code);
- } else {
- return defaultValue;
- }
-}
-
-/*!
- Sets the attribute associated with \a code to \a value. If the attribute is
- already set, the previous value is discarded. If \a value is an invalid QVariant, the attribute
- is unset.
-
- \sa attribute(), QBluetoothTransferRequest::Attribute
-*/
-void QBluetoothTransferRequest::setAttribute(Attribute code, const QVariant &value)
-{
- Q_D(QBluetoothTransferRequest);
-
- d->m_parameters.insert((int)code, value);
-}
-
-/*!
- Returns the address associated with the Bluetooth transfer request.
-*/
-QBluetoothAddress QBluetoothTransferRequest::address() const
-{
- Q_D(const QBluetoothTransferRequest);
-
- return d->m_address;
-}
-
-
-/*!
- Returns true if this object is not the same as \a other.
-
- \sa operator==()
-*/
-bool QBluetoothTransferRequest::operator!=(const QBluetoothTransferRequest &other) const
-{
- return !(*this == other);
-}
-
-/*!
- Creates a copy of \a other.
-*/
-QBluetoothTransferRequest &QBluetoothTransferRequest::operator=(const QBluetoothTransferRequest &other)
-{
- Q_D(QBluetoothTransferRequest);
-
- d->m_address = other.d_func()->m_address;
- d->m_parameters = other.d_func()->m_parameters;
-
- return *this;
-}
-
-/*!
- Returns true if this object is the same as \a other.
-*/
-bool QBluetoothTransferRequest::operator==(const QBluetoothTransferRequest &other) const
-{
- Q_D(const QBluetoothTransferRequest);
- if (d->m_address == other.d_func()->m_address && d->m_parameters == other.d_func()->m_parameters) {
- return true;
- }
- return false;
-}
-
-QBluetoothTransferRequestPrivate::QBluetoothTransferRequestPrivate()
-{
-}
-
-QT_END_NAMESPACE
diff --git a/src/bluetooth/qbluetoothtransferrequest.h b/src/bluetooth/qbluetoothtransferrequest.h
deleted file mode 100644
index 5485a0d9..00000000
--- a/src/bluetooth/qbluetoothtransferrequest.h
+++ /dev/null
@@ -1,88 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QBLUETOOTHTRANSFERREQUEST_H
-#define QBLUETOOTHTRANSFERREQUEST_H
-
-#include <QtBluetooth/qtbluetoothglobal.h>
-#include <QtBluetooth/QBluetoothAddress>
-
-#include <QtCore/QtGlobal>
-#include <QtCore/QVariant>
-
-QT_BEGIN_NAMESPACE
-
-class QBluetoothAddress;
-class QBluetoothTransferRequestPrivate;
-
-class Q_BLUETOOTH_EXPORT QBluetoothTransferRequest
-{
-public:
- enum Attribute {
- DescriptionAttribute,
- TimeAttribute,
- TypeAttribute,
- LengthAttribute,
- NameAttribute
- };
-
- explicit QBluetoothTransferRequest(const QBluetoothAddress &address = QBluetoothAddress());
- QBluetoothTransferRequest(const QBluetoothTransferRequest &other);
- ~QBluetoothTransferRequest();
-
- QVariant attribute(Attribute code, const QVariant &defaultValue = QVariant()) const;
- void setAttribute(Attribute code, const QVariant &value);
-
- QBluetoothAddress address() const;
-
- bool operator!=(const QBluetoothTransferRequest &other) const;
- QBluetoothTransferRequest &operator=(const QBluetoothTransferRequest &other);
- bool operator==(const QBluetoothTransferRequest &other) const;
-
-protected:
- QBluetoothTransferRequestPrivate *d_ptr;
-
-private:
- Q_DECLARE_PRIVATE(QBluetoothTransferRequest)
-
-};
-
-QT_END_NAMESPACE
-
-#endif // QBLUETOOTHTRANSFERREQUEST_H
diff --git a/src/bluetooth/qbluetoothtransferrequest_p.h b/src/bluetooth/qbluetoothtransferrequest_p.h
deleted file mode 100644
index 410a9709..00000000
--- a/src/bluetooth/qbluetoothtransferrequest_p.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QBLUETOOTHTRANSFERREQUESTPRIVATE_H
-#define QBLUETOOTHTRANSFERREQUESTPRIVATE_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <QtBluetooth/qtbluetoothglobal.h>
-#include "qbluetoothtransferrequest.h"
-
-QT_BEGIN_NAMESPACE
-
-class QBluetoothAddress;
-
-class QBluetoothTransferRequestPrivate
-{
-public:
- QBluetoothTransferRequestPrivate();
-
- QBluetoothAddress m_address;
- QMap<int, QVariant> m_parameters;
-};
-
-QT_END_NAMESPACE
-
-#endif // QBLUETOOTHTRANSFERREQUESTPRIVATE_H
diff --git a/src/bluetooth/qbluetoothutils_win.cpp b/src/bluetooth/qbluetoothutils_win.cpp
deleted file mode 100644
index a5151d82..00000000
--- a/src/bluetooth/qbluetoothutils_win.cpp
+++ /dev/null
@@ -1,94 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <QtCore/private/qeventdispatcher_winrt_p.h>
-
-#define Q_OS_WINRT
-#include <QtCore/qfunctions_winrt.h>
-
-#include <wrl.h>
-#include <windows.devices.bluetooth.h>
-
-using namespace Microsoft::WRL;
-using namespace Microsoft::WRL::Wrappers;
-using namespace ABI::Windows::Devices::Bluetooth;
-using namespace ABI::Windows::Foundation;
-
-QT_BEGIN_NAMESPACE
-
-#pragma warning (push)
-#pragma warning (disable: 4273)
-HRESULT QEventDispatcherWinRT::runOnXamlThread(const std::function<HRESULT()> &delegate, bool waitForRun)
-{
- Q_UNUSED(waitForRun)
- return delegate();
-}
-#pragma warning (pop)
-
-extern "C" BOOL WINAPI DllMain(HINSTANCE, DWORD reason, LPVOID)
-{
- switch (reason)
- {
- case DLL_PROCESS_ATTACH: {
- // Check if we are running on a recent enough Windows
- HRESULT hr = OleInitialize(NULL);
- if (FAILED(hr)) {
- MessageBox(NULL, (LPCWSTR)L"OleInitialize failed.", (LPCWSTR)L"Error", MB_OK | MB_ICONERROR | MB_APPLMODAL);
- exit(-1);
- }
- ComPtr<IBluetoothDeviceStatics> deviceStatics;
- hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Devices_Bluetooth_BluetoothDevice).Get(), &deviceStatics);
- if (hr == REGDB_E_CLASSNOTREG) {
- QString error ("This Windows version (" + QSysInfo::kernelVersion() + ") does not "
- "support the required Bluetooth API. Consider updating to a more recent Windows "
- "(10.0.10586 or above).");
- MessageBox(NULL, (LPCWSTR)error.constData(), (LPCWSTR)L"Error", MB_OK | MB_ICONERROR | MB_APPLMODAL);
- CoUninitialize();
- exit(-1);
- }
- break;
- }
- case DLL_PROCESS_DETACH:
- CoUninitialize();
- }
-
- return TRUE;
-}
-
-QT_END_NAMESPACE
diff --git a/src/bluetooth/qbluetoothutils_winrt.cpp b/src/bluetooth/qbluetoothutils_winrt.cpp
index de4355c6..b146be19 100644
--- a/src/bluetooth/qbluetoothutils_winrt.cpp
+++ b/src/bluetooth/qbluetoothutils_winrt.cpp
@@ -1,83 +1,24 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qbluetoothutils_winrt_p.h"
#include <QtBluetooth/private/qtbluetoothglobal_p.h>
-
-#include <QtCore/qfunctions_winrt.h>
+#include <QtCore/private/qfunctions_winrt_p.h>
+#include <QtCore/QLoggingCategory>
#include <robuffer.h>
#include <wrl.h>
-#include <windows.foundation.metadata.h>
+#include <winrt/windows.foundation.metadata.h>
#include <windows.storage.streams.h>
using namespace Microsoft::WRL;
using namespace Microsoft::WRL::Wrappers;
-using namespace ABI::Windows::Foundation::Metadata;
+using namespace winrt::Windows::Foundation::Metadata;
using namespace ABI::Windows::Storage::Streams;
QT_BEGIN_NAMESPACE
-bool supportsNewLEApi()
-{
- static bool initialized = false;
- static boolean apiPresent = false;
- if (initialized)
- return apiPresent;
-
- initialized = true;
-#if !QT_CONFIG(winrt_btle_no_pairing)
- return apiPresent;
-#endif
-
- ComPtr<IApiInformationStatics> apiInformationStatics;
- HRESULT hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Foundation_Metadata_ApiInformation).Get(),
- IID_PPV_ARGS(&apiInformationStatics));
- if (FAILED(hr))
- return apiPresent;
-
- const HStringReference valueRef(L"Windows.Foundation.UniversalApiContract");
- hr = apiInformationStatics->IsApiContractPresentByMajor(
- valueRef.Get(), 4, &apiPresent);
- apiPresent = SUCCEEDED(hr) && apiPresent;
- return apiPresent;
-}
+Q_DECLARE_LOGGING_CATEGORY(QT_BT_WINDOWS)
QByteArray byteArrayFromBuffer(const ComPtr<NativeBuffer> &buffer, bool isWCharString)
{
@@ -95,10 +36,59 @@ QByteArray byteArrayFromBuffer(const ComPtr<NativeBuffer> &buffer, bool isWCharS
hr = buffer->get_Length(&size);
RETURN_IF_FAILED("Could not obtain buffer size", return QByteArray())
if (isWCharString) {
- QString valueString = QString::fromUtf16(reinterpret_cast<ushort *>(data)).left(size / 2);
+ QString valueString = QString::fromUtf16(reinterpret_cast<char16_t *>(data)).left(size / 2);
return valueString.toUtf8();
}
return QByteArray(data, qint32(size));
}
+static QSet<void*> successfulInits;
+static QThread *mainThread = nullptr;
+
+void mainThreadCoInit(void* caller)
+{
+ Q_ASSERT(caller);
+
+ if (QThread::currentThread() != QCoreApplication::instance()->thread()) {
+ qCWarning(QT_BT_WINDOWS) << "Main thread COM init tried from another thread";
+ return;
+ }
+
+ if (successfulInits.contains(caller)) {
+ qCWarning(QT_BT_WINDOWS) << "Multiple COM inits by same object";
+ return;
+ }
+
+ Q_ASSERT_X(!mainThread || mainThread == QThread::currentThread(),
+ __FUNCTION__, "QCoreApplication's thread has changed!");
+
+ // This executes in main thread which may run Gui => use apartment threaded
+ if (!SUCCEEDED(CoInitializeEx(NULL, COINIT_APARTMENTTHREADED))) {
+ qCWarning(QT_BT_WINDOWS) << "Unexpected COM initialization result";
+ return;
+ }
+ successfulInits.insert(caller);
+ if (!mainThread)
+ mainThread = QThread::currentThread();
+}
+
+void mainThreadCoUninit(void* caller)
+{
+ Q_ASSERT(caller);
+
+ if (!successfulInits.contains(caller)) {
+ qCWarning(QT_BT_WINDOWS) << "COM uninitialization without initialization";
+ return;
+ }
+
+ if (QThread::currentThread() != mainThread) {
+ qCWarning(QT_BT_WINDOWS) << "Main thread COM uninit tried from another thread";
+ return;
+ }
+
+ CoUninitialize();
+ successfulInits.remove(caller);
+
+}
+
QT_END_NAMESPACE
diff --git a/src/bluetooth/qbluetoothutils_winrt_p.h b/src/bluetooth/qbluetoothutils_winrt_p.h
index 93950fc9..9e1d4752 100644
--- a/src/bluetooth/qbluetoothutils_winrt_p.h
+++ b/src/bluetooth/qbluetoothutils_winrt_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QBLUETOOTHUTILS_WINRT_P_H
#define QBLUETOOTHUTILS_WINRT_P_H
@@ -51,7 +15,18 @@
// We mean it.
//
+// Workaround for Windows SDK bug.
+// See https://github.com/microsoft/Windows.UI.Composition-Win32-Samples/issues/47
+ #include <winrt/base.h>
+#include <QtCore/private/qfactorycacheregistration_p.h>
+namespace winrt::impl
+{
+ template <typename Async>
+ auto wait_for(Async const& async, Windows::Foundation::TimeSpan const& timeout);
+}
+
#include <QtCore/QtGlobal>
+#include <QtCore/private/qglobal_p.h>
#include <wrl/client.h>
@@ -67,12 +42,14 @@ namespace ABI {
QT_BEGIN_NAMESPACE
-bool supportsNewLEApi();
-
using NativeBuffer = ABI::Windows::Storage::Streams::IBuffer;
QByteArray byteArrayFromBuffer(const Microsoft::WRL::ComPtr<NativeBuffer> &buffer,
bool isWCharString = false);
+// The calls to Co(Un)init must be balanced
+void mainThreadCoInit(void* caller);
+void mainThreadCoUninit(void* caller);
+
QT_END_NAMESPACE
#endif // QBLUETOOTHSOCKET_WINRT_P_H
diff --git a/src/bluetooth/qbluetoothuuid.cpp b/src/bluetooth/qbluetoothuuid.cpp
index bc00aa95..5eefde44 100644
--- a/src/bluetooth/qbluetoothuuid.cpp
+++ b/src/bluetooth/qbluetoothuuid.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qbluetoothuuid.h"
#include "qbluetoothservicediscoveryagent.h"
@@ -47,8 +11,21 @@
QT_BEGIN_NAMESPACE
+QT_IMPL_METATYPE_EXTERN(QBluetoothUuid)
+
// Bluetooth base UUID 00000000-0000-1000-8000-00805F9B34FB
-Q_GLOBAL_STATIC_WITH_ARGS(QUuid, baseUuid, ("{00000000-0000-1000-8000-00805F9B34FB}"))
+// these defines represent the above UUID
+// static inline constexpr const uint data1Reference = 0x00000000;
+static inline constexpr const ushort data2Reference = 0x0000;
+static inline constexpr const ushort data3Reference = 0x1000;
+static inline constexpr const unsigned char data4Reference[] { 0x80, 0x00, 0x00, 0x80,
+ 0x5f, 0x9b, 0x34, 0xfb };
+
+void registerQBluetoothUuid()
+{
+ qRegisterMetaType<QBluetoothUuid>();
+}
+Q_CONSTRUCTOR_FUNCTION(registerQBluetoothUuid)
/*!
\class QBluetoothUuid
@@ -503,159 +480,102 @@ Q_GLOBAL_STATIC_WITH_ARGS(QUuid, baseUuid, ("{00000000-0000-1000-8000-00805F9B34
\value UnknownDescriptorType The descriptor type is unknown.
*/
-static void registerQBluetoothUuidMetaType()
-{
- static bool initDone = false;
- if (!initDone) {
- qRegisterMetaType<QBluetoothUuid>();
- initDone = true;
- }
-}
-
/*!
+ \fn QBluetoothUuid::QBluetoothUuid()
+
Constructs a new null Bluetooth UUID.
*/
-QBluetoothUuid::QBluetoothUuid()
-{
- registerQBluetoothUuidMetaType();
-}
/*!
+ \fn QBluetoothUuid::QBluetoothUuid(ProtocolUuid uuid)
+
Constructs a new Bluetooth UUID from the protocol \a uuid.
*/
-QBluetoothUuid::QBluetoothUuid(ProtocolUuid uuid)
-: QUuid(uuid, baseUuid()->data2,
- baseUuid()->data3, baseUuid()->data4[0], baseUuid()->data4[1],
- baseUuid()->data4[2], baseUuid()->data4[3], baseUuid()->data4[4], baseUuid()->data4[5],
- baseUuid()->data4[6], baseUuid()->data4[7])
-{
- registerQBluetoothUuidMetaType();
-}
/*!
+ \fn QBluetoothUuid::QBluetoothUuid(ServiceClassUuid uuid)
+
Constructs a new Bluetooth UUID from the service class \a uuid.
*/
-QBluetoothUuid::QBluetoothUuid(ServiceClassUuid uuid)
-: QUuid(uuid, baseUuid()->data2, baseUuid()->data3, baseUuid()->data4[0], baseUuid()->data4[1],
- baseUuid()->data4[2], baseUuid()->data4[3], baseUuid()->data4[4], baseUuid()->data4[5],
- baseUuid()->data4[6], baseUuid()->data4[7])
-{
- registerQBluetoothUuidMetaType();
-}
/*!
+ \fn QBluetoothUuid::QBluetoothUuid(CharacteristicType uuid)
+
Constructs a new Bluetooth UUID from the characteristic type \a uuid.
\since 5.4
*/
-QBluetoothUuid::QBluetoothUuid(CharacteristicType uuid)
-: QUuid(uuid, baseUuid()->data2, baseUuid()->data3, baseUuid()->data4[0], baseUuid()->data4[1],
- baseUuid()->data4[2], baseUuid()->data4[3], baseUuid()->data4[4], baseUuid()->data4[5],
- baseUuid()->data4[6], baseUuid()->data4[7])
-{
- registerQBluetoothUuidMetaType();
-}
/*!
+ \fn QBluetoothUuid::QBluetoothUuid(DescriptorType uuid)
+
Constructs a new Bluetooth UUID from the descriptor type \a uuid.
\since 5.4
*/
-QBluetoothUuid::QBluetoothUuid(DescriptorType uuid)
- : QUuid(uuid, baseUuid()->data2, baseUuid()->data3, baseUuid()->data4[0], baseUuid()->data4[1],
- baseUuid()->data4[2], baseUuid()->data4[3], baseUuid()->data4[4], baseUuid()->data4[5],
- baseUuid()->data4[6], baseUuid()->data4[7])
-{
- registerQBluetoothUuidMetaType();
-}
/*!
+ \fn QBluetoothUuid::QBluetoothUuid(quint16 uuid)
+
Constructs a new Bluetooth UUID from the 16 bit \a uuid.
*/
-QBluetoothUuid::QBluetoothUuid(quint16 uuid)
-: QUuid(uuid, baseUuid()->data2, baseUuid()->data3, baseUuid()->data4[0], baseUuid()->data4[1],
- baseUuid()->data4[2], baseUuid()->data4[3], baseUuid()->data4[4], baseUuid()->data4[5],
- baseUuid()->data4[6], baseUuid()->data4[7])
-{
- registerQBluetoothUuidMetaType();
-}
/*!
+ \fn QBluetoothUuid::QBluetoothUuid(quint32 uuid)
+
Constructs a new Bluetooth UUID from the 32 bit \a uuid.
*/
-QBluetoothUuid::QBluetoothUuid(quint32 uuid)
-: QUuid(uuid, baseUuid()->data2, baseUuid()->data3, baseUuid()->data4[0], baseUuid()->data4[1],
- baseUuid()->data4[2], baseUuid()->data4[3], baseUuid()->data4[4], baseUuid()->data4[5],
- baseUuid()->data4[6], baseUuid()->data4[7])
-{
- registerQBluetoothUuidMetaType();
-}
/*!
- Constructs a new Bluetooth UUID from the 128 bit \a uuid.
+ \fn QBluetoothUuid::QBluetoothUuid(QUuid::Id128Bytes uuid, QSysInfo::Endian order)
+ \since 6.6
- Note that \a uuid must be in big endian order.
+ Constructs a new Bluetooth UUID from the 128 bit \a uuid represented
+ by the integral \a uuid parameter and respecting the byte order \a order.
*/
-QBluetoothUuid::QBluetoothUuid(quint128 uuid)
-{
- registerQBluetoothUuidMetaType();
-QT_WARNING_PUSH
-QT_WARNING_DISABLE_GCC("-Wstrict-aliasing")
- data1 = qFromBigEndian<quint32>(*reinterpret_cast<quint32 *>(&uuid.data[0]));
- data2 = qFromBigEndian<quint16>(*reinterpret_cast<quint16 *>(&uuid.data[4]));
- data3 = qFromBigEndian<quint16>(*reinterpret_cast<quint16 *>(&uuid.data[6]));
-QT_WARNING_POP
-
- memcpy(data4, &uuid.data[8], 8);
-}
/*!
- Creates a QBluetoothUuid object from the string \a uuid,
- which must be formatted as five hex fields separated by '-',
- e.g., "{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}" where 'x' is a hex digit.
- The curly braces shown here are optional, but it is normal to include them.
- If the conversion fails, a null UUID is created. See \l QUuid::toString() for an
- explanation of how the five hex fields map to the public data members in QUuid.
-*/
-QBluetoothUuid::QBluetoothUuid(const QString &uuid)
-: QUuid(uuid)
-{
- registerQBluetoothUuidMetaType();
-}
+ \fn quint128 QBluetoothUuid::toUInt128(QSysInfo::Endian order) const
-/*!
- Constructs a new Bluetooth UUID that is a copy of \a uuid.
+ Returns the 128 bit representation of this UUID in byte order \a order.
+
+ \note In Qt versions prior to 6.6, the \a order argument was not present,
+ and the function was hard-coded to return in big-endian order.
*/
-QBluetoothUuid::QBluetoothUuid(const QBluetoothUuid &uuid)
-: QUuid(uuid)
+#ifndef QT_SUPPORTS_INT128 // otherwise falls back to QUuid::toUint128()
+quint128 QBluetoothUuid::toUInt128(QSysInfo::Endian order) const noexcept
{
- registerQBluetoothUuidMetaType();
+ quint128 r;
+ const auto bytes = toBytes(order);
+ static_assert(sizeof(quint128) == sizeof(decltype(bytes)));
+ memcpy(&r, bytes.data, sizeof(quint128));
+ return r;
}
+#endif // !QT_SUPPORTS_INT128
/*!
- Constructs a new Bluetooth UUID that is a copy of \a uuid.
+ \fn QBluetoothUuid::QBluetoothUuid(quint128 uuid, QSysInfo::Endian order)
+
+ Constructs a new Bluetooth UUID from a 128 bit \a uuid.
+
+ \note In Qt versions prior to 6.6, the \a order argument was not present,
+ and the function was hard-coded to big-endian order.
*/
-QBluetoothUuid::QBluetoothUuid(const QUuid &uuid)
-: QUuid(uuid)
-{
- registerQBluetoothUuidMetaType();
-}
/*!
- Destroys the Bluetooth UUID.
+ \fn QBluetoothUuid::QBluetoothUuid(const QUuid &uuid)
+
+ Constructs a new Bluetooth UUID that is a copy of \a uuid.
*/
-QBluetoothUuid::~QBluetoothUuid()
-{
-}
/*!
Returns the minimum size in bytes that this UUID can be represented in. For non-null UUIDs 2,
4 or 16 is returned. 0 is returned for null UUIDs.
- \sa isNull(), toUInt16(), toUInt32(), toUInt128()
+ \sa isNull(), toUInt16(), toUInt32()
*/
int QBluetoothUuid::minimumSize() const
{
- if (data2 == baseUuid()->data2 && data3 == baseUuid()->data3 &&
- memcmp(data4, baseUuid()->data4, 8) == 0) {
+ if (data2 == data2Reference && data3 == data3Reference
+ && memcmp(data4, data4Reference, 8) == 0) {
// 16 or 32 bit Bluetooth UUID
if (data1 & 0xFFFF0000)
return 4;
@@ -676,8 +596,8 @@ int QBluetoothUuid::minimumSize() const
*/
quint16 QBluetoothUuid::toUInt16(bool *ok) const
{
- if (data1 & 0xFFFF0000 || data2 != baseUuid()->data2 || data3 != baseUuid()->data3 ||
- memcmp(data4, baseUuid()->data4, 8) != 0) {
+ if (data1 & 0xFFFF0000 || data2 != data2Reference || data3 != data3Reference
+ || memcmp(data4, data4Reference, 8) != 0) {
// not convertable to 16 bit Bluetooth UUID.
if (ok)
*ok = false;
@@ -697,8 +617,8 @@ quint16 QBluetoothUuid::toUInt16(bool *ok) const
*/
quint32 QBluetoothUuid::toUInt32(bool *ok) const
{
- if (data2 != baseUuid()->data2 || data3 != baseUuid()->data3 ||
- memcmp(data4, baseUuid()->data4, 8) != 0) {
+ if (data2 != data2Reference || data3 != data3Reference
+ || memcmp(data4, data4Reference, 8) != 0) {
// not convertable to 32 bit Bluetooth UUID.
if (ok)
*ok = false;
@@ -712,27 +632,6 @@ quint32 QBluetoothUuid::toUInt32(bool *ok) const
}
/*!
- Returns the 128 bit representation of this UUID.
-*/
-quint128 QBluetoothUuid::toUInt128() const
-{
- quint128 uuid;
-
- quint32 tmp32 = qToBigEndian<quint32>(data1);
- memcpy(&uuid.data[0], &tmp32, 4);
-
- quint16 tmp16 = qToBigEndian<quint16>(data2);
- memcpy(&uuid.data[4], &tmp16, 2);
-
- tmp16 = qToBigEndian<quint16>(data3);
- memcpy(&uuid.data[6], &tmp16, 2);
-
- memcpy(&uuid.data[8], data4, 8);
-
- return uuid;
-}
-
-/*!
Returns a human-readable and translated name for the given service class
represented by \a uuid.
@@ -742,100 +641,98 @@ quint128 QBluetoothUuid::toUInt128() const
QString QBluetoothUuid::serviceClassToString(QBluetoothUuid::ServiceClassUuid uuid)
{
switch (uuid) {
- case QBluetoothUuid::ServiceDiscoveryServer: return QBluetoothServiceDiscoveryAgent::tr("Service Discovery");
- case QBluetoothUuid::BrowseGroupDescriptor: return QBluetoothServiceDiscoveryAgent::tr("Browse Group Descriptor");
- case QBluetoothUuid::PublicBrowseGroup: return QBluetoothServiceDiscoveryAgent::tr("Public Browse Group");
- case QBluetoothUuid::SerialPort: return QBluetoothServiceDiscoveryAgent::tr("Serial Port Profile");
- case QBluetoothUuid::LANAccessUsingPPP: return QBluetoothServiceDiscoveryAgent::tr("LAN Access Profile");
- case QBluetoothUuid::DialupNetworking: return QBluetoothServiceDiscoveryAgent::tr("Dial-Up Networking");
- case QBluetoothUuid::IrMCSync: return QBluetoothServiceDiscoveryAgent::tr("Synchronization");
- case QBluetoothUuid::ObexObjectPush: return QBluetoothServiceDiscoveryAgent::tr("Object Push");
- case QBluetoothUuid::OBEXFileTransfer: return QBluetoothServiceDiscoveryAgent::tr("File Transfer");
- case QBluetoothUuid::IrMCSyncCommand: return QBluetoothServiceDiscoveryAgent::tr("Synchronization Command");
- case QBluetoothUuid::Headset: return QBluetoothServiceDiscoveryAgent::tr("Headset");
- case QBluetoothUuid::AudioSource: return QBluetoothServiceDiscoveryAgent::tr("Audio Source");
- case QBluetoothUuid::AudioSink: return QBluetoothServiceDiscoveryAgent::tr("Audio Sink");
- case QBluetoothUuid::AV_RemoteControlTarget: return QBluetoothServiceDiscoveryAgent::tr("Audio/Video Remote Control Target");
- case QBluetoothUuid::AdvancedAudioDistribution: return QBluetoothServiceDiscoveryAgent::tr("Advanced Audio Distribution");
- case QBluetoothUuid::AV_RemoteControl: return QBluetoothServiceDiscoveryAgent::tr("Audio/Video Remote Control");
- case QBluetoothUuid::AV_RemoteControlController: return QBluetoothServiceDiscoveryAgent::tr("Audio/Video Remote Control Controller");
- case QBluetoothUuid::HeadsetAG: return QBluetoothServiceDiscoveryAgent::tr("Headset AG");
- case QBluetoothUuid::PANU: return QBluetoothServiceDiscoveryAgent::tr("Personal Area Networking (PANU)");
- case QBluetoothUuid::NAP: return QBluetoothServiceDiscoveryAgent::tr("Personal Area Networking (NAP)");
- case QBluetoothUuid::GN: return QBluetoothServiceDiscoveryAgent::tr("Personal Area Networking (GN)");
- case QBluetoothUuid::DirectPrinting: return QBluetoothServiceDiscoveryAgent::tr("Basic Direct Printing (BPP)");
- case QBluetoothUuid::ReferencePrinting: return QBluetoothServiceDiscoveryAgent::tr("Basic Reference Printing (BPP)");
- case QBluetoothUuid::BasicImage: return QBluetoothServiceDiscoveryAgent::tr("Basic Imaging Profile");
- case QBluetoothUuid::ImagingResponder: return QBluetoothServiceDiscoveryAgent::tr("Basic Imaging Responder");
- case QBluetoothUuid::ImagingAutomaticArchive: return QBluetoothServiceDiscoveryAgent::tr("Basic Imaging Archive");
- case QBluetoothUuid::ImagingReferenceObjects: return QBluetoothServiceDiscoveryAgent::tr("Basic Imaging Ref Objects");
- case QBluetoothUuid::Handsfree: return QBluetoothServiceDiscoveryAgent::tr("Hands-Free");
- case QBluetoothUuid::HandsfreeAudioGateway: return QBluetoothServiceDiscoveryAgent::tr("Hands-Free AG");
- case QBluetoothUuid::DirectPrintingReferenceObjectsService: return QBluetoothServiceDiscoveryAgent::tr("Basic Printing RefObject Service");
- case QBluetoothUuid::ReflectedUI: return QBluetoothServiceDiscoveryAgent::tr("Basic Printing Reflected UI");
- case QBluetoothUuid::BasicPrinting: return QBluetoothServiceDiscoveryAgent::tr("Basic Printing");
- case QBluetoothUuid::PrintingStatus: return QBluetoothServiceDiscoveryAgent::tr("Basic Printing Status");
- case QBluetoothUuid::HumanInterfaceDeviceService: return QBluetoothServiceDiscoveryAgent::tr("Human Interface Device");
- case QBluetoothUuid::HardcopyCableReplacement: return QBluetoothServiceDiscoveryAgent::tr("Hardcopy Cable Replacement");
- case QBluetoothUuid::HCRPrint: return QBluetoothServiceDiscoveryAgent::tr("Hardcopy Cable Replacement Print");
- case QBluetoothUuid::HCRScan: return QBluetoothServiceDiscoveryAgent::tr("Hardcopy Cable Replacement Scan");
- case QBluetoothUuid::SIMAccess: return QBluetoothServiceDiscoveryAgent::tr("SIM Access Server");
- case QBluetoothUuid::PhonebookAccessPCE: return QBluetoothServiceDiscoveryAgent::tr("Phonebook Access PCE");
- case QBluetoothUuid::PhonebookAccessPSE: return QBluetoothServiceDiscoveryAgent::tr("Phonebook Access PSE");
- case QBluetoothUuid::PhonebookAccess: return QBluetoothServiceDiscoveryAgent::tr("Phonebook Access");
- case QBluetoothUuid::HeadsetHS: return QBluetoothServiceDiscoveryAgent::tr("Headset HS");
- case QBluetoothUuid::MessageAccessServer: return QBluetoothServiceDiscoveryAgent::tr("Message Access Server");
- case QBluetoothUuid::MessageNotificationServer: return QBluetoothServiceDiscoveryAgent::tr("Message Notification Server");
- case QBluetoothUuid::MessageAccessProfile: return QBluetoothServiceDiscoveryAgent::tr("Message Access");
- case QBluetoothUuid::GNSS: return QBluetoothServiceDiscoveryAgent::tr("Global Navigation Satellite System");
- case QBluetoothUuid::GNSSServer: return QBluetoothServiceDiscoveryAgent::tr("Global Navigation Satellite System Server");
- case QBluetoothUuid::Display3D: return QBluetoothServiceDiscoveryAgent::tr("3D Synchronization Display");
- case QBluetoothUuid::Glasses3D: return QBluetoothServiceDiscoveryAgent::tr("3D Synchronization Glasses");
- case QBluetoothUuid::Synchronization3D: return QBluetoothServiceDiscoveryAgent::tr("3D Synchronization");
- case QBluetoothUuid::MPSProfile: return QBluetoothServiceDiscoveryAgent::tr("Multi-Profile Specification (Profile)");
- case QBluetoothUuid::MPSService: return QBluetoothServiceDiscoveryAgent::tr("Multi-Profile Specification");
- case QBluetoothUuid::PnPInformation: return QBluetoothServiceDiscoveryAgent::tr("Device Identification");
- case QBluetoothUuid::GenericNetworking: return QBluetoothServiceDiscoveryAgent::tr("Generic Networking");
- case QBluetoothUuid::GenericFileTransfer: return QBluetoothServiceDiscoveryAgent::tr("Generic File Transfer");
- case QBluetoothUuid::GenericAudio: return QBluetoothServiceDiscoveryAgent::tr("Generic Audio");
- case QBluetoothUuid::GenericTelephony: return QBluetoothServiceDiscoveryAgent::tr("Generic Telephony");
- case QBluetoothUuid::VideoSource: return QBluetoothServiceDiscoveryAgent::tr("Video Source");
- case QBluetoothUuid::VideoSink: return QBluetoothServiceDiscoveryAgent::tr("Video Sink");
- case QBluetoothUuid::VideoDistribution: return QBluetoothServiceDiscoveryAgent::tr("Video Distribution");
- case QBluetoothUuid::HDP: return QBluetoothServiceDiscoveryAgent::tr("Health Device");
- case QBluetoothUuid::HDPSource: return QBluetoothServiceDiscoveryAgent::tr("Health Device Source");
- case QBluetoothUuid::HDPSink: return QBluetoothServiceDiscoveryAgent::tr("Health Device Sink");
- case QBluetoothUuid::GenericAccess: return QBluetoothServiceDiscoveryAgent::tr("Generic Access");
- case QBluetoothUuid::GenericAttribute: return QBluetoothServiceDiscoveryAgent::tr("Generic Attribute");
- case QBluetoothUuid::ImmediateAlert: return QBluetoothServiceDiscoveryAgent::tr("Immediate Alert");
- case QBluetoothUuid::LinkLoss: return QBluetoothServiceDiscoveryAgent::tr("Link Loss");
- case QBluetoothUuid::TxPower: return QBluetoothServiceDiscoveryAgent::tr("Tx Power");
- case QBluetoothUuid::CurrentTimeService: return QBluetoothServiceDiscoveryAgent::tr("Current Time Service");
- case QBluetoothUuid::ReferenceTimeUpdateService: return QBluetoothServiceDiscoveryAgent::tr("Reference Time Update Service");
- case QBluetoothUuid::NextDSTChangeService: return QBluetoothServiceDiscoveryAgent::tr("Next DST Change Service");
- case QBluetoothUuid::Glucose: return QBluetoothServiceDiscoveryAgent::tr("Glucose");
- case QBluetoothUuid::HealthThermometer: return QBluetoothServiceDiscoveryAgent::tr("Health Thermometer");
- case QBluetoothUuid::DeviceInformation: return QBluetoothServiceDiscoveryAgent::tr("Device Information");
- case QBluetoothUuid::HeartRate: return QBluetoothServiceDiscoveryAgent::tr("Heart Rate");
- case QBluetoothUuid::PhoneAlertStatusService: return QBluetoothServiceDiscoveryAgent::tr("Phone Alert Status Service");
- case QBluetoothUuid::BatteryService: return QBluetoothServiceDiscoveryAgent::tr("Battery Service");
- case QBluetoothUuid::BloodPressure: return QBluetoothServiceDiscoveryAgent::tr("Blood Pressure");
- case QBluetoothUuid::AlertNotificationService: return QBluetoothServiceDiscoveryAgent::tr("Alert Notification Service");
- case QBluetoothUuid::HumanInterfaceDevice: return QBluetoothServiceDiscoveryAgent::tr("Human Interface Device");
- case QBluetoothUuid::ScanParameters: return QBluetoothServiceDiscoveryAgent::tr("Scan Parameters");
- case QBluetoothUuid::RunningSpeedAndCadence: return QBluetoothServiceDiscoveryAgent::tr("Running Speed and Cadence");
- case QBluetoothUuid::CyclingSpeedAndCadence: return QBluetoothServiceDiscoveryAgent::tr("Cycling Speed and Cadence");
- case QBluetoothUuid::CyclingPower: return QBluetoothServiceDiscoveryAgent::tr("Cycling Power");
- case QBluetoothUuid::LocationAndNavigation: return QBluetoothServiceDiscoveryAgent::tr("Location and Navigation");
- case QBluetoothUuid::EnvironmentalSensing: return QBluetoothServiceDiscoveryAgent::tr("Environmental Sensing");
- case QBluetoothUuid::BodyComposition: return QBluetoothServiceDiscoveryAgent::tr("Body Composition");
- case QBluetoothUuid::UserData: return QBluetoothServiceDiscoveryAgent::tr("User Data");
- case QBluetoothUuid::WeightScale: return QBluetoothServiceDiscoveryAgent::tr("Weight Scale");
+ case QBluetoothUuid::ServiceClassUuid::ServiceDiscoveryServer: return QBluetoothServiceDiscoveryAgent::tr("Service Discovery");
+ case QBluetoothUuid::ServiceClassUuid::BrowseGroupDescriptor: return QBluetoothServiceDiscoveryAgent::tr("Browse Group Descriptor");
+ case QBluetoothUuid::ServiceClassUuid::PublicBrowseGroup: return QBluetoothServiceDiscoveryAgent::tr("Public Browse Group");
+ case QBluetoothUuid::ServiceClassUuid::SerialPort: return QBluetoothServiceDiscoveryAgent::tr("Serial Port Profile");
+ case QBluetoothUuid::ServiceClassUuid::LANAccessUsingPPP: return QBluetoothServiceDiscoveryAgent::tr("LAN Access Profile");
+ case QBluetoothUuid::ServiceClassUuid::DialupNetworking: return QBluetoothServiceDiscoveryAgent::tr("Dial-Up Networking");
+ case QBluetoothUuid::ServiceClassUuid::IrMCSync: return QBluetoothServiceDiscoveryAgent::tr("Synchronization");
+ case QBluetoothUuid::ServiceClassUuid::ObexObjectPush: return QBluetoothServiceDiscoveryAgent::tr("Object Push");
+ case QBluetoothUuid::ServiceClassUuid::OBEXFileTransfer: return QBluetoothServiceDiscoveryAgent::tr("File Transfer");
+ case QBluetoothUuid::ServiceClassUuid::IrMCSyncCommand: return QBluetoothServiceDiscoveryAgent::tr("Synchronization Command");
+ case QBluetoothUuid::ServiceClassUuid::Headset: return QBluetoothServiceDiscoveryAgent::tr("Headset");
+ case QBluetoothUuid::ServiceClassUuid::AudioSource: return QBluetoothServiceDiscoveryAgent::tr("Audio Source");
+ case QBluetoothUuid::ServiceClassUuid::AudioSink: return QBluetoothServiceDiscoveryAgent::tr("Audio Sink");
+ case QBluetoothUuid::ServiceClassUuid::AV_RemoteControlTarget: return QBluetoothServiceDiscoveryAgent::tr("Audio/Video Remote Control Target");
+ case QBluetoothUuid::ServiceClassUuid::AdvancedAudioDistribution: return QBluetoothServiceDiscoveryAgent::tr("Advanced Audio Distribution");
+ case QBluetoothUuid::ServiceClassUuid::AV_RemoteControl: return QBluetoothServiceDiscoveryAgent::tr("Audio/Video Remote Control");
+ case QBluetoothUuid::ServiceClassUuid::AV_RemoteControlController: return QBluetoothServiceDiscoveryAgent::tr("Audio/Video Remote Control Controller");
+ case QBluetoothUuid::ServiceClassUuid::HeadsetAG: return QBluetoothServiceDiscoveryAgent::tr("Headset AG");
+ case QBluetoothUuid::ServiceClassUuid::PANU: return QBluetoothServiceDiscoveryAgent::tr("Personal Area Networking (PANU)");
+ case QBluetoothUuid::ServiceClassUuid::NAP: return QBluetoothServiceDiscoveryAgent::tr("Personal Area Networking (NAP)");
+ case QBluetoothUuid::ServiceClassUuid::GN: return QBluetoothServiceDiscoveryAgent::tr("Personal Area Networking (GN)");
+ case QBluetoothUuid::ServiceClassUuid::DirectPrinting: return QBluetoothServiceDiscoveryAgent::tr("Basic Direct Printing (BPP)");
+ case QBluetoothUuid::ServiceClassUuid::ReferencePrinting: return QBluetoothServiceDiscoveryAgent::tr("Basic Reference Printing (BPP)");
+ case QBluetoothUuid::ServiceClassUuid::BasicImage: return QBluetoothServiceDiscoveryAgent::tr("Basic Imaging Profile");
+ case QBluetoothUuid::ServiceClassUuid::ImagingResponder: return QBluetoothServiceDiscoveryAgent::tr("Basic Imaging Responder");
+ case QBluetoothUuid::ServiceClassUuid::ImagingAutomaticArchive: return QBluetoothServiceDiscoveryAgent::tr("Basic Imaging Archive");
+ case QBluetoothUuid::ServiceClassUuid::ImagingReferenceObjects: return QBluetoothServiceDiscoveryAgent::tr("Basic Imaging Ref Objects");
+ case QBluetoothUuid::ServiceClassUuid::Handsfree: return QBluetoothServiceDiscoveryAgent::tr("Hands-Free");
+ case QBluetoothUuid::ServiceClassUuid::HandsfreeAudioGateway: return QBluetoothServiceDiscoveryAgent::tr("Hands-Free AG");
+ case QBluetoothUuid::ServiceClassUuid::DirectPrintingReferenceObjectsService: return QBluetoothServiceDiscoveryAgent::tr("Basic Printing RefObject Service");
+ case QBluetoothUuid::ServiceClassUuid::ReflectedUI: return QBluetoothServiceDiscoveryAgent::tr("Basic Printing Reflected UI");
+ case QBluetoothUuid::ServiceClassUuid::BasicPrinting: return QBluetoothServiceDiscoveryAgent::tr("Basic Printing");
+ case QBluetoothUuid::ServiceClassUuid::PrintingStatus: return QBluetoothServiceDiscoveryAgent::tr("Basic Printing Status");
+ case QBluetoothUuid::ServiceClassUuid::HumanInterfaceDeviceService: return QBluetoothServiceDiscoveryAgent::tr("Human Interface Device");
+ case QBluetoothUuid::ServiceClassUuid::HardcopyCableReplacement: return QBluetoothServiceDiscoveryAgent::tr("Hardcopy Cable Replacement");
+ case QBluetoothUuid::ServiceClassUuid::HCRPrint: return QBluetoothServiceDiscoveryAgent::tr("Hardcopy Cable Replacement Print");
+ case QBluetoothUuid::ServiceClassUuid::HCRScan: return QBluetoothServiceDiscoveryAgent::tr("Hardcopy Cable Replacement Scan");
+ case QBluetoothUuid::ServiceClassUuid::SIMAccess: return QBluetoothServiceDiscoveryAgent::tr("SIM Access Server");
+ case QBluetoothUuid::ServiceClassUuid::PhonebookAccessPCE: return QBluetoothServiceDiscoveryAgent::tr("Phonebook Access PCE");
+ case QBluetoothUuid::ServiceClassUuid::PhonebookAccessPSE: return QBluetoothServiceDiscoveryAgent::tr("Phonebook Access PSE");
+ case QBluetoothUuid::ServiceClassUuid::PhonebookAccess: return QBluetoothServiceDiscoveryAgent::tr("Phonebook Access");
+ case QBluetoothUuid::ServiceClassUuid::HeadsetHS: return QBluetoothServiceDiscoveryAgent::tr("Headset HS");
+ case QBluetoothUuid::ServiceClassUuid::MessageAccessServer: return QBluetoothServiceDiscoveryAgent::tr("Message Access Server");
+ case QBluetoothUuid::ServiceClassUuid::MessageNotificationServer: return QBluetoothServiceDiscoveryAgent::tr("Message Notification Server");
+ case QBluetoothUuid::ServiceClassUuid::MessageAccessProfile: return QBluetoothServiceDiscoveryAgent::tr("Message Access");
+ case QBluetoothUuid::ServiceClassUuid::GNSS: return QBluetoothServiceDiscoveryAgent::tr("Global Navigation Satellite System");
+ case QBluetoothUuid::ServiceClassUuid::GNSSServer: return QBluetoothServiceDiscoveryAgent::tr("Global Navigation Satellite System Server");
+ case QBluetoothUuid::ServiceClassUuid::Display3D: return QBluetoothServiceDiscoveryAgent::tr("3D Synchronization Display");
+ case QBluetoothUuid::ServiceClassUuid::Glasses3D: return QBluetoothServiceDiscoveryAgent::tr("3D Synchronization Glasses");
+ case QBluetoothUuid::ServiceClassUuid::Synchronization3D: return QBluetoothServiceDiscoveryAgent::tr("3D Synchronization");
+ case QBluetoothUuid::ServiceClassUuid::MPSProfile: return QBluetoothServiceDiscoveryAgent::tr("Multi-Profile Specification (Profile)");
+ case QBluetoothUuid::ServiceClassUuid::MPSService: return QBluetoothServiceDiscoveryAgent::tr("Multi-Profile Specification");
+ case QBluetoothUuid::ServiceClassUuid::PnPInformation: return QBluetoothServiceDiscoveryAgent::tr("Device Identification");
+ case QBluetoothUuid::ServiceClassUuid::GenericNetworking: return QBluetoothServiceDiscoveryAgent::tr("Generic Networking");
+ case QBluetoothUuid::ServiceClassUuid::GenericFileTransfer: return QBluetoothServiceDiscoveryAgent::tr("Generic File Transfer");
+ case QBluetoothUuid::ServiceClassUuid::GenericAudio: return QBluetoothServiceDiscoveryAgent::tr("Generic Audio");
+ case QBluetoothUuid::ServiceClassUuid::GenericTelephony: return QBluetoothServiceDiscoveryAgent::tr("Generic Telephony");
+ case QBluetoothUuid::ServiceClassUuid::VideoSource: return QBluetoothServiceDiscoveryAgent::tr("Video Source");
+ case QBluetoothUuid::ServiceClassUuid::VideoSink: return QBluetoothServiceDiscoveryAgent::tr("Video Sink");
+ case QBluetoothUuid::ServiceClassUuid::VideoDistribution: return QBluetoothServiceDiscoveryAgent::tr("Video Distribution");
+ case QBluetoothUuid::ServiceClassUuid::HDP: return QBluetoothServiceDiscoveryAgent::tr("Health Device");
+ case QBluetoothUuid::ServiceClassUuid::HDPSource: return QBluetoothServiceDiscoveryAgent::tr("Health Device Source");
+ case QBluetoothUuid::ServiceClassUuid::HDPSink: return QBluetoothServiceDiscoveryAgent::tr("Health Device Sink");
+ case QBluetoothUuid::ServiceClassUuid::GenericAccess: return QBluetoothServiceDiscoveryAgent::tr("Generic Access");
+ case QBluetoothUuid::ServiceClassUuid::GenericAttribute: return QBluetoothServiceDiscoveryAgent::tr("Generic Attribute");
+ case QBluetoothUuid::ServiceClassUuid::ImmediateAlert: return QBluetoothServiceDiscoveryAgent::tr("Immediate Alert");
+ case QBluetoothUuid::ServiceClassUuid::LinkLoss: return QBluetoothServiceDiscoveryAgent::tr("Link Loss");
+ case QBluetoothUuid::ServiceClassUuid::TxPower: return QBluetoothServiceDiscoveryAgent::tr("Tx Power");
+ case QBluetoothUuid::ServiceClassUuid::CurrentTimeService: return QBluetoothServiceDiscoveryAgent::tr("Current Time Service");
+ case QBluetoothUuid::ServiceClassUuid::ReferenceTimeUpdateService: return QBluetoothServiceDiscoveryAgent::tr("Reference Time Update Service");
+ case QBluetoothUuid::ServiceClassUuid::NextDSTChangeService: return QBluetoothServiceDiscoveryAgent::tr("Next DST Change Service");
+ case QBluetoothUuid::ServiceClassUuid::Glucose: return QBluetoothServiceDiscoveryAgent::tr("Glucose");
+ case QBluetoothUuid::ServiceClassUuid::HealthThermometer: return QBluetoothServiceDiscoveryAgent::tr("Health Thermometer");
+ case QBluetoothUuid::ServiceClassUuid::DeviceInformation: return QBluetoothServiceDiscoveryAgent::tr("Device Information");
+ case QBluetoothUuid::ServiceClassUuid::HeartRate: return QBluetoothServiceDiscoveryAgent::tr("Heart Rate");
+ case QBluetoothUuid::ServiceClassUuid::PhoneAlertStatusService: return QBluetoothServiceDiscoveryAgent::tr("Phone Alert Status Service");
+ case QBluetoothUuid::ServiceClassUuid::BatteryService: return QBluetoothServiceDiscoveryAgent::tr("Battery Service");
+ case QBluetoothUuid::ServiceClassUuid::BloodPressure: return QBluetoothServiceDiscoveryAgent::tr("Blood Pressure");
+ case QBluetoothUuid::ServiceClassUuid::AlertNotificationService: return QBluetoothServiceDiscoveryAgent::tr("Alert Notification Service");
+ case QBluetoothUuid::ServiceClassUuid::HumanInterfaceDevice: return QBluetoothServiceDiscoveryAgent::tr("Human Interface Device");
+ case QBluetoothUuid::ServiceClassUuid::ScanParameters: return QBluetoothServiceDiscoveryAgent::tr("Scan Parameters");
+ case QBluetoothUuid::ServiceClassUuid::RunningSpeedAndCadence: return QBluetoothServiceDiscoveryAgent::tr("Running Speed and Cadence");
+ case QBluetoothUuid::ServiceClassUuid::CyclingSpeedAndCadence: return QBluetoothServiceDiscoveryAgent::tr("Cycling Speed and Cadence");
+ case QBluetoothUuid::ServiceClassUuid::CyclingPower: return QBluetoothServiceDiscoveryAgent::tr("Cycling Power");
+ case QBluetoothUuid::ServiceClassUuid::LocationAndNavigation: return QBluetoothServiceDiscoveryAgent::tr("Location and Navigation");
+ case QBluetoothUuid::ServiceClassUuid::EnvironmentalSensing: return QBluetoothServiceDiscoveryAgent::tr("Environmental Sensing");
+ case QBluetoothUuid::ServiceClassUuid::BodyComposition: return QBluetoothServiceDiscoveryAgent::tr("Body Composition");
+ case QBluetoothUuid::ServiceClassUuid::UserData: return QBluetoothServiceDiscoveryAgent::tr("User Data");
+ case QBluetoothUuid::ServiceClassUuid::WeightScale: return QBluetoothServiceDiscoveryAgent::tr("Weight Scale");
//: Connection management (Bluetooth)
- case QBluetoothUuid::BondManagement: return QBluetoothServiceDiscoveryAgent::tr("Bond Management");
- case QBluetoothUuid::ContinuousGlucoseMonitoring: return QBluetoothServiceDiscoveryAgent::tr("Continuous Glucose Monitoring");
- default:
- break;
+ case QBluetoothUuid::ServiceClassUuid::BondManagement: return QBluetoothServiceDiscoveryAgent::tr("Bond Management");
+ case QBluetoothUuid::ServiceClassUuid::ContinuousGlucoseMonitoring: return QBluetoothServiceDiscoveryAgent::tr("Continuous Glucose Monitoring");
}
return QString();
@@ -853,33 +750,31 @@ QString QBluetoothUuid::serviceClassToString(QBluetoothUuid::ServiceClassUuid uu
QString QBluetoothUuid::protocolToString(QBluetoothUuid::ProtocolUuid uuid)
{
switch (uuid) {
- case QBluetoothUuid::Sdp: return QBluetoothServiceDiscoveryAgent::tr("Service Discovery Protocol");
- case QBluetoothUuid::Udp: return QBluetoothServiceDiscoveryAgent::tr("User Datagram Protocol");
- case QBluetoothUuid::Rfcomm: return QBluetoothServiceDiscoveryAgent::tr("Radio Frequency Communication");
- case QBluetoothUuid::Tcp: return QBluetoothServiceDiscoveryAgent::tr("Transmission Control Protocol");
- case QBluetoothUuid::TcsBin: return QBluetoothServiceDiscoveryAgent::tr("Telephony Control Specification - Binary");
- case QBluetoothUuid::TcsAt: return QBluetoothServiceDiscoveryAgent::tr("Telephony Control Specification - AT");
- case QBluetoothUuid::Att: return QBluetoothServiceDiscoveryAgent::tr("Attribute Protocol");
- case QBluetoothUuid::Obex: return QBluetoothServiceDiscoveryAgent::tr("Object Exchange Protocol");
- case QBluetoothUuid::Ip: return QBluetoothServiceDiscoveryAgent::tr("Internet Protocol");
- case QBluetoothUuid::Ftp: return QBluetoothServiceDiscoveryAgent::tr("File Transfer Protocol");
- case QBluetoothUuid::Http: return QBluetoothServiceDiscoveryAgent::tr("Hypertext Transfer Protocol");
- case QBluetoothUuid::Wsp: return QBluetoothServiceDiscoveryAgent::tr("Wireless Short Packet Protocol");
- case QBluetoothUuid::Bnep: return QBluetoothServiceDiscoveryAgent::tr("Bluetooth Network Encapsulation Protocol");
- case QBluetoothUuid::Upnp: return QBluetoothServiceDiscoveryAgent::tr("Extended Service Discovery Protocol");
- case QBluetoothUuid::Hidp: return QBluetoothServiceDiscoveryAgent::tr("Human Interface Device Protocol");
- case QBluetoothUuid::HardcopyControlChannel: return QBluetoothServiceDiscoveryAgent::tr("Hardcopy Control Channel");
- case QBluetoothUuid::HardcopyDataChannel: return QBluetoothServiceDiscoveryAgent::tr("Hardcopy Data Channel");
- case QBluetoothUuid::HardcopyNotification: return QBluetoothServiceDiscoveryAgent::tr("Hardcopy Notification");
- case QBluetoothUuid::Avctp: return QBluetoothServiceDiscoveryAgent::tr("Audio/Video Control Transport Protocol");
- case QBluetoothUuid::Avdtp: return QBluetoothServiceDiscoveryAgent::tr("Audio/Video Distribution Transport Protocol");
- case QBluetoothUuid::Cmtp: return QBluetoothServiceDiscoveryAgent::tr("Common ISDN Access Protocol");
- case QBluetoothUuid::UdiCPlain: return QBluetoothServiceDiscoveryAgent::tr("UdiCPlain");
- case QBluetoothUuid::McapControlChannel: return QBluetoothServiceDiscoveryAgent::tr("Multi-Channel Adaptation Protocol - Control");
- case QBluetoothUuid::McapDataChannel: return QBluetoothServiceDiscoveryAgent::tr("Multi-Channel Adaptation Protocol - Data");
- case QBluetoothUuid::L2cap: return QBluetoothServiceDiscoveryAgent::tr("Layer 2 Control Protocol");
- default:
- break;
+ case QBluetoothUuid::ProtocolUuid::Sdp: return QBluetoothServiceDiscoveryAgent::tr("Service Discovery Protocol");
+ case QBluetoothUuid::ProtocolUuid::Udp: return QBluetoothServiceDiscoveryAgent::tr("User Datagram Protocol");
+ case QBluetoothUuid::ProtocolUuid::Rfcomm: return QBluetoothServiceDiscoveryAgent::tr("Radio Frequency Communication");
+ case QBluetoothUuid::ProtocolUuid::Tcp: return QBluetoothServiceDiscoveryAgent::tr("Transmission Control Protocol");
+ case QBluetoothUuid::ProtocolUuid::TcsBin: return QBluetoothServiceDiscoveryAgent::tr("Telephony Control Specification - Binary");
+ case QBluetoothUuid::ProtocolUuid::TcsAt: return QBluetoothServiceDiscoveryAgent::tr("Telephony Control Specification - AT");
+ case QBluetoothUuid::ProtocolUuid::Att: return QBluetoothServiceDiscoveryAgent::tr("Attribute Protocol");
+ case QBluetoothUuid::ProtocolUuid::Obex: return QBluetoothServiceDiscoveryAgent::tr("Object Exchange Protocol");
+ case QBluetoothUuid::ProtocolUuid::Ip: return QBluetoothServiceDiscoveryAgent::tr("Internet Protocol");
+ case QBluetoothUuid::ProtocolUuid::Ftp: return QBluetoothServiceDiscoveryAgent::tr("File Transfer Protocol");
+ case QBluetoothUuid::ProtocolUuid::Http: return QBluetoothServiceDiscoveryAgent::tr("Hypertext Transfer Protocol");
+ case QBluetoothUuid::ProtocolUuid::Wsp: return QBluetoothServiceDiscoveryAgent::tr("Wireless Short Packet Protocol");
+ case QBluetoothUuid::ProtocolUuid::Bnep: return QBluetoothServiceDiscoveryAgent::tr("Bluetooth Network Encapsulation Protocol");
+ case QBluetoothUuid::ProtocolUuid::Upnp: return QBluetoothServiceDiscoveryAgent::tr("Extended Service Discovery Protocol");
+ case QBluetoothUuid::ProtocolUuid::Hidp: return QBluetoothServiceDiscoveryAgent::tr("Human Interface Device Protocol");
+ case QBluetoothUuid::ProtocolUuid::HardcopyControlChannel: return QBluetoothServiceDiscoveryAgent::tr("Hardcopy Control Channel");
+ case QBluetoothUuid::ProtocolUuid::HardcopyDataChannel: return QBluetoothServiceDiscoveryAgent::tr("Hardcopy Data Channel");
+ case QBluetoothUuid::ProtocolUuid::HardcopyNotification: return QBluetoothServiceDiscoveryAgent::tr("Hardcopy Notification");
+ case QBluetoothUuid::ProtocolUuid::Avctp: return QBluetoothServiceDiscoveryAgent::tr("Audio/Video Control Transport Protocol");
+ case QBluetoothUuid::ProtocolUuid::Avdtp: return QBluetoothServiceDiscoveryAgent::tr("Audio/Video Distribution Transport Protocol");
+ case QBluetoothUuid::ProtocolUuid::Cmtp: return QBluetoothServiceDiscoveryAgent::tr("Common ISDN Access Protocol");
+ case QBluetoothUuid::ProtocolUuid::UdiCPlain: return QBluetoothServiceDiscoveryAgent::tr("UdiCPlain");
+ case QBluetoothUuid::ProtocolUuid::McapControlChannel: return QBluetoothServiceDiscoveryAgent::tr("Multi-Channel Adaptation Protocol - Control");
+ case QBluetoothUuid::ProtocolUuid::McapDataChannel: return QBluetoothServiceDiscoveryAgent::tr("Multi-Channel Adaptation Protocol - Data");
+ case QBluetoothUuid::ProtocolUuid::L2cap: return QBluetoothServiceDiscoveryAgent::tr("Layer 2 Control Protocol");
}
return QString();
@@ -897,197 +792,197 @@ QString QBluetoothUuid::characteristicToString(CharacteristicType uuid)
{
switch (uuid) {
//: GAP: Generic Access Profile (Bluetooth)
- case QBluetoothUuid::DeviceName: return QBluetoothServiceDiscoveryAgent::tr("GAP Device Name");
+ case QBluetoothUuid::CharacteristicType::DeviceName: return QBluetoothServiceDiscoveryAgent::tr("GAP Device Name");
//: GAP: Generic Access Profile (Bluetooth)
- case QBluetoothUuid::Appearance: return QBluetoothServiceDiscoveryAgent::tr("GAP Appearance");
- case QBluetoothUuid::PeripheralPrivacyFlag:
+ case QBluetoothUuid::CharacteristicType::Appearance: return QBluetoothServiceDiscoveryAgent::tr("GAP Appearance");
+ case QBluetoothUuid::CharacteristicType::PeripheralPrivacyFlag:
//: GAP: Generic Access Profile (Bluetooth)
return QBluetoothServiceDiscoveryAgent::tr("GAP Peripheral Privacy Flag");
- case QBluetoothUuid::ReconnectionAddress:
+ case QBluetoothUuid::CharacteristicType::ReconnectionAddress:
//: GAP: Generic Access Profile (Bluetooth)
return QBluetoothServiceDiscoveryAgent::tr("GAP Reconnection Address");
- case QBluetoothUuid::PeripheralPreferredConnectionParameters:
+ case QBluetoothUuid::CharacteristicType::PeripheralPreferredConnectionParameters:
return QBluetoothServiceDiscoveryAgent::tr("GAP Peripheral Preferred Connection Parameters");
//: GATT: _G_eneric _Att_ribute Profile (Bluetooth)
- case QBluetoothUuid::ServiceChanged: return QBluetoothServiceDiscoveryAgent::tr("GATT Service Changed");
- case QBluetoothUuid::AlertLevel: return QBluetoothServiceDiscoveryAgent::tr("Alert Level");
- case QBluetoothUuid::TxPowerLevel: return QBluetoothServiceDiscoveryAgent::tr("TX Power");
- case QBluetoothUuid::DateTime: return QBluetoothServiceDiscoveryAgent::tr("Date Time");
- case QBluetoothUuid::DayOfWeek: return QBluetoothServiceDiscoveryAgent::tr("Day Of Week");
- case QBluetoothUuid::DayDateTime: return QBluetoothServiceDiscoveryAgent::tr("Day Date Time");
- case QBluetoothUuid::ExactTime256: return QBluetoothServiceDiscoveryAgent::tr("Exact Time 256");
- case QBluetoothUuid::DSTOffset: return QBluetoothServiceDiscoveryAgent::tr("DST Offset");
- case QBluetoothUuid::TimeZone: return QBluetoothServiceDiscoveryAgent::tr("Time Zone");
- case QBluetoothUuid::LocalTimeInformation:
+ case QBluetoothUuid::CharacteristicType::ServiceChanged: return QBluetoothServiceDiscoveryAgent::tr("GATT Service Changed");
+ case QBluetoothUuid::CharacteristicType::AlertLevel: return QBluetoothServiceDiscoveryAgent::tr("Alert Level");
+ case QBluetoothUuid::CharacteristicType::TxPowerLevel: return QBluetoothServiceDiscoveryAgent::tr("TX Power");
+ case QBluetoothUuid::CharacteristicType::DateTime: return QBluetoothServiceDiscoveryAgent::tr("Date Time");
+ case QBluetoothUuid::CharacteristicType::DayOfWeek: return QBluetoothServiceDiscoveryAgent::tr("Day Of Week");
+ case QBluetoothUuid::CharacteristicType::DayDateTime: return QBluetoothServiceDiscoveryAgent::tr("Day Date Time");
+ case QBluetoothUuid::CharacteristicType::ExactTime256: return QBluetoothServiceDiscoveryAgent::tr("Exact Time 256");
+ case QBluetoothUuid::CharacteristicType::DSTOffset: return QBluetoothServiceDiscoveryAgent::tr("DST Offset");
+ case QBluetoothUuid::CharacteristicType::TimeZone: return QBluetoothServiceDiscoveryAgent::tr("Time Zone");
+ case QBluetoothUuid::CharacteristicType::LocalTimeInformation:
return QBluetoothServiceDiscoveryAgent::tr("Local Time Information");
- case QBluetoothUuid::TimeWithDST: return QBluetoothServiceDiscoveryAgent::tr("Time With DST");
- case QBluetoothUuid::TimeAccuracy: return QBluetoothServiceDiscoveryAgent::tr("Time Accuracy");
- case QBluetoothUuid::TimeSource: return QBluetoothServiceDiscoveryAgent::tr("Time Source");
- case QBluetoothUuid::ReferenceTimeInformation:
+ case QBluetoothUuid::CharacteristicType::TimeWithDST: return QBluetoothServiceDiscoveryAgent::tr("Time With DST");
+ case QBluetoothUuid::CharacteristicType::TimeAccuracy: return QBluetoothServiceDiscoveryAgent::tr("Time Accuracy");
+ case QBluetoothUuid::CharacteristicType::TimeSource: return QBluetoothServiceDiscoveryAgent::tr("Time Source");
+ case QBluetoothUuid::CharacteristicType::ReferenceTimeInformation:
return QBluetoothServiceDiscoveryAgent::tr("Reference Time Information");
- case QBluetoothUuid::TimeUpdateControlPoint:
+ case QBluetoothUuid::CharacteristicType::TimeUpdateControlPoint:
return QBluetoothServiceDiscoveryAgent::tr("Time Update Control Point");
- case QBluetoothUuid::TimeUpdateState: return QBluetoothServiceDiscoveryAgent::tr("Time Update State");
- case QBluetoothUuid::GlucoseMeasurement: return QBluetoothServiceDiscoveryAgent::tr("Glucose Measurement");
- case QBluetoothUuid::BatteryLevel: return QBluetoothServiceDiscoveryAgent::tr("Battery Level");
- case QBluetoothUuid::TemperatureMeasurement:
+ case QBluetoothUuid::CharacteristicType::TimeUpdateState: return QBluetoothServiceDiscoveryAgent::tr("Time Update State");
+ case QBluetoothUuid::CharacteristicType::GlucoseMeasurement: return QBluetoothServiceDiscoveryAgent::tr("Glucose Measurement");
+ case QBluetoothUuid::CharacteristicType::BatteryLevel: return QBluetoothServiceDiscoveryAgent::tr("Battery Level");
+ case QBluetoothUuid::CharacteristicType::TemperatureMeasurement:
return QBluetoothServiceDiscoveryAgent::tr("Temperature Measurement");
- case QBluetoothUuid::TemperatureType: return QBluetoothServiceDiscoveryAgent::tr("Temperature Type");
- case QBluetoothUuid::IntermediateTemperature:
+ case QBluetoothUuid::CharacteristicType::TemperatureType: return QBluetoothServiceDiscoveryAgent::tr("Temperature Type");
+ case QBluetoothUuid::CharacteristicType::IntermediateTemperature:
return QBluetoothServiceDiscoveryAgent::tr("Intermediate Temperature");
- case QBluetoothUuid::MeasurementInterval: return QBluetoothServiceDiscoveryAgent::tr("Measurement Interval");
- case QBluetoothUuid::BootKeyboardInputReport: return QBluetoothServiceDiscoveryAgent::tr("Boot Keyboard Input Report");
- case QBluetoothUuid::SystemID: return QBluetoothServiceDiscoveryAgent::tr("System ID");
- case QBluetoothUuid::ModelNumberString: return QBluetoothServiceDiscoveryAgent::tr("Model Number String");
- case QBluetoothUuid::SerialNumberString: return QBluetoothServiceDiscoveryAgent::tr("Serial Number String");
- case QBluetoothUuid::FirmwareRevisionString: return QBluetoothServiceDiscoveryAgent::tr("Firmware Revision String");
- case QBluetoothUuid::HardwareRevisionString: return QBluetoothServiceDiscoveryAgent::tr("Hardware Revision String");
- case QBluetoothUuid::SoftwareRevisionString: return QBluetoothServiceDiscoveryAgent::tr("Software Revision String");
- case QBluetoothUuid::ManufacturerNameString: return QBluetoothServiceDiscoveryAgent::tr("Manufacturer Name String");
- case QBluetoothUuid::IEEE1107320601RegulatoryCertificationDataList:
+ case QBluetoothUuid::CharacteristicType::MeasurementInterval: return QBluetoothServiceDiscoveryAgent::tr("Measurement Interval");
+ case QBluetoothUuid::CharacteristicType::BootKeyboardInputReport: return QBluetoothServiceDiscoveryAgent::tr("Boot Keyboard Input Report");
+ case QBluetoothUuid::CharacteristicType::SystemID: return QBluetoothServiceDiscoveryAgent::tr("System ID");
+ case QBluetoothUuid::CharacteristicType::ModelNumberString: return QBluetoothServiceDiscoveryAgent::tr("Model Number String");
+ case QBluetoothUuid::CharacteristicType::SerialNumberString: return QBluetoothServiceDiscoveryAgent::tr("Serial Number String");
+ case QBluetoothUuid::CharacteristicType::FirmwareRevisionString: return QBluetoothServiceDiscoveryAgent::tr("Firmware Revision String");
+ case QBluetoothUuid::CharacteristicType::HardwareRevisionString: return QBluetoothServiceDiscoveryAgent::tr("Hardware Revision String");
+ case QBluetoothUuid::CharacteristicType::SoftwareRevisionString: return QBluetoothServiceDiscoveryAgent::tr("Software Revision String");
+ case QBluetoothUuid::CharacteristicType::ManufacturerNameString: return QBluetoothServiceDiscoveryAgent::tr("Manufacturer Name String");
+ case QBluetoothUuid::CharacteristicType::IEEE1107320601RegulatoryCertificationDataList:
return QBluetoothServiceDiscoveryAgent::tr("IEEE 11073 20601 Regulatory Certification Data List");
- case QBluetoothUuid::CurrentTime: return QBluetoothServiceDiscoveryAgent::tr("Current Time");
- case QBluetoothUuid::ScanRefresh: return QBluetoothServiceDiscoveryAgent::tr("Scan Refresh");
- case QBluetoothUuid::BootKeyboardOutputReport:
+ case QBluetoothUuid::CharacteristicType::CurrentTime: return QBluetoothServiceDiscoveryAgent::tr("Current Time");
+ case QBluetoothUuid::CharacteristicType::ScanRefresh: return QBluetoothServiceDiscoveryAgent::tr("Scan Refresh");
+ case QBluetoothUuid::CharacteristicType::BootKeyboardOutputReport:
return QBluetoothServiceDiscoveryAgent::tr("Boot Keyboard Output Report");
- case QBluetoothUuid::BootMouseInputReport: return QBluetoothServiceDiscoveryAgent::tr("Boot Mouse Input Report");
- case QBluetoothUuid::GlucoseMeasurementContext:
+ case QBluetoothUuid::CharacteristicType::BootMouseInputReport: return QBluetoothServiceDiscoveryAgent::tr("Boot Mouse Input Report");
+ case QBluetoothUuid::CharacteristicType::GlucoseMeasurementContext:
return QBluetoothServiceDiscoveryAgent::tr("Glucose Measurement Context");
- case QBluetoothUuid::BloodPressureMeasurement:
+ case QBluetoothUuid::CharacteristicType::BloodPressureMeasurement:
return QBluetoothServiceDiscoveryAgent::tr("Blood Pressure Measurement");
- case QBluetoothUuid::IntermediateCuffPressure:
+ case QBluetoothUuid::CharacteristicType::IntermediateCuffPressure:
return QBluetoothServiceDiscoveryAgent::tr("Intermediate Cuff Pressure");
- case QBluetoothUuid::HeartRateMeasurement: return QBluetoothServiceDiscoveryAgent::tr("Heart Rate Measurement");
- case QBluetoothUuid::BodySensorLocation: return QBluetoothServiceDiscoveryAgent::tr("Body Sensor Location");
- case QBluetoothUuid::HeartRateControlPoint: return QBluetoothServiceDiscoveryAgent::tr("Heart Rate Control Point");
- case QBluetoothUuid::AlertStatus: return QBluetoothServiceDiscoveryAgent::tr("Alert Status");
- case QBluetoothUuid::RingerControlPoint: return QBluetoothServiceDiscoveryAgent::tr("Ringer Control Point");
- case QBluetoothUuid::RingerSetting: return QBluetoothServiceDiscoveryAgent::tr("Ringer Setting");
- case QBluetoothUuid::AlertCategoryIDBitMask:
+ case QBluetoothUuid::CharacteristicType::HeartRateMeasurement: return QBluetoothServiceDiscoveryAgent::tr("Heart Rate Measurement");
+ case QBluetoothUuid::CharacteristicType::BodySensorLocation: return QBluetoothServiceDiscoveryAgent::tr("Body Sensor Location");
+ case QBluetoothUuid::CharacteristicType::HeartRateControlPoint: return QBluetoothServiceDiscoveryAgent::tr("Heart Rate Control Point");
+ case QBluetoothUuid::CharacteristicType::AlertStatus: return QBluetoothServiceDiscoveryAgent::tr("Alert Status");
+ case QBluetoothUuid::CharacteristicType::RingerControlPoint: return QBluetoothServiceDiscoveryAgent::tr("Ringer Control Point");
+ case QBluetoothUuid::CharacteristicType::RingerSetting: return QBluetoothServiceDiscoveryAgent::tr("Ringer Setting");
+ case QBluetoothUuid::CharacteristicType::AlertCategoryIDBitMask:
return QBluetoothServiceDiscoveryAgent::tr("Alert Category ID Bit Mask");
- case QBluetoothUuid::AlertCategoryID: return QBluetoothServiceDiscoveryAgent::tr("Alert Category ID");
- case QBluetoothUuid::AlertNotificationControlPoint:
+ case QBluetoothUuid::CharacteristicType::AlertCategoryID: return QBluetoothServiceDiscoveryAgent::tr("Alert Category ID");
+ case QBluetoothUuid::CharacteristicType::AlertNotificationControlPoint:
return QBluetoothServiceDiscoveryAgent::tr("Alert Notification Control Point");
- case QBluetoothUuid::UnreadAlertStatus: return QBluetoothServiceDiscoveryAgent::tr("Unread Alert Status");
- case QBluetoothUuid::NewAlert: return QBluetoothServiceDiscoveryAgent::tr("New Alert");
- case QBluetoothUuid::SupportedNewAlertCategory:
+ case QBluetoothUuid::CharacteristicType::UnreadAlertStatus: return QBluetoothServiceDiscoveryAgent::tr("Unread Alert Status");
+ case QBluetoothUuid::CharacteristicType::NewAlert: return QBluetoothServiceDiscoveryAgent::tr("New Alert");
+ case QBluetoothUuid::CharacteristicType::SupportedNewAlertCategory:
return QBluetoothServiceDiscoveryAgent::tr("Supported New Alert Category");
- case QBluetoothUuid::SupportedUnreadAlertCategory:
+ case QBluetoothUuid::CharacteristicType::SupportedUnreadAlertCategory:
return QBluetoothServiceDiscoveryAgent::tr("Supported Unread Alert Category");
- case QBluetoothUuid::BloodPressureFeature: return QBluetoothServiceDiscoveryAgent::tr("Blood Pressure Feature");
+ case QBluetoothUuid::CharacteristicType::BloodPressureFeature: return QBluetoothServiceDiscoveryAgent::tr("Blood Pressure Feature");
//: HID: Human Interface Device Profile (Bluetooth)
- case QBluetoothUuid::HIDInformation: return QBluetoothServiceDiscoveryAgent::tr("HID Information");
- case QBluetoothUuid::ReportMap: return QBluetoothServiceDiscoveryAgent::tr("Report Map");
+ case QBluetoothUuid::CharacteristicType::HIDInformation: return QBluetoothServiceDiscoveryAgent::tr("HID Information");
+ case QBluetoothUuid::CharacteristicType::ReportMap: return QBluetoothServiceDiscoveryAgent::tr("Report Map");
//: HID: Human Interface Device Profile (Bluetooth)
- case QBluetoothUuid::HIDControlPoint: return QBluetoothServiceDiscoveryAgent::tr("HID Control Point");
- case QBluetoothUuid::Report: return QBluetoothServiceDiscoveryAgent::tr("Report");
- case QBluetoothUuid::ProtocolMode: return QBluetoothServiceDiscoveryAgent::tr("Protocol Mode");
- case QBluetoothUuid::ScanIntervalWindow: return QBluetoothServiceDiscoveryAgent::tr("Scan Interval Window");
- case QBluetoothUuid::PnPID: return QBluetoothServiceDiscoveryAgent::tr("PnP ID");
- case QBluetoothUuid::GlucoseFeature: return QBluetoothServiceDiscoveryAgent::tr("Glucose Feature");
- case QBluetoothUuid::RecordAccessControlPoint:
+ case QBluetoothUuid::CharacteristicType::HIDControlPoint: return QBluetoothServiceDiscoveryAgent::tr("HID Control Point");
+ case QBluetoothUuid::CharacteristicType::Report: return QBluetoothServiceDiscoveryAgent::tr("Report");
+ case QBluetoothUuid::CharacteristicType::ProtocolMode: return QBluetoothServiceDiscoveryAgent::tr("Protocol Mode");
+ case QBluetoothUuid::CharacteristicType::ScanIntervalWindow: return QBluetoothServiceDiscoveryAgent::tr("Scan Interval Window");
+ case QBluetoothUuid::CharacteristicType::PnPID: return QBluetoothServiceDiscoveryAgent::tr("PnP ID");
+ case QBluetoothUuid::CharacteristicType::GlucoseFeature: return QBluetoothServiceDiscoveryAgent::tr("Glucose Feature");
+ case QBluetoothUuid::CharacteristicType::RecordAccessControlPoint:
//: Glucose Sensor patient record database.
return QBluetoothServiceDiscoveryAgent::tr("Record Access Control Point");
//: RSC: Running Speed and Cadence
- case QBluetoothUuid::RSCMeasurement: return QBluetoothServiceDiscoveryAgent::tr("RSC Measurement");
+ case QBluetoothUuid::CharacteristicType::RSCMeasurement: return QBluetoothServiceDiscoveryAgent::tr("RSC Measurement");
//: RSC: Running Speed and Cadence
- case QBluetoothUuid::RSCFeature: return QBluetoothServiceDiscoveryAgent::tr("RSC Feature");
- case QBluetoothUuid::SCControlPoint: return QBluetoothServiceDiscoveryAgent::tr("SC Control Point");
+ case QBluetoothUuid::CharacteristicType::RSCFeature: return QBluetoothServiceDiscoveryAgent::tr("RSC Feature");
+ case QBluetoothUuid::CharacteristicType::SCControlPoint: return QBluetoothServiceDiscoveryAgent::tr("SC Control Point");
//: CSC: Cycling Speed and Cadence
- case QBluetoothUuid::CSCMeasurement: return QBluetoothServiceDiscoveryAgent::tr("CSC Measurement");
+ case QBluetoothUuid::CharacteristicType::CSCMeasurement: return QBluetoothServiceDiscoveryAgent::tr("CSC Measurement");
//: CSC: Cycling Speed and Cadence
- case QBluetoothUuid::CSCFeature: return QBluetoothServiceDiscoveryAgent::tr("CSC Feature");
- case QBluetoothUuid::SensorLocation: return QBluetoothServiceDiscoveryAgent::tr("Sensor Location");
- case QBluetoothUuid::CyclingPowerMeasurement:
+ case QBluetoothUuid::CharacteristicType::CSCFeature: return QBluetoothServiceDiscoveryAgent::tr("CSC Feature");
+ case QBluetoothUuid::CharacteristicType::SensorLocation: return QBluetoothServiceDiscoveryAgent::tr("Sensor Location");
+ case QBluetoothUuid::CharacteristicType::CyclingPowerMeasurement:
return QBluetoothServiceDiscoveryAgent::tr("Cycling Power Measurement");
- case QBluetoothUuid::CyclingPowerVector: return QBluetoothServiceDiscoveryAgent::tr("Cycling Power Vector");
- case QBluetoothUuid::CyclingPowerFeature: return QBluetoothServiceDiscoveryAgent::tr("Cycling Power Feature");
- case QBluetoothUuid::CyclingPowerControlPoint:
+ case QBluetoothUuid::CharacteristicType::CyclingPowerVector: return QBluetoothServiceDiscoveryAgent::tr("Cycling Power Vector");
+ case QBluetoothUuid::CharacteristicType::CyclingPowerFeature: return QBluetoothServiceDiscoveryAgent::tr("Cycling Power Feature");
+ case QBluetoothUuid::CharacteristicType::CyclingPowerControlPoint:
return QBluetoothServiceDiscoveryAgent::tr("Cycling Power Control Point");
- case QBluetoothUuid::LocationAndSpeed: return QBluetoothServiceDiscoveryAgent::tr("Location And Speed");
- case QBluetoothUuid::Navigation: return QBluetoothServiceDiscoveryAgent::tr("Navigation");
- case QBluetoothUuid::PositionQuality: return QBluetoothServiceDiscoveryAgent::tr("Position Quality");
- case QBluetoothUuid::LNFeature: return QBluetoothServiceDiscoveryAgent::tr("LN Feature");
- case QBluetoothUuid::LNControlPoint: return QBluetoothServiceDiscoveryAgent::tr("LN Control Point");
- case QBluetoothUuid::MagneticDeclination:
+ case QBluetoothUuid::CharacteristicType::LocationAndSpeed: return QBluetoothServiceDiscoveryAgent::tr("Location And Speed");
+ case QBluetoothUuid::CharacteristicType::Navigation: return QBluetoothServiceDiscoveryAgent::tr("Navigation");
+ case QBluetoothUuid::CharacteristicType::PositionQuality: return QBluetoothServiceDiscoveryAgent::tr("Position Quality");
+ case QBluetoothUuid::CharacteristicType::LNFeature: return QBluetoothServiceDiscoveryAgent::tr("LN Feature");
+ case QBluetoothUuid::CharacteristicType::LNControlPoint: return QBluetoothServiceDiscoveryAgent::tr("LN Control Point");
+ case QBluetoothUuid::CharacteristicType::MagneticDeclination:
//: Angle between geographic and magnetic north
return QBluetoothServiceDiscoveryAgent::tr("Magnetic Declination");
//: Above/below sea level
- case QBluetoothUuid::Elevation: return QBluetoothServiceDiscoveryAgent::tr("Elevation");
- case QBluetoothUuid::Pressure: return QBluetoothServiceDiscoveryAgent::tr("Pressure");
- case QBluetoothUuid::Temperature: return QBluetoothServiceDiscoveryAgent::tr("Temperature");
- case QBluetoothUuid::Humidity: return QBluetoothServiceDiscoveryAgent::tr("Humidity");
+ case QBluetoothUuid::CharacteristicType::Elevation: return QBluetoothServiceDiscoveryAgent::tr("Elevation");
+ case QBluetoothUuid::CharacteristicType::Pressure: return QBluetoothServiceDiscoveryAgent::tr("Pressure");
+ case QBluetoothUuid::CharacteristicType::Temperature: return QBluetoothServiceDiscoveryAgent::tr("Temperature");
+ case QBluetoothUuid::CharacteristicType::Humidity: return QBluetoothServiceDiscoveryAgent::tr("Humidity");
//: Wind speed while standing
- case QBluetoothUuid::TrueWindSpeed: return QBluetoothServiceDiscoveryAgent::tr("True Wind Speed");
- case QBluetoothUuid::TrueWindDirection : return QBluetoothServiceDiscoveryAgent::tr("True Wind Direction");
- case QBluetoothUuid::ApparentWindSpeed:
+ case QBluetoothUuid::CharacteristicType::TrueWindSpeed: return QBluetoothServiceDiscoveryAgent::tr("True Wind Speed");
+ case QBluetoothUuid::CharacteristicType::TrueWindDirection : return QBluetoothServiceDiscoveryAgent::tr("True Wind Direction");
+ case QBluetoothUuid::CharacteristicType::ApparentWindSpeed:
//: Wind speed while observer is moving
return QBluetoothServiceDiscoveryAgent::tr("Apparent Wind Speed");
- case QBluetoothUuid::ApparentWindDirection: return QBluetoothServiceDiscoveryAgent::tr("Apparent Wind Direction");
- case QBluetoothUuid::GustFactor:
+ case QBluetoothUuid::CharacteristicType::ApparentWindDirection: return QBluetoothServiceDiscoveryAgent::tr("Apparent Wind Direction");
+ case QBluetoothUuid::CharacteristicType::GustFactor:
//: Factor by which wind gust is stronger than average wind
return QBluetoothServiceDiscoveryAgent::tr("Gust Factor");
- case QBluetoothUuid::PollenConcentration: return QBluetoothServiceDiscoveryAgent::tr("Pollen Concentration");
- case QBluetoothUuid::UVIndex: return QBluetoothServiceDiscoveryAgent::tr("UV Index");
- case QBluetoothUuid::Irradiance: return QBluetoothServiceDiscoveryAgent::tr("Irradiance");
- case QBluetoothUuid::Rainfall: return QBluetoothServiceDiscoveryAgent::tr("Rainfall");
- case QBluetoothUuid::WindChill: return QBluetoothServiceDiscoveryAgent::tr("Wind Chill");
- case QBluetoothUuid::HeatIndex: return QBluetoothServiceDiscoveryAgent::tr("Heat Index");
- case QBluetoothUuid::DewPoint: return QBluetoothServiceDiscoveryAgent::tr("Dew Point");
- case QBluetoothUuid::DescriptorValueChanged:
+ case QBluetoothUuid::CharacteristicType::PollenConcentration: return QBluetoothServiceDiscoveryAgent::tr("Pollen Concentration");
+ case QBluetoothUuid::CharacteristicType::UVIndex: return QBluetoothServiceDiscoveryAgent::tr("UV Index");
+ case QBluetoothUuid::CharacteristicType::Irradiance: return QBluetoothServiceDiscoveryAgent::tr("Irradiance");
+ case QBluetoothUuid::CharacteristicType::Rainfall: return QBluetoothServiceDiscoveryAgent::tr("Rainfall");
+ case QBluetoothUuid::CharacteristicType::WindChill: return QBluetoothServiceDiscoveryAgent::tr("Wind Chill");
+ case QBluetoothUuid::CharacteristicType::HeatIndex: return QBluetoothServiceDiscoveryAgent::tr("Heat Index");
+ case QBluetoothUuid::CharacteristicType::DewPoint: return QBluetoothServiceDiscoveryAgent::tr("Dew Point");
+ case QBluetoothUuid::CharacteristicType::DescriptorValueChanged:
//: Environmental sensing related
return QBluetoothServiceDiscoveryAgent::tr("Descriptor Value Changed");
- case QBluetoothUuid::AerobicHeartRateLowerLimit:
+ case QBluetoothUuid::CharacteristicType::AerobicHeartRateLowerLimit:
return QBluetoothServiceDiscoveryAgent::tr("Aerobic Heart Rate Lower Limit");
- case QBluetoothUuid::AerobicHeartRateUpperLimit:
+ case QBluetoothUuid::CharacteristicType::AerobicHeartRateUpperLimit:
return QBluetoothServiceDiscoveryAgent::tr("Aerobic Heart Rate Upper Limit");
- case QBluetoothUuid::AerobicThreshold: return QBluetoothServiceDiscoveryAgent::tr("Aerobic Threshold");
+ case QBluetoothUuid::CharacteristicType::AerobicThreshold: return QBluetoothServiceDiscoveryAgent::tr("Aerobic Threshold");
//: Age of person
- case QBluetoothUuid::Age: return QBluetoothServiceDiscoveryAgent::tr("Age");
- case QBluetoothUuid::AnaerobicHeartRateLowerLimit:
+ case QBluetoothUuid::CharacteristicType::Age: return QBluetoothServiceDiscoveryAgent::tr("Age");
+ case QBluetoothUuid::CharacteristicType::AnaerobicHeartRateLowerLimit:
return QBluetoothServiceDiscoveryAgent::tr("Anaerobic Heart Rate Lower Limit");
- case QBluetoothUuid::AnaerobicHeartRateUpperLimit:
+ case QBluetoothUuid::CharacteristicType::AnaerobicHeartRateUpperLimit:
return QBluetoothServiceDiscoveryAgent::tr("Anaerobic Heart Rate Upper Limit");
- case QBluetoothUuid::AnaerobicThreshold: return QBluetoothServiceDiscoveryAgent::tr("Anaerobic Threshold");
- case QBluetoothUuid::DateOfBirth: return QBluetoothServiceDiscoveryAgent::tr("Date Of Birth");
- case QBluetoothUuid::DateOfThresholdAssessment: return QBluetoothServiceDiscoveryAgent::tr("Date Of Threshold Assessment");
- case QBluetoothUuid::EmailAddress: return QBluetoothServiceDiscoveryAgent::tr("Email Address");
- case QBluetoothUuid::FatBurnHeartRateLowerLimit:
+ case QBluetoothUuid::CharacteristicType::AnaerobicThreshold: return QBluetoothServiceDiscoveryAgent::tr("Anaerobic Threshold");
+ case QBluetoothUuid::CharacteristicType::DateOfBirth: return QBluetoothServiceDiscoveryAgent::tr("Date Of Birth");
+ case QBluetoothUuid::CharacteristicType::DateOfThresholdAssessment: return QBluetoothServiceDiscoveryAgent::tr("Date Of Threshold Assessment");
+ case QBluetoothUuid::CharacteristicType::EmailAddress: return QBluetoothServiceDiscoveryAgent::tr("Email Address");
+ case QBluetoothUuid::CharacteristicType::FatBurnHeartRateLowerLimit:
return QBluetoothServiceDiscoveryAgent::tr("Fat Burn Heart Rate Lower Limit");
- case QBluetoothUuid::FatBurnHeartRateUpperLimit:
+ case QBluetoothUuid::CharacteristicType::FatBurnHeartRateUpperLimit:
return QBluetoothServiceDiscoveryAgent::tr("Fat Burn Heart Rate Upper Limit");
- case QBluetoothUuid::FirstName: return QBluetoothServiceDiscoveryAgent::tr("First Name");
- case QBluetoothUuid::FiveZoneHeartRateLimits: return QBluetoothServiceDiscoveryAgent::tr("5-Zone Heart Rate Limits");
- case QBluetoothUuid::Gender: return QBluetoothServiceDiscoveryAgent::tr("Gender");
- case QBluetoothUuid::HeartRateMax: return QBluetoothServiceDiscoveryAgent::tr("Heart Rate Maximum");
+ case QBluetoothUuid::CharacteristicType::FirstName: return QBluetoothServiceDiscoveryAgent::tr("First Name");
+ case QBluetoothUuid::CharacteristicType::FiveZoneHeartRateLimits: return QBluetoothServiceDiscoveryAgent::tr("5-Zone Heart Rate Limits");
+ case QBluetoothUuid::CharacteristicType::Gender: return QBluetoothServiceDiscoveryAgent::tr("Gender");
+ case QBluetoothUuid::CharacteristicType::HeartRateMax: return QBluetoothServiceDiscoveryAgent::tr("Heart Rate Maximum");
//: Height of a person
- case QBluetoothUuid::Height: return QBluetoothServiceDiscoveryAgent::tr("Height");
- case QBluetoothUuid::HipCircumference: return QBluetoothServiceDiscoveryAgent::tr("Hip Circumference");
- case QBluetoothUuid::LastName: return QBluetoothServiceDiscoveryAgent::tr("Last Name");
- case QBluetoothUuid::MaximumRecommendedHeartRate:
+ case QBluetoothUuid::CharacteristicType::Height: return QBluetoothServiceDiscoveryAgent::tr("Height");
+ case QBluetoothUuid::CharacteristicType::HipCircumference: return QBluetoothServiceDiscoveryAgent::tr("Hip Circumference");
+ case QBluetoothUuid::CharacteristicType::LastName: return QBluetoothServiceDiscoveryAgent::tr("Last Name");
+ case QBluetoothUuid::CharacteristicType::MaximumRecommendedHeartRate:
return QBluetoothServiceDiscoveryAgent::tr("Maximum Recommended Heart Rate");
- case QBluetoothUuid::RestingHeartRate: return QBluetoothServiceDiscoveryAgent::tr("Resting Heart Rate");
- case QBluetoothUuid::SportTypeForAerobicAnaerobicThresholds:
+ case QBluetoothUuid::CharacteristicType::RestingHeartRate: return QBluetoothServiceDiscoveryAgent::tr("Resting Heart Rate");
+ case QBluetoothUuid::CharacteristicType::SportTypeForAerobicAnaerobicThresholds:
return QBluetoothServiceDiscoveryAgent::tr("Sport Type For Aerobic/Anaerobic Thresholds");
- case QBluetoothUuid::ThreeZoneHeartRateLimits: return QBluetoothServiceDiscoveryAgent::tr("3-Zone Heart Rate Limits");
- case QBluetoothUuid::TwoZoneHeartRateLimits: return QBluetoothServiceDiscoveryAgent::tr("2-Zone Heart Rate Limits");
- case QBluetoothUuid::VO2Max: return QBluetoothServiceDiscoveryAgent::tr("Oxygen Uptake");
- case QBluetoothUuid::WaistCircumference: return QBluetoothServiceDiscoveryAgent::tr("Waist Circumference");
- case QBluetoothUuid::Weight: return QBluetoothServiceDiscoveryAgent::tr("Weight");
- case QBluetoothUuid::DatabaseChangeIncrement:
+ case QBluetoothUuid::CharacteristicType::ThreeZoneHeartRateLimits: return QBluetoothServiceDiscoveryAgent::tr("3-Zone Heart Rate Limits");
+ case QBluetoothUuid::CharacteristicType::TwoZoneHeartRateLimits: return QBluetoothServiceDiscoveryAgent::tr("2-Zone Heart Rate Limits");
+ case QBluetoothUuid::CharacteristicType::VO2Max: return QBluetoothServiceDiscoveryAgent::tr("Oxygen Uptake");
+ case QBluetoothUuid::CharacteristicType::WaistCircumference: return QBluetoothServiceDiscoveryAgent::tr("Waist Circumference");
+ case QBluetoothUuid::CharacteristicType::Weight: return QBluetoothServiceDiscoveryAgent::tr("Weight");
+ case QBluetoothUuid::CharacteristicType::DatabaseChangeIncrement:
//: Environmental sensing related
return QBluetoothServiceDiscoveryAgent::tr("Database Change Increment");
- case QBluetoothUuid::UserIndex: return QBluetoothServiceDiscoveryAgent::tr("User Index");
- case QBluetoothUuid::BodyCompositionFeature: return QBluetoothServiceDiscoveryAgent::tr("Body Composition Feature");
- case QBluetoothUuid::BodyCompositionMeasurement: return QBluetoothServiceDiscoveryAgent::tr("Body Composition Measurement");
- case QBluetoothUuid::WeightMeasurement: return QBluetoothServiceDiscoveryAgent::tr("Weight Measurement");
- case QBluetoothUuid::UserControlPoint: return QBluetoothServiceDiscoveryAgent::tr("User Control Point");
- case QBluetoothUuid::MagneticFluxDensity2D: return QBluetoothServiceDiscoveryAgent::tr("Magnetic Flux Density 2D");
- case QBluetoothUuid::MagneticFluxDensity3D: return QBluetoothServiceDiscoveryAgent::tr("Magnetic Flux Density 3D");
- case QBluetoothUuid::Language: return QBluetoothServiceDiscoveryAgent::tr("Language");
- case QBluetoothUuid::BarometricPressureTrend: return QBluetoothServiceDiscoveryAgent::tr("Barometric Pressure Trend");
- default:
- break;
+ case QBluetoothUuid::CharacteristicType::UserIndex: return QBluetoothServiceDiscoveryAgent::tr("User Index");
+ case QBluetoothUuid::CharacteristicType::BodyCompositionFeature: return QBluetoothServiceDiscoveryAgent::tr("Body Composition Feature");
+ case QBluetoothUuid::CharacteristicType::BodyCompositionMeasurement: return QBluetoothServiceDiscoveryAgent::tr("Body Composition Measurement");
+ case QBluetoothUuid::CharacteristicType::WeightMeasurement: return QBluetoothServiceDiscoveryAgent::tr("Weight Measurement");
+ case QBluetoothUuid::CharacteristicType::WeightScaleFeature:
+ return QBluetoothServiceDiscoveryAgent::tr("Weight Scale Feature");
+ case QBluetoothUuid::CharacteristicType::UserControlPoint: return QBluetoothServiceDiscoveryAgent::tr("User Control Point");
+ case QBluetoothUuid::CharacteristicType::MagneticFluxDensity2D: return QBluetoothServiceDiscoveryAgent::tr("Magnetic Flux Density 2D");
+ case QBluetoothUuid::CharacteristicType::MagneticFluxDensity3D: return QBluetoothServiceDiscoveryAgent::tr("Magnetic Flux Density 3D");
+ case QBluetoothUuid::CharacteristicType::Language: return QBluetoothServiceDiscoveryAgent::tr("Language");
+ case QBluetoothUuid::CharacteristicType::BarometricPressureTrend: return QBluetoothServiceDiscoveryAgent::tr("Barometric Pressure Trend");
}
return QString();
@@ -1104,49 +999,52 @@ QString QBluetoothUuid::characteristicToString(CharacteristicType uuid)
QString QBluetoothUuid::descriptorToString(QBluetoothUuid::DescriptorType uuid)
{
switch (uuid) {
- case QBluetoothUuid::CharacteristicExtendedProperties:
+ case QBluetoothUuid::DescriptorType::UnknownDescriptorType:
+ break; // returns {} below
+ case QBluetoothUuid::DescriptorType::CharacteristicExtendedProperties:
return QBluetoothServiceDiscoveryAgent::tr("Characteristic Extended Properties");
- case QBluetoothUuid::CharacteristicUserDescription:
+ case QBluetoothUuid::DescriptorType::CharacteristicUserDescription:
return QBluetoothServiceDiscoveryAgent::tr("Characteristic User Description");
- case QBluetoothUuid::ClientCharacteristicConfiguration:
+ case QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration:
return QBluetoothServiceDiscoveryAgent::tr("Client Characteristic Configuration");
- case QBluetoothUuid::ServerCharacteristicConfiguration:
+ case QBluetoothUuid::DescriptorType::ServerCharacteristicConfiguration:
return QBluetoothServiceDiscoveryAgent::tr("Server Characteristic Configuration");
- case QBluetoothUuid::CharacteristicPresentationFormat:
+ case QBluetoothUuid::DescriptorType::CharacteristicPresentationFormat:
return QBluetoothServiceDiscoveryAgent::tr("Characteristic Presentation Format");
- case QBluetoothUuid::CharacteristicAggregateFormat:
+ case QBluetoothUuid::DescriptorType::CharacteristicAggregateFormat:
return QBluetoothServiceDiscoveryAgent::tr("Characteristic Aggregate Format");
- case QBluetoothUuid::ValidRange:
+ case QBluetoothUuid::DescriptorType::ValidRange:
return QBluetoothServiceDiscoveryAgent::tr("Valid Range");
- case QBluetoothUuid::ExternalReportReference:
+ case QBluetoothUuid::DescriptorType::ExternalReportReference:
return QBluetoothServiceDiscoveryAgent::tr("External Report Reference");
- case QBluetoothUuid::ReportReference:
+ case QBluetoothUuid::DescriptorType::ReportReference:
return QBluetoothServiceDiscoveryAgent::tr("Report Reference");
- case QBluetoothUuid::EnvironmentalSensingConfiguration:
+ case QBluetoothUuid::DescriptorType::EnvironmentalSensingConfiguration:
return QBluetoothServiceDiscoveryAgent::tr("Environmental Sensing Configuration");
- case QBluetoothUuid::EnvironmentalSensingMeasurement:
+ case QBluetoothUuid::DescriptorType::EnvironmentalSensingMeasurement:
return QBluetoothServiceDiscoveryAgent::tr("Environmental Sensing Measurement");
- case QBluetoothUuid::EnvironmentalSensingTriggerSetting:
+ case QBluetoothUuid::DescriptorType::EnvironmentalSensingTriggerSetting:
return QBluetoothServiceDiscoveryAgent::tr("Environmental Sensing Trigger Setting");
- default:
- break;
}
return QString();
}
/*!
- Returns \c true if \a other is equal to this Bluetooth UUID, otherwise \c false.
+ \fn bool QBluetoothUuid::operator==(const QBluetoothUuid &a, const QBluetoothUuid &b)
+ \brief Returns \c true if \a a is equal to \a b, otherwise \c false.
*/
-bool QBluetoothUuid::operator==(const QBluetoothUuid &other) const
-{
- return QUuid::operator==(other);
-}
/*!
- \fn bool QBluetoothUuid::operator!=(const QBluetoothUuid &other) const
- Returns \c true if \a other is not equal to this Bluetooth UUID, otherwise \c false.
- \since 5.7
+ \fn bool QBluetoothUuid::operator!=(const QBluetoothUuid &a, const QBluetoothUuid &b)
+ \brief Returns \c true if \a a is not equal to \a b, otherwise \c false.
*/
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug debug, const QBluetoothUuid &uuid)
+{
+ debug << uuid.toString();
+ return debug;
+}
+#endif
QT_END_NAMESPACE
diff --git a/src/bluetooth/qbluetoothuuid.h b/src/bluetooth/qbluetoothuuid.h
index dd587694..c19928ce 100644
--- a/src/bluetooth/qbluetoothuuid.h
+++ b/src/bluetooth/qbluetoothuuid.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QBLUETOOTHUUID_H
#define QBLUETOOTHUUID_H
@@ -48,18 +12,23 @@
#include <QtCore/QDebug>
+#if defined(Q_OS_DARWIN) || defined(Q_QDOC)
+Q_FORWARD_DECLARE_OBJC_CLASS(CBUUID);
+#endif
+
QT_BEGIN_NAMESPACE
+#if !defined(QT_SUPPORTS_INT128)
struct quint128
{
quint8 data[16];
};
+#endif
class Q_BLUETOOTH_EXPORT QBluetoothUuid : public QUuid
{
public:
- //TODO Qt 6: Convert enums to scoped enums (see QTBUG-65831)
- enum ProtocolUuid {
+ enum class ProtocolUuid {
Sdp = 0x0001,
Udp = 0x0002,
Rfcomm = 0x0003,
@@ -87,7 +56,7 @@ public:
L2cap = 0x0100
};
- enum ServiceClassUuid {
+ enum class ServiceClassUuid {
ServiceDiscoveryServer = 0x1000,
BrowseGroupDescriptor = 0x1001,
PublicBrowseGroup = 0x1002,
@@ -181,7 +150,7 @@ public:
ContinuousGlucoseMonitoring = 0x181f
};
- enum CharacteristicType {
+ enum class CharacteristicType {
DeviceName = 0x2a00,
Appearance = 0x2a01,
PeripheralPrivacyFlag = 0x2a02,
@@ -348,7 +317,7 @@ public:
BarometricPressureTrend = 0x2aa3
};
- enum DescriptorType {
+ enum class DescriptorType {
UnknownDescriptorType = 0x0,
CharacteristicExtendedProperties = 0x2900,
CharacteristicUserDescription = 0x2901,
@@ -366,29 +335,67 @@ public:
EnvironmentalSensingTriggerSetting = 0x290d
};
- QBluetoothUuid();
- QBluetoothUuid(ProtocolUuid uuid);
- QBluetoothUuid(ServiceClassUuid uuid);
- QBluetoothUuid(CharacteristicType uuid);
- QBluetoothUuid(DescriptorType uuid);
- explicit QBluetoothUuid(quint16 uuid);
- explicit QBluetoothUuid(quint32 uuid);
+ constexpr QBluetoothUuid() noexcept {};
+
+ // values below are based on Bluetooth BASE_UUID
+ constexpr QBluetoothUuid(ProtocolUuid uuid) noexcept
+ : QBluetoothUuid(static_cast<quint32>(uuid)) {};
+ constexpr QBluetoothUuid(ServiceClassUuid uuid) noexcept
+ : QBluetoothUuid(static_cast<quint32>(uuid)) {};
+ constexpr QBluetoothUuid(CharacteristicType uuid) noexcept
+ : QBluetoothUuid(static_cast<quint32>(uuid)) {};
+ constexpr QBluetoothUuid(DescriptorType uuid) noexcept
+ : QBluetoothUuid(static_cast<quint32>(uuid)) {};
+ explicit constexpr QBluetoothUuid(quint16 uuid) noexcept
+ : QBluetoothUuid(quint32{uuid}) {};
+ explicit constexpr QBluetoothUuid(quint32 uuid) noexcept
+ : QUuid(uuid, 0x0, 0x1000, 0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb) {};
+ // end of bluetooth-specific constructors; rest is essentially `using QUuid::QUuid;`
+
+ using QUuid::QUuid;
+#if QT_BLUETOOTH_REMOVED_SINCE(6, 6)
explicit QBluetoothUuid(quint128 uuid);
+#endif
+ QT6_ONLY(QT_POST_CXX17_API_IN_EXPORTED_CLASS) // quint128 changes based on QT_SUPPORTS_INT128!
+ explicit QBluetoothUuid(quint128 uuid, QSysInfo::Endian order = QSysInfo::BigEndian) noexcept
+ : QUuid{fromBytes(&uuid, order)} {}
+#if QT_BLUETOOTH_REMOVED_SINCE(6, 6) // actually 6.3 (cf. QUuid)
explicit QBluetoothUuid(const QString &uuid);
- QBluetoothUuid(const QBluetoothUuid &uuid);
- QBluetoothUuid(const QUuid &uuid);
- ~QBluetoothUuid();
-
- bool operator==(const QBluetoothUuid &other) const;
- bool operator!=(const QBluetoothUuid &other) const { return !operator==(other); }
+#endif
+ QBluetoothUuid(const QBluetoothUuid &uuid) = default;
+ QT_BLUETOOTH_INLINE_SINCE(6, 6)
+ QBluetoothUuid(QUuid QT6_ONLY(const &)uuid);
+ ~QBluetoothUuid() = default;
QBluetoothUuid &operator=(const QBluetoothUuid &other) = default;
+ friend bool operator==(const QBluetoothUuid &a, const QBluetoothUuid &b)
+ {
+ return static_cast<QUuid>(a) == static_cast<QUuid>(b);
+ }
+ friend bool operator!=(const QBluetoothUuid &a, const QBluetoothUuid &b) { return !(a == b); }
+#ifndef QT_NO_DEBUG_STREAM
+ friend Q_BLUETOOTH_EXPORT QDebug operator<<(QDebug debug, const QBluetoothUuid &uuid);
+#if QT_BLUETOOTH_REMOVED_SINCE(6, 6)
+ static QDebug streamingOperator(QDebug debug, const QBluetoothUuid &uuid);
+#endif
+#endif
int minimumSize() const;
quint16 toUInt16(bool *ok = nullptr) const;
quint32 toUInt32(bool *ok = nullptr) const;
+
+#if QT_BLUETOOTH_REMOVED_SINCE(6, 6)
quint128 toUInt128() const;
+#endif
+#if defined(Q_QDOC) || !defined(QT_SUPPORTS_INT128) // otherwise falls back to QUuid::toUint128()
+ quint128 toUInt128(QSysInfo::Endian order = QSysInfo::BigEndian) const noexcept;
+#endif
+
+#if defined(Q_OS_DARWIN) || defined(Q_QDOC)
+ static QBluetoothUuid fromCBUUID(CBUUID *cbUuid);
+ CBUUID *toCBUUID() const Q_DECL_NS_RETURNS_AUTORELEASED;
+#endif
static QString serviceClassToString(ServiceClassUuid uuid);
static QString protocolToString(ProtocolUuid uuid);
@@ -396,6 +403,14 @@ public:
static QString descriptorToString(DescriptorType uuid);
};
+#if QT_BLUETOOTH_INLINE_IMPL_SINCE(6, 6)
+QBluetoothUuid::QBluetoothUuid(QUuid QT6_ONLY(const &)uuid)
+ : QUuid(uuid)
+{
+}
+#endif
+
+
#ifndef QT_NO_DATASTREAM
inline QDataStream &operator<<(QDataStream &s, const QBluetoothUuid &uuid)
{
@@ -408,17 +423,8 @@ inline QDataStream &operator>>(QDataStream &s, QBluetoothUuid &uuid)
}
#endif
-#ifndef QT_NO_DEBUG_STREAM
-/// TODO: Move implementation to .cpp, uninline and add Q_BLUETOOTH_EXPORT for Qt 6
-inline QDebug operator<<(QDebug debug, const QBluetoothUuid &uuid)
-{
- debug << uuid.toString();
- return debug;
-}
-#endif
-
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(QBluetoothUuid)
+QT_DECL_METATYPE_EXTERN(QBluetoothUuid, Q_BLUETOOTH_EXPORT)
#endif
diff --git a/src/bluetooth/qbluetoothuuid_darwin.mm b/src/bluetooth/qbluetoothuuid_darwin.mm
new file mode 100644
index 00000000..056a2666
--- /dev/null
+++ b/src/bluetooth/qbluetoothuuid_darwin.mm
@@ -0,0 +1,46 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "darwin/btutility_p.h"
+
+#include "qbluetoothuuid.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \brief Constructs a new QBluetoothUuid, containing a copy of the \a cbUuid CBUUID.
+
+ \note this function is only available on Apple platforms.
+
+ \since 6.6
+ \ingroup platform-type-conversions
+*/
+QBluetoothUuid QBluetoothUuid::fromCBUUID(CBUUID *cbUuid)
+{
+ if (!cbUuid)
+ return {};
+
+ return DarwinBluetooth::qt_uuid(cbUuid);
+}
+
+/*!
+ \brief Creates a CBUUID from a QBluetoothUuid.
+
+ The resulting CBUUID is autoreleased.
+
+ \note this function is only available on Apple platforms.
+
+ \since 6.6
+ \ingroup platform-type-conversions
+*/
+
+CBUUID *QBluetoothUuid::toCBUUID() const
+{
+ const auto cbUuidGuard = DarwinBluetooth::cb_uuid(*this);
+ // cb_uuid returns a strong reference (RAII object). Let
+ // it do its job and release, but we return auto-released
+ // CBUUID, as documented.
+ return [[cbUuidGuard.data() retain] autorelease];
+}
+
+QT_END_NAMESPACE
diff --git a/src/bluetooth/qleadvertiser_bluez.cpp b/src/bluetooth/qleadvertiser_bluez.cpp
index 47daed25..422bb147 100644
--- a/src/bluetooth/qleadvertiser_bluez.cpp
+++ b/src/bluetooth/qleadvertiser_bluez.cpp
@@ -1,43 +1,7 @@
-/***************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qleadvertiser_p.h"
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qleadvertiser_bluez_p.h"
#include "bluez/bluez_data_p.h"
#include "bluez/hcimanager_p.h"
@@ -51,6 +15,9 @@ QT_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(QT_BT_BLUEZ)
+QLeAdvertiser::~QLeAdvertiser()
+ = default;
+
struct AdvParams {
quint16 minInterval;
quint16 maxInterval;
@@ -73,31 +40,33 @@ struct WhiteListParams {
};
-template<typename T> QByteArray byteArrayFromStruct(const T &data, int maxSize = -1)
+template <typename T>
+static QByteArray byteArrayFromStruct(const T &data)
{
- return QByteArray(reinterpret_cast<const char *>(&data), maxSize != -1 ? maxSize : sizeof data);
+ return QByteArray(reinterpret_cast<const char *>(&data), sizeof data);
}
QLeAdvertiserBluez::QLeAdvertiserBluez(const QLowEnergyAdvertisingParameters &params,
const QLowEnergyAdvertisingData &advertisingData,
const QLowEnergyAdvertisingData &scanResponseData,
- HciManager &hciManager, QObject *parent)
+ std::shared_ptr<HciManager> hciManager, QObject *parent)
: QLeAdvertiser(params, advertisingData, scanResponseData, parent), m_hciManager(hciManager)
{
- connect(&m_hciManager, &HciManager::commandCompleted, this,
+ Q_ASSERT(m_hciManager);
+ connect(m_hciManager.get(), &HciManager::commandCompleted, this,
&QLeAdvertiserBluez::handleCommandCompleted);
}
QLeAdvertiserBluez::~QLeAdvertiserBluez()
{
- disconnect(&m_hciManager, &HciManager::commandCompleted, this,
+ disconnect(m_hciManager.get(), &HciManager::commandCompleted, this,
&QLeAdvertiserBluez::handleCommandCompleted);
doStopAdvertising();
}
void QLeAdvertiserBluez::doStartAdvertising()
{
- if (!m_hciManager.monitorEvent(HciManager::CommandCompleteEvent)) {
+ if (!m_hciManager->monitorEvent(HciManager::HciEvent::EVT_CMD_COMPLETE)) {
handleError();
return;
}
@@ -117,7 +86,7 @@ void QLeAdvertiserBluez::doStopAdvertising()
sendNextCommand();
}
-void QLeAdvertiserBluez::queueCommand(OpCodeCommandField ocf, const QByteArray &data)
+void QLeAdvertiserBluez::queueCommand(QBluezConst::OpCodeCommandField ocf, const QByteArray &data)
{
m_pendingCommands << Command(ocf, data);
}
@@ -129,7 +98,7 @@ void QLeAdvertiserBluez::sendNextCommand()
return;
}
const Command &c = m_pendingCommands.first();
- if (!m_hciManager.sendCommand(OgfLinkControl, c.ocf, c.data)) {
+ if (!m_hciManager->sendCommand(QBluezConst::OgfLinkControl, c.ocf, c.data)) {
handleError();
return;
}
@@ -148,18 +117,19 @@ void QLeAdvertiserBluez::queueAdvertisingCommands()
void QLeAdvertiserBluez::queueReadTxPowerLevelCommand()
{
// Spec v4.2, Vol 2, Part E, 7.8.6
- queueCommand(OcfLeReadTxPowerLevel, QByteArray());
+ queueCommand(QBluezConst::OcfLeReadTxPowerLevel, QByteArray());
}
void QLeAdvertiserBluez::toggleAdvertising(bool enable)
{
// Spec v4.2, Vol 2, Part E, 7.8.9
- queueCommand(OcfLeSetAdvEnable, QByteArray(1, enable));
+ queueCommand(QBluezConst::OcfLeSetAdvEnable, QByteArray(1, enable));
}
void QLeAdvertiserBluez::setAdvertisingParams()
{
// Spec v4.2, Vol 2, Part E, 7.8.5
+ // or Spec v5.3, Vol 4, Part E, 7.8.5
AdvParams params;
static_assert(sizeof params == 15, "unexpected struct size");
using namespace std;
@@ -183,7 +153,7 @@ void QLeAdvertiserBluez::setAdvertisingParams()
const QByteArray paramsData = byteArrayFromStruct(params);
qCDebug(QT_BT_BLUEZ) << "advertising parameters:" << paramsData.toHex();
- queueCommand(OcfLeSetAdvParams, paramsData);
+ queueCommand(QBluezConst::OcfLeSetAdvParams, paramsData);
}
static quint16 forceIntoRange(quint16 val, quint16 min, quint16 max)
@@ -240,59 +210,58 @@ template<> quint8 servicesType<quint32>(bool dataComplete)
{
return dataComplete ? 0x5 : 0x4;
}
-template<> quint8 servicesType<quint128>(bool dataComplete)
+template<> quint8 servicesType<QUuid::Id128Bytes>(bool dataComplete)
{
return dataComplete ? 0x7 : 0x6;
}
-template<typename T> static void addServicesData(AdvData &data, const QVector<T> &services)
+template<typename T>
+static void addServicesData(AdvData &data, const QList<T> &services)
{
if (services.isEmpty())
return;
- const int spaceAvailable = sizeof data.data - data.length;
- const int maxServices = qMin<int>((spaceAvailable - 2) / sizeof(T), services.count());
+ constexpr auto sizeofT = static_cast<int>(sizeof(T)); // signed is more convenient
+ const qsizetype spaceAvailable = sizeof data.data - data.length;
+ // Determine how many services will be set, space may limit the number
+ const qsizetype maxServices = (std::min)((spaceAvailable - 2) / sizeofT, services.size());
if (maxServices <= 0) {
qCWarning(QT_BT_BLUEZ) << "services data does not fit into advertising data packet";
return;
}
- const bool dataComplete = maxServices == services.count();
+ const bool dataComplete = maxServices == services.size();
if (!dataComplete) {
- qCWarning(QT_BT_BLUEZ) << "only" << maxServices << "out of" << services.count()
+ qCWarning(QT_BT_BLUEZ) << "only" << maxServices << "out of" << services.size()
<< "services fit into the advertising data";
}
- data.data[data.length++] = 1 + maxServices * sizeof(T);
+ data.data[data.length++] = 1 + maxServices * sizeofT;
data.data[data.length++] = servicesType<T>(dataComplete);
- for (int i = 0; i < maxServices; ++i) {
- putBtData(services.at(i), data.data + data.length);
- data.length += sizeof(T);
+ for (qsizetype i = 0; i < maxServices; ++i) {
+ memcpy(data.data + data.length, &services.at(i), sizeofT);
+ data.length += sizeofT;
}
}
void QLeAdvertiserBluez::setServicesData(const QLowEnergyAdvertisingData &src, AdvData &dest)
{
- QVector<quint16> services16;
- QVector<quint32> services32;
- QVector<quint128> services128;
+ QList<quint16> services16;
+ QList<quint32> services32;
+ QList<QUuid::Id128Bytes> services128;
const QList<QBluetoothUuid> services = src.services();
for (const QBluetoothUuid &service : services) {
bool ok;
const quint16 service16 = service.toUInt16(&ok);
if (ok) {
- services16 << service16;
+ services16 << qToLittleEndian(service16);
continue;
}
const quint32 service32 = service.toUInt32(&ok);
if (ok) {
- services32 << service32;
+ services32 << qToLittleEndian(service32);
continue;
}
- // QBluetoothUuid::toUInt128() is always Big-Endian
- // convert it to host order
- quint128 hostOrder;
- quint128 qtUuidOrder = service.toUInt128();
- ntoh128(&qtUuidOrder, &hostOrder);
- services128 << hostOrder;
+ // QUuid::toBytes() is defaults to Big-Endian
+ services128 << service.toBytes(QSysInfo::LittleEndian);
}
addServicesData(dest, services16);
addServicesData(dest, services32);
@@ -303,17 +272,19 @@ void QLeAdvertiserBluez::setManufacturerData(const QLowEnergyAdvertisingData &sr
{
if (src.manufacturerId() == QLowEnergyAdvertisingData::invalidManufacturerId())
return;
- if (dest.length >= sizeof dest.data - 1 - 1 - 2 - src.manufacturerData().count()) {
+
+ const QByteArray manufacturerData = src.manufacturerData();
+ if (dest.length >= sizeof dest.data - 1 - 1 - 2 - manufacturerData.size()) {
qCWarning(QT_BT_BLUEZ) << "manufacturer data does not fit into advertising data packet";
return;
}
- dest.data[dest.length++] = src.manufacturerData().count() + 1 + 2;
+ dest.data[dest.length++] = manufacturerData.size() + 1 + 2;
dest.data[dest.length++] = 0xff;
putBtData(src.manufacturerId(), dest.data + dest.length);
dest.length += sizeof(quint16);
- std::memcpy(dest.data + dest.length, src.manufacturerData(), src.manufacturerData().count());
- dest.length += src.manufacturerData().count();
+ std::memcpy(dest.data + dest.length, manufacturerData.data(), manufacturerData.size());
+ dest.length += manufacturerData.size();
}
void QLeAdvertiserBluez::setLocalNameData(const QLowEnergyAdvertisingData &src, AdvData &dest)
@@ -326,8 +297,8 @@ void QLeAdvertiserBluez::setLocalNameData(const QLowEnergyAdvertisingData &src,
}
const QByteArray localNameUtf8 = src.localName().toUtf8();
- const int fullSize = localNameUtf8.count() + 1 + 1;
- const int size = qMin<int>(fullSize, sizeof dest.data - dest.length);
+ const qsizetype fullSize = localNameUtf8.size() + 1 + 1;
+ const qsizetype size = (std::min)(fullSize, qsizetype(sizeof dest.data - dest.length));
const bool isComplete = size == fullSize;
dest.data[dest.length++] = size - 1;
const int dataType = isComplete ? 0x9 : 0x8;
@@ -346,9 +317,9 @@ void QLeAdvertiserBluez::setData(bool isScanResponseData)
const QLowEnergyAdvertisingData &sourceData = isScanResponseData
? scanResponseData() : advertisingData();
- if (!sourceData.rawData().isEmpty()) {
- theData.length = qMin<int>(sizeof theData.data, sourceData.rawData().count());
- std::memcpy(theData.data, sourceData.rawData().constData(), theData.length);
+ if (const QByteArray rawData = sourceData.rawData(); !rawData.isEmpty()) {
+ theData.length = (std::min)(qsizetype(sizeof theData.data), rawData.size());
+ std::memcpy(theData.data, rawData.data(), theData.length);
} else {
if (sourceData.includePowerLevel())
setPowerLevel(theData);
@@ -367,12 +338,12 @@ void QLeAdvertiserBluez::setData(bool isScanResponseData)
if (!isScanResponseData) {
qCDebug(QT_BT_BLUEZ) << "advertising data:" << dataToSend.toHex();
- queueCommand(OcfLeSetAdvData, dataToSend);
+ queueCommand(QBluezConst::OcfLeSetAdvData, dataToSend);
} else if ((parameters().mode() == QLowEnergyAdvertisingParameters::AdvScanInd
|| parameters().mode() == QLowEnergyAdvertisingParameters::AdvInd)
&& theData.length > 0) {
qCDebug(QT_BT_BLUEZ) << "scan response data:" << dataToSend.toHex();
- queueCommand(OcfLeSetScanResponseData, dataToSend);
+ queueCommand(QBluezConst::OcfLeSetScanResponseData, dataToSend);
}
}
@@ -393,7 +364,7 @@ void QLeAdvertiserBluez::setWhiteList()
// Spec v4.2, Vol 2, Part E, 7.8.15-16
if (parameters().filterPolicy() == QLowEnergyAdvertisingParameters::IgnoreWhiteList)
return;
- queueCommand(OcfLeClearWhiteList, QByteArray());
+ queueCommand(QBluezConst::OcfLeClearWhiteList, QByteArray());
const QList<QLowEnergyAdvertisingParameters::AddressInfo> whiteListInfos
= parameters().whiteList();
for (const auto &addressInfo : whiteListInfos) {
@@ -401,7 +372,7 @@ void QLeAdvertiserBluez::setWhiteList()
static_assert(sizeof commandParam == 7, "unexpected struct size");
commandParam.addrType = addressInfo.type;
convertAddress(addressInfo.address.toUInt64(), commandParam.addr.b);
- queueCommand(OcfLeAddToWhiteList, byteArrayFromStruct(commandParam));
+ queueCommand(QBluezConst::OcfLeAddToWhiteList, byteArrayFromStruct(commandParam));
}
}
@@ -410,14 +381,16 @@ void QLeAdvertiserBluez::handleCommandCompleted(quint16 opCode, quint8 status,
{
if (m_pendingCommands.isEmpty())
return;
- const quint16 ocf = ocfFromOpCode(opCode);
+ const QBluezConst::OpCodeCommandField ocf = QBluezConst::OpCodeCommandField(ocfFromOpCode(opCode));
const Command currentCmd = m_pendingCommands.first();
if (currentCmd.ocf != ocf)
return; // Not one of our commands.
m_pendingCommands.takeFirst();
if (status != 0) {
- qCDebug(QT_BT_BLUEZ) << "command" << ocf << "failed with status" << status;
- if (ocf == OcfLeSetAdvEnable && status == 0xc && currentCmd.data == QByteArray(1, '\0')) {
+ qCDebug(QT_BT_BLUEZ) << "command" << ocf
+ << "failed with status" << (HciManager::HciError)status
+ << "status code" << status;
+ if (ocf == QBluezConst::OcfLeSetAdvEnable && status == 0xc && currentCmd.data == QByteArray(1, '\0')) {
// we ignore OcfLeSetAdvEnable if it tries to disable an active advertisement
// it seems the platform often automatically turns off advertisements
// subsequently the explicit stopAdvertisement call fails when re-issued
@@ -425,7 +398,7 @@ void QLeAdvertiserBluez::handleCommandCompleted(quint16 opCode, quint8 status,
sendNextCommand();
return;
}
- if (ocf == OcfLeReadTxPowerLevel) {
+ if (ocf == QBluezConst::OcfLeReadTxPowerLevel) {
qCDebug(QT_BT_BLUEZ) << "reading power level failed, leaving it out of the "
"advertising data";
m_sendPowerLevel = false;
@@ -438,7 +411,7 @@ void QLeAdvertiserBluez::handleCommandCompleted(quint16 opCode, quint8 status,
}
switch (ocf) {
- case OcfLeReadTxPowerLevel:
+ case QBluezConst::OcfLeReadTxPowerLevel:
if (m_sendPowerLevel) {
m_powerLevel = data.at(0);
qCDebug(QT_BT_BLUEZ) << "TX power level is" << m_powerLevel;
@@ -460,3 +433,5 @@ void QLeAdvertiserBluez::handleError()
}
QT_END_NAMESPACE
+
+#include "moc_qleadvertiser_bluez_p.cpp"
diff --git a/src/bluetooth/qleadvertiser_p.h b/src/bluetooth/qleadvertiser_bluez_p.h
index 9b8ffbb5..5bb5d968 100644
--- a/src/bluetooth/qleadvertiser_p.h
+++ b/src/bluetooth/qleadvertiser_bluez_p.h
@@ -1,44 +1,8 @@
-/***************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QLEADVERTISER_P_H
-#define QLEADVERTISER_P_H
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QLEADVERTISER_BLUEZ_P_H
+#define QLEADVERTISER_BLUEZ_P_H
//
// W A R N I N G
@@ -54,12 +18,12 @@
#include "qlowenergyadvertisingdata.h"
#include "qlowenergyadvertisingparameters.h"
-#if QT_CONFIG(bluez)
+QT_REQUIRE_CONFIG(bluez);
+
#include "bluez/bluez_data_p.h"
-#endif
+#include <QtCore/qlist.h>
#include <QtCore/qobject.h>
-#include <QtCore/qvector.h>
QT_BEGIN_NAMESPACE
@@ -78,7 +42,7 @@ public:
const QLowEnergyAdvertisingData &advData,
const QLowEnergyAdvertisingData &responseData, QObject *parent)
: QObject(parent), m_params(params), m_advData(advData), m_responseData(responseData) {}
- virtual ~QLeAdvertiser() { }
+ ~QLeAdvertiser() override;
protected:
const QLowEnergyAdvertisingParameters &parameters() const { return m_params; }
@@ -94,18 +58,18 @@ private:
const QLowEnergyAdvertisingData m_responseData;
};
-
-#if QT_CONFIG(bluez)
struct AdvData;
struct AdvParams;
class HciManager;
class QLeAdvertiserBluez : public QLeAdvertiser
{
+ Q_OBJECT
public:
QLeAdvertiserBluez(const QLowEnergyAdvertisingParameters &params,
const QLowEnergyAdvertisingData &advertisingData,
- const QLowEnergyAdvertisingData &scanResponseData, HciManager &hciManager,
+ const QLowEnergyAdvertisingData &scanResponseData,
+ std::shared_ptr<HciManager> hciManager,
QObject *parent = nullptr);
~QLeAdvertiserBluez() override;
@@ -119,7 +83,7 @@ private:
void setManufacturerData(const QLowEnergyAdvertisingData &src, AdvData &dest);
void setLocalNameData(const QLowEnergyAdvertisingData &src, AdvData &dest);
- void queueCommand(OpCodeCommandField ocf, const QByteArray &advertisingData);
+ void queueCommand(QBluezConst::OpCodeCommandField ocf, const QByteArray &advertisingData);
void sendNextCommand();
void queueAdvertisingCommands();
void queueReadTxPowerLevelCommand();
@@ -134,20 +98,19 @@ private:
void handleCommandCompleted(quint16 opCode, quint8 status, const QByteArray &advertisingData);
void handleError();
- HciManager &m_hciManager;
+ std::shared_ptr<HciManager> m_hciManager;
struct Command {
Command() {}
- Command(OpCodeCommandField ocf, const QByteArray &data) : ocf(ocf), data(data) { }
- OpCodeCommandField ocf;
+ Command(QBluezConst::OpCodeCommandField ocf, const QByteArray &data) : ocf(ocf), data(data) { }
+ QBluezConst::OpCodeCommandField ocf;
QByteArray data;
};
- QVector<Command> m_pendingCommands;
+ QList<Command> m_pendingCommands;
quint8 m_powerLevel;
bool m_sendPowerLevel;
};
-#endif // QT_CONFIG(bluez)
QT_END_NAMESPACE
diff --git a/src/bluetooth/qleadvertiser_bluezdbus.cpp b/src/bluetooth/qleadvertiser_bluezdbus.cpp
new file mode 100644
index 00000000..78e95a76
--- /dev/null
+++ b/src/bluetooth/qleadvertiser_bluezdbus.cpp
@@ -0,0 +1,229 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qleadvertiser_bluezdbus_p.h"
+#include "bluez/leadvertisement1_p.h"
+#include "bluez/leadvertisingmanager1_p.h"
+#include "bluez/bluez5_helper_p.h"
+
+#include <QtCore/QtMinMax>
+#include <QtCore/QLoggingCategory>
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_LOGGING_CATEGORY(QT_BT_BLUEZ)
+
+using namespace Qt::StringLiterals;
+
+// The advertisement dbus object path is freely definable, use as prefix
+static constexpr auto advObjectPathTemplate{"/qt/btle/advertisement/%1%2/%3"_L1};
+static constexpr auto bluezService{"org.bluez"_L1};
+static constexpr auto bluezErrorFailed{"org.bluez.Error.Failed"_L1};
+
+// From bluez API documentation
+static constexpr auto advDataTXPower{"tx-power"_L1};
+static constexpr auto advDataTypePeripheral{"peripheral"_L1};
+static constexpr auto advDataTypeBroadcast{"broadcast"_L1};
+static constexpr quint16 advDataMinIntervalMs{20};
+static constexpr quint16 advDataMaxIntervalMs{10485};
+
+
+QLeDBusAdvertiser::QLeDBusAdvertiser(const QLowEnergyAdvertisingParameters &params,
+ const QLowEnergyAdvertisingData &advertisingData,
+ const QLowEnergyAdvertisingData &scanResponseData,
+ const QString &hostAdapterPath,
+ QObject* parent)
+ : QObject(parent),
+ m_advParams(params),
+ m_advData(advertisingData),
+ m_advObjectPath(QString(advObjectPathTemplate).
+ arg(sanitizeNameForDBus(QCoreApplication::applicationName())).
+ arg(QCoreApplication::applicationPid()).
+ arg(QRandomGenerator::global()->generate())),
+ m_advDataDBus(new OrgBluezLEAdvertisement1Adaptor(this)),
+ m_advManager(new OrgBluezLEAdvertisingManager1Interface(bluezService, hostAdapterPath,
+ QDBusConnection::systemBus(), this))
+{
+ // Bluez DBus API doesn't allow distinguishing between advertisement and scan response data;
+ // consolidate the two if they differ.
+ // Union of service UUIDs:
+ if (scanResponseData.services() != advertisingData.services()) {
+ QList<QBluetoothUuid> services = advertisingData.services();
+ for (const auto &service: scanResponseData.services()) {
+ if (!services.contains(service))
+ services.append(service);
+ }
+ m_advData.setServices(services);
+ }
+ // Scan response is given precedence with rest of the data
+ if (!scanResponseData.localName().isEmpty())
+ m_advData.setLocalName(scanResponseData.localName());
+ if (scanResponseData.manufacturerId() != QLowEnergyAdvertisingData::invalidManufacturerId()) {
+ m_advData.setManufacturerData(scanResponseData.manufacturerId(),
+ scanResponseData.manufacturerData());
+ }
+ if (scanResponseData.includePowerLevel())
+ m_advData.setIncludePowerLevel(true);
+
+ setDataForDBus();
+}
+
+QLeDBusAdvertiser::~QLeDBusAdvertiser()
+{
+ stopAdvertising();
+}
+
+// This function parses the advertising data provided by the application and
+// populates the dbus adaptor with it. DBus will ask the data from the adaptor when
+// the advertisement is later registered (started)
+void QLeDBusAdvertiser::setDataForDBus()
+{
+ setAdvertisingParamsForDBus();
+ setAdvertisementDataForDBus();
+}
+
+void QLeDBusAdvertiser::setAdvertisingParamsForDBus()
+{
+ // Whitelist and filter policy
+ if (!m_advParams.whiteList().isEmpty())
+ qCWarning(QT_BT_BLUEZ) << "White lists and filter policies not supported, ignoring";
+
+ // Legacy advertising mode mapped to GAP role (peripheral vs broadcast)
+ switch (m_advParams.mode())
+ {
+ case QLowEnergyAdvertisingParameters::AdvScanInd:
+ case QLowEnergyAdvertisingParameters::AdvNonConnInd:
+ m_advDataDBus->setType(advDataTypeBroadcast);
+ break;
+ case QLowEnergyAdvertisingParameters::AdvInd:
+ default:
+ m_advDataDBus->setType(advDataTypePeripheral);
+ }
+
+ // Advertisement interval (min max in milliseconds). Ensure the values fit the range bluez
+ // allows. The max >= min is guaranteed by QLowEnergyAdvertisingParameters::setInterval().
+ // Note: Bluez reads these values but at the time of this writing it marks this feature
+ // as 'experimental'
+ m_advDataDBus->setMinInterval(qBound(advDataMinIntervalMs,
+ quint16(m_advParams.minimumInterval()),
+ advDataMaxIntervalMs));
+ m_advDataDBus->setMaxInterval(qBound(advDataMinIntervalMs,
+ quint16(m_advParams.maximumInterval()),
+ advDataMaxIntervalMs));
+}
+
+void QLeDBusAdvertiser::setAdvertisementDataForDBus()
+{
+ // We don't calculate the advertisement length to guard for too long advertisements.
+ // There isn't adequate control and visibility on the advertisement for that.
+ // - We don't know the max length (legacy or extended advertising)
+ // - Bluez may truncate some of the fields on its own, making calculus here imprecise
+ // - Scan response may or may not be used to offload some of the data
+
+ // Include the power level if requested and dbus supports it
+ const auto supportedIncludes = m_advManager->supportedIncludes();
+ if (m_advData.includePowerLevel() && supportedIncludes.contains(advDataTXPower))
+ m_advDataDBus->setIncludes({advDataTXPower});
+
+ // Set the application provided name (valid to be empty).
+ // For clarity: bluez also has "local-name" system include that could be set if no local
+ // name is provided. However that would require that the LocalName DBus property would
+ // not exist. Existing LocalName property when 'local-name' is included leads to an
+ // advertisement error.
+ m_advDataDBus->setLocalName(m_advData.localName());
+
+ // Service UUIDs
+ if (!m_advData.services().isEmpty()) {
+ QStringList serviceUUIDList;
+ for (const auto& service: m_advData.services())
+ serviceUUIDList << service.toString(QUuid::StringFormat::WithoutBraces);
+ m_advDataDBus->setServiceUUIDs(serviceUUIDList);
+ }
+
+ // Manufacturer data
+ if (m_advData.manufacturerId() != QLowEnergyAdvertisingData::invalidManufacturerId()) {
+ m_advDataDBus->setManufacturerData({
+ {m_advData.manufacturerId(), QDBusVariant(m_advData.manufacturerData())}});
+ }
+
+ // Discoverability
+ if (m_advDataDBus->type() == advDataTypePeripheral) {
+ m_advDataDBus->setDiscoverable(m_advData.discoverability()
+ != QLowEnergyAdvertisingData::DiscoverabilityNone);
+ } else {
+ qCDebug(QT_BT_BLUEZ) << "Ignoring advertisement discoverability in broadcast mode";
+ }
+
+ // Raw data
+ if (!m_advData.rawData().isEmpty())
+ qCWarning(QT_BT_BLUEZ) << "Raw advertisement data not supported, ignoring";
+}
+
+void QLeDBusAdvertiser::startAdvertising()
+{
+ qCDebug(QT_BT_BLUEZ) << "Start advertising" << m_advObjectPath << "on" << m_advManager->path();
+ if (m_advertising) {
+ qCWarning(QT_BT_BLUEZ) << "Start tried while already advertising";
+ return;
+ }
+
+ if (!QDBusConnection::systemBus().registerObject(m_advObjectPath, m_advDataDBus,
+ QDBusConnection::ExportAllContents)) {
+ qCWarning(QT_BT_BLUEZ) << "Advertisement dbus object registration failed";
+ emit errorOccurred();
+ return;
+ }
+
+ // Register the advertisement which starts the actual advertising.
+ // We use call watcher here instead of waitForFinished() because DBus will
+ // call back our advertisement object (to read data) in this same thread => would block
+ auto reply = m_advManager->RegisterAdvertisement(QDBusObjectPath(m_advObjectPath), {});
+ QDBusPendingCallWatcher* watcher = new QDBusPendingCallWatcher(reply, this);
+
+ QObject::connect(watcher, &QDBusPendingCallWatcher::finished, this,
+ [this](QDBusPendingCallWatcher* watcher){
+ QDBusPendingReply<> reply = *watcher;
+ if (reply.isError()) {
+ qCWarning(QT_BT_BLUEZ) << "Advertisement registration failed" << reply.error();
+ if (reply.error().name() == bluezErrorFailed)
+ qCDebug(QT_BT_BLUEZ) << "Advertisement could've been too large";
+ QDBusConnection::systemBus().unregisterObject(m_advObjectPath);
+ emit errorOccurred();
+ } else {
+ qCDebug(QT_BT_BLUEZ) << "Advertisement started successfully";
+ m_advertising = true;
+ }
+ watcher->deleteLater();
+ });
+}
+
+void QLeDBusAdvertiser::stopAdvertising()
+{
+ if (!m_advertising)
+ return;
+
+ m_advertising = false;
+ auto reply = m_advManager->UnregisterAdvertisement(QDBusObjectPath(m_advObjectPath));
+ reply.waitForFinished();
+ if (reply.isError())
+ qCWarning(QT_BT_BLUEZ) << "Error in unregistering advertisement" << reply.error();
+ else
+ qCDebug(QT_BT_BLUEZ) << "Advertisement unregistered successfully";
+ QDBusConnection::systemBus().unregisterObject(m_advObjectPath);
+}
+
+// Called by Bluez when the advertisement has been removed (org.bluez.LEAdvertisement1.Release)
+void QLeDBusAdvertiser::Release()
+{
+ qCDebug(QT_BT_BLUEZ) << "Advertisement" << m_advObjectPath << "released"
+ << (m_advertising ? "unexpectedly" : "");
+ if (m_advertising) {
+ // If we are advertising, it means the Release is unsolicited
+ // and handled as an advertisement error. No need to call UnregisterAdvertisement
+ m_advertising = false;
+ QDBusConnection::systemBus().unregisterObject(m_advObjectPath);
+ emit errorOccurred();
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/bluetooth/qleadvertiser_bluezdbus_p.h b/src/bluetooth/qleadvertiser_bluezdbus_p.h
new file mode 100644
index 00000000..5a119884
--- /dev/null
+++ b/src/bluetooth/qleadvertiser_bluezdbus_p.h
@@ -0,0 +1,66 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QLEADVERTISER_BLUEZDBUS_P_H
+#define QLEADVERTISER_BLUEZDBUS_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qlowenergyadvertisingdata.h"
+#include "qlowenergyadvertisingparameters.h"
+
+QT_REQUIRE_CONFIG(bluez);
+
+#include <QtCore/QObject>
+
+class OrgBluezLEAdvertisement1Adaptor;
+class OrgBluezLEAdvertisingManager1Interface;
+
+QT_BEGIN_NAMESPACE
+
+class QLeDBusAdvertiser : public QObject
+{
+ Q_OBJECT
+
+public:
+ QLeDBusAdvertiser(const QLowEnergyAdvertisingParameters &params,
+ const QLowEnergyAdvertisingData &advertisingData,
+ const QLowEnergyAdvertisingData &scanResponseData,
+ const QString &hostAdapterPath,
+ QObject* parent = nullptr);
+ ~QLeDBusAdvertiser() override;
+
+ void startAdvertising();
+ void stopAdvertising();
+
+ Q_INVOKABLE void Release();
+
+signals:
+ void errorOccurred();
+
+private:
+ void setDataForDBus();
+ void setAdvertisingParamsForDBus();
+ void setAdvertisementDataForDBus();
+
+private:
+ const QLowEnergyAdvertisingParameters m_advParams;
+ QLowEnergyAdvertisingData m_advData;
+ const QString m_advObjectPath;
+ OrgBluezLEAdvertisement1Adaptor* const m_advDataDBus;
+ OrgBluezLEAdvertisingManager1Interface* const m_advManager;
+ bool m_advertising = false;
+};
+
+QT_END_NAMESPACE
+
+#endif // QLEADVERTISER_BLUEZDBUS_P_H
diff --git a/src/bluetooth/qlowenergyadvertisingdata.cpp b/src/bluetooth/qlowenergyadvertisingdata.cpp
index 3837025b..90cf4529 100644
--- a/src/bluetooth/qlowenergyadvertisingdata.cpp
+++ b/src/bluetooth/qlowenergyadvertisingdata.cpp
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qlowenergyadvertisingdata.h"
@@ -77,6 +41,10 @@ public:
\note The actual data packets sent over the advertising channel cannot contain more than 31
bytes. If the variable-length data set via this class exceeds that limit, it will
be left out of the packet or truncated, depending on the type.
+ On Android, advertising will fail if advertising data is larger than 31 bytes.
+ On Bluez DBus backend the advertising length limit and the behavior when it is exceeded
+ is up to BlueZ; it may for example support extended advertising. For the most
+ predictable behavior keep the advertising data short.
\sa QLowEnergyAdvertisingParameters
\sa QLowEnergyController::startAdvertising()
@@ -243,6 +211,9 @@ QList<QBluetoothUuid> QLowEnergyAdvertisingData::services() const
This can be used to send non-standard data.
\note If \a data is longer than 31 bytes, it will be truncated. It is the caller's responsibility
to ensure that \a data is well-formed.
+
+ Providing the raw advertising data is not supported on BlueZ DBus backend as BlueZ does not
+ support it. This may change in a future release.
*/
void QLowEnergyAdvertisingData::setRawData(const QByteArray &data)
{
@@ -263,27 +234,34 @@ QByteArray QLowEnergyAdvertisingData::rawData() const
*/
/*!
- Returns \c true if \a data1 and \a data2 are equal with respect to their public state,
- otherwise returns \c false.
+ \brief Returns \c true if \a a and \a b are equal with respect to their public state,
+ otherwise returns \c false.
+ \internal
*/
-bool operator==(const QLowEnergyAdvertisingData &data1, const QLowEnergyAdvertisingData &data2)
+bool QLowEnergyAdvertisingData::equals(const QLowEnergyAdvertisingData &a,
+ const QLowEnergyAdvertisingData &b)
{
- if (data1.d == data2.d)
+ if (a.d == b.d)
return true;
- return data1.discoverability() == data2.discoverability()
- && data1.includePowerLevel() == data2.includePowerLevel()
- && data1.localName() == data2.localName()
- && data1.manufacturerData() == data2.manufacturerData()
- && data1.manufacturerId() == data2.manufacturerId()
- && data1.services() == data2.services()
- && data1.rawData() == data2.rawData();
+ return a.discoverability() == b.discoverability()
+ && a.includePowerLevel() == b.includePowerLevel() && a.localName() == b.localName()
+ && a.manufacturerData() == b.manufacturerData()
+ && a.manufacturerId() == b.manufacturerId() && a.services() == b.services()
+ && a.rawData() == b.rawData();
}
/*!
- \fn bool operator!=(const QLowEnergyAdvertisingData &data1,
- const QLowEnergyAdvertisingData &data2)
- Returns \c true if \a data1 and \a data2 are not equal with respect to their public state,
- otherwise returns \c false.
+ \fn bool QLowEnergyAdvertisingData::operator!=(const QLowEnergyAdvertisingData &data1,
+ const QLowEnergyAdvertisingData &data2)
+ \brief Returns \c true if \a data1 and \a data2 are not equal with respect to their
+ public state, otherwise returns \c false.
+ */
+
+/*!
+ \fn bool QLowEnergyAdvertisingData::operator==(const QLowEnergyAdvertisingData &data1,
+ const QLowEnergyAdvertisingData &data2)
+ \brief Returns \c true if \a data1 and \a data2 are equal with respect to their public
+ state, otherwise returns \c false.
*/
/*!
diff --git a/src/bluetooth/qlowenergyadvertisingdata.h b/src/bluetooth/qlowenergyadvertisingdata.h
index 0fc55adb..600bd21b 100644
--- a/src/bluetooth/qlowenergyadvertisingdata.h
+++ b/src/bluetooth/qlowenergyadvertisingdata.h
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QLOWENERGYADVERTISINGDATA_H
#define QLOWENERGYADVERTISINGDATA_H
@@ -50,14 +14,20 @@ class QLowEnergyAdvertisingDataPrivate;
class Q_BLUETOOTH_EXPORT QLowEnergyAdvertisingData
{
- friend Q_BLUETOOTH_EXPORT bool operator==(const QLowEnergyAdvertisingData &data1,
- const QLowEnergyAdvertisingData &data2);
public:
QLowEnergyAdvertisingData();
QLowEnergyAdvertisingData(const QLowEnergyAdvertisingData &other);
~QLowEnergyAdvertisingData();
QLowEnergyAdvertisingData &operator=(const QLowEnergyAdvertisingData &other);
+ friend bool operator==(const QLowEnergyAdvertisingData &a, const QLowEnergyAdvertisingData &b)
+ {
+ return equals(a, b);
+ }
+ friend bool operator!=(const QLowEnergyAdvertisingData &a, const QLowEnergyAdvertisingData &b)
+ {
+ return !equals(a, b);
+ }
void setLocalName(const QString &name);
QString localName() const;
@@ -84,20 +54,13 @@ public:
void setRawData(const QByteArray &data);
QByteArray rawData() const;
- void swap(QLowEnergyAdvertisingData &other) Q_DECL_NOTHROW { qSwap(d, other.d); }
+ void swap(QLowEnergyAdvertisingData &other) noexcept { d.swap(other.d); }
private:
+ static bool equals(const QLowEnergyAdvertisingData &a, const QLowEnergyAdvertisingData &b);
QSharedDataPointer<QLowEnergyAdvertisingDataPrivate> d;
};
-Q_BLUETOOTH_EXPORT bool operator==(const QLowEnergyAdvertisingData &data1,
- const QLowEnergyAdvertisingData &data2);
-inline bool operator!=(const QLowEnergyAdvertisingData &data1,
- const QLowEnergyAdvertisingData &data2)
-{
- return !(data1 == data2);
-}
-
Q_DECLARE_SHARED(QLowEnergyAdvertisingData)
QT_END_NAMESPACE
diff --git a/src/bluetooth/qlowenergyadvertisingparameters.cpp b/src/bluetooth/qlowenergyadvertisingparameters.cpp
index 31111da6..b0923036 100644
--- a/src/bluetooth/qlowenergyadvertisingparameters.cpp
+++ b/src/bluetooth/qlowenergyadvertisingparameters.cpp
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qlowenergyadvertisingparameters.h"
@@ -206,6 +170,8 @@ QLowEnergyAdvertisingParameters::Mode QLowEnergyAdvertisingParameters::mode() co
Sets the white list that is potentially used for filtering scan and connection requests.
The \a whiteList parameter is the list of addresses to use for filtering, and \a policy
specifies how exactly to use \a whiteList.
+
+ Whitelists are not supported on the BlueZ DBus backend as they are not supported by BlueZ.
*/
void QLowEnergyAdvertisingParameters::setWhiteList(const QList<AddressInfo> &whiteList,
FilterPolicy policy)
@@ -240,6 +206,10 @@ QLowEnergyAdvertisingParameters::FilterPolicy QLowEnergyAdvertisingParameters::f
\note There are limits for the minimum and maximum interval; the exact values depend on
the mode. If they are exceeded, the lowest or highest possible value will be used,
respectively.
+
+ Setting the advertising interval is supported on BlueZ DBus backend if its experimental
+ status is changed in later versions of BlueZ (or run in experimental mode).
+
*/
void QLowEnergyAdvertisingParameters::setInterval(quint16 minimum, quint16 maximum)
{
@@ -269,26 +239,58 @@ int QLowEnergyAdvertisingParameters::maximumInterval() const
*/
/*!
- Returns \a true if \a p1 and \a p2 are equal with respect to their public state,
- otherwise returns false.
+ \brief Returns \c true if \a a and \a b are equal with respect to their public state,
+ otherwise returns \c false.
+ \internal
*/
-bool operator==(const QLowEnergyAdvertisingParameters &p1,
- const QLowEnergyAdvertisingParameters &p2)
+bool QLowEnergyAdvertisingParameters::equals(const QLowEnergyAdvertisingParameters &a,
+ const QLowEnergyAdvertisingParameters &b)
{
- if (p1.d == p2.d)
+ if (a.d == b.d)
return true;
- return p1.filterPolicy() == p2.filterPolicy()
- && p1.minimumInterval() == p2.minimumInterval()
- && p1.maximumInterval() == p2.maximumInterval()
- && p1.mode() == p2.mode()
- && p1.whiteList() == p2.whiteList();
+ return a.filterPolicy() == b.filterPolicy() && a.minimumInterval() == b.minimumInterval()
+ && a.maximumInterval() == b.maximumInterval() && a.mode() == b.mode()
+ && a.whiteList() == b.whiteList();
+}
+
+bool QLowEnergyAdvertisingParameters::AddressInfo::equals(
+ const QLowEnergyAdvertisingParameters::AddressInfo &ai1,
+ const QLowEnergyAdvertisingParameters::AddressInfo &ai2)
+{
+ return ai1.address == ai2.address && ai1.type == ai2.type;
}
/*!
- \fn bool operator!=(const QLowEnergyAdvertisingParameters &p1,
- const QLowEnergyAdvertisingParameters &p2)
- Returns \a true if \a p1 and \a p2 are not equal with respect to their public state,
- otherwise returns false.
+ \fn bool QLowEnergyAdvertisingParameters::operator!=(
+ const QLowEnergyAdvertisingParameters &a,
+ const QLowEnergyAdvertisingParameters &b)
+ \brief Returns \c true if \a a and \a b are not equal with respect to their public state,
+ otherwise returns \c false.
+ */
+
+/*!
+ \fn bool QLowEnergyAdvertisingParameters::operator==(
+ const QLowEnergyAdvertisingParameters &a,
+ const QLowEnergyAdvertisingParameters &b)
+ \brief Returns \c true if \a a and \a b are equal with respect to their public state,
+ otherwise returns \c false.
+ */
+
+/*!
+ \fn bool QLowEnergyAdvertisingParameters::AddressInfo::operator!=(const
+ QLowEnergyAdvertisingParameters::AddressInfo &a, const
+ QLowEnergyAdvertisingParameters::AddressInfo &b)
+
+ \brief Returns \c true if \a a and \a b are not equal with respect to their public state,
+ otherwise returns \c false.
+ */
+
+/*!
+ \fn bool QLowEnergyAdvertisingParameters::AddressInfo::operator==(
+ const QLowEnergyAdvertisingParameters::AddressInfo &a,
+ const QLowEnergyAdvertisingParameters::AddressInfo &b)
+ \brief Returns \c true if \a a and \a b are equal with respect to their public state,
+ otherwise returns \c false.
*/
QT_END_NAMESPACE
diff --git a/src/bluetooth/qlowenergyadvertisingparameters.h b/src/bluetooth/qlowenergyadvertisingparameters.h
index 055026e6..fe3ed1c5 100644
--- a/src/bluetooth/qlowenergyadvertisingparameters.h
+++ b/src/bluetooth/qlowenergyadvertisingparameters.h
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QLOWENERGYADVERTISINGPARAMETERS_H
#define QLOWENERGYADVERTISINGPARAMETERS_H
@@ -52,27 +16,44 @@ class QLowEnergyAdvertisingParametersPrivate;
class Q_BLUETOOTH_EXPORT QLowEnergyAdvertisingParameters
{
- friend Q_BLUETOOTH_EXPORT bool operator==(const QLowEnergyAdvertisingParameters &p1,
- const QLowEnergyAdvertisingParameters &p2);
public:
QLowEnergyAdvertisingParameters();
QLowEnergyAdvertisingParameters(const QLowEnergyAdvertisingParameters &other);
~QLowEnergyAdvertisingParameters();
QLowEnergyAdvertisingParameters &operator=(const QLowEnergyAdvertisingParameters &other);
+ friend bool operator==(const QLowEnergyAdvertisingParameters &a,
+ const QLowEnergyAdvertisingParameters &b)
+ {
+ return equals(a, b);
+ }
+
+ friend bool operator!=(const QLowEnergyAdvertisingParameters &a,
+ const QLowEnergyAdvertisingParameters &b)
+ {
+ return !equals(a, b);
+ }
enum Mode { AdvInd = 0x0, AdvScanInd = 0x2, AdvNonConnInd = 0x3 };
void setMode(Mode mode);
Mode mode() const;
- struct AddressInfo {
+ class Q_BLUETOOTH_EXPORT AddressInfo
+ {
+ public:
AddressInfo(const QBluetoothAddress &addr, QLowEnergyController::RemoteAddressType t)
: address(addr), type(t) {}
AddressInfo() : type(QLowEnergyController::PublicAddress) {}
QBluetoothAddress address;
QLowEnergyController::RemoteAddressType type;
+ friend bool operator==(const AddressInfo &a, const AddressInfo &b) { return equals(a, b); }
+ friend bool operator!=(const AddressInfo &a, const AddressInfo &b) { return !equals(a, b); }
+
+ private:
+ static bool equals(const AddressInfo &a, const AddressInfo &b);
};
+
enum FilterPolicy {
IgnoreWhiteList = 0x00,
UseWhiteListForScanning = 0x01,
@@ -90,26 +71,14 @@ public:
// TODO: own address type
// TODO: For ADV_DIRECT_IND: peer address + peer address type
- void swap(QLowEnergyAdvertisingParameters &other) Q_DECL_NOTHROW { qSwap(d, other.d); }
+ void swap(QLowEnergyAdvertisingParameters &other) noexcept { d.swap(other.d); }
private:
+ static bool equals(const QLowEnergyAdvertisingParameters &a,
+ const QLowEnergyAdvertisingParameters &b);
QSharedDataPointer<QLowEnergyAdvertisingParametersPrivate> d;
};
-inline bool operator==(const QLowEnergyAdvertisingParameters::AddressInfo &ai1,
- const QLowEnergyAdvertisingParameters::AddressInfo &ai2)
-{
- return ai1.address == ai2.address && ai1.type == ai2.type;
-}
-
-Q_BLUETOOTH_EXPORT bool operator==(const QLowEnergyAdvertisingParameters &p1,
- const QLowEnergyAdvertisingParameters &p2);
-inline bool operator!=(const QLowEnergyAdvertisingParameters &p1,
- const QLowEnergyAdvertisingParameters &p2)
-{
- return !(p1 == p2);
-}
-
Q_DECLARE_SHARED(QLowEnergyAdvertisingParameters)
QT_END_NAMESPACE
diff --git a/src/bluetooth/qlowenergycharacteristic.cpp b/src/bluetooth/qlowenergycharacteristic.cpp
index 1419fa7c..d71861c0 100644
--- a/src/bluetooth/qlowenergycharacteristic.cpp
+++ b/src/bluetooth/qlowenergycharacteristic.cpp
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2016 BlackBerry Limited. All rights reserved.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 BlackBerry Limited. All rights reserved.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qlowenergycharacteristic.h"
#include "qlowenergyserviceprivate_p.h"
@@ -43,6 +7,8 @@
QT_BEGIN_NAMESPACE
+QT_IMPL_METATYPE_EXTERN(QLowEnergyCharacteristic)
+
/*!
\class QLowEnergyCharacteristic
\inmodule QtBluetooth
@@ -52,16 +18,16 @@ QT_BEGIN_NAMESPACE
\since 5.4
QLowEnergyCharacteristic provides information about a Bluetooth Low Energy
- service characteristic's \l name(), \l uuid(), \l value(), \l properties(),
- \l handle() and \l descriptors(). To obtain the characteristic's specification
+ service characteristic's name(), uuid(), value(), properties(), and
+ descriptors(). To obtain the characteristic's specification
and information, it is necessary to connect to the device using the
- \l QLowEnergyService and \l QLowEnergyController classes.
+ QLowEnergyService and QLowEnergyController classes.
The characteristic value may be written via the \l QLowEnergyService instance
that manages the service to which this characteristic belongs. The
\l {QLowEnergyService::writeCharacteristic()} function writes the new value.
The \l {QLowEnergyService::characteristicWritten()} signal is emitted upon success.
- The \l value() of this object is automatically updated accordingly.
+ The value() of this object is automatically updated accordingly.
Characteristics may contain none, one or more descriptors. They can be individually
retrieved using the \l descriptor() function. The \l descriptors() function returns
@@ -89,6 +55,11 @@ QT_BEGIN_NAMESPACE
\value ExtendedProperty Additional characteristic properties are defined in the characteristic's
extended properties descriptor.
+ It is not recommended to set both Notify and Indicate properties on the same characteristic
+ as the underlying Bluetooth stack behaviors differ from platform to platform. Please see
+ \l QLowEnergyCharacteristic::clientCharacteristicConfiguration
+
+
\sa properties()
*/
@@ -214,6 +185,8 @@ QByteArray QLowEnergyCharacteristic::value() const
}
/*!
+ \internal
+
Returns the handle of the characteristic's value attribute;
or \c 0 if the handle cannot be accessed on the platform or
if the characteristic is invalid.
@@ -253,43 +226,53 @@ QLowEnergyCharacteristic &QLowEnergyCharacteristic::operator=(const QLowEnergyCh
}
/*!
- Returns \c true if \a other is equal to this QLowEnergyCharacteristic; otherwise \c false.
+ \fn bool QLowEnergyCharacteristic::operator==(const QLowEnergyCharacteristic &a,
+ const QLowEnergyCharacteristic &b)
+ \brief Returns \c true if \a a is equal to \a b, otherwise \c false.
+
+ Two \l QLowEnergyCharacteristic instances are considered to be equal if they refer to
+ the same characteristic on the same remote Bluetooth Low Energy device or both instances
+ have been default-constructed.
+ */
+
+/*!
+ \fn bool QLowEnergyCharacteristic::operator!=(const QLowEnergyCharacteristic &a,
+ const QLowEnergyCharacteristic &b)
+ \brief Returns \c true if \a a and \a b are not equal; otherwise \c
+ false.
+
+ Two QLowEnergyCharcteristic instances are considered to be equal if they refer to
+ the same characteristic on the same remote Bluetooth Low Energy device or both instances
+ have been default-constructed.
+ */
+
+/*!
+ \brief Returns \c true if \a a is equal to \a b; otherwise \c false.
+ \internal
Two \l QLowEnergyCharacteristic instances are considered to be equal if they refer to
the same characteristic on the same remote Bluetooth Low Energy device or both instances
have been default-constructed.
*/
-bool QLowEnergyCharacteristic::operator==(const QLowEnergyCharacteristic &other) const
+bool QLowEnergyCharacteristic::equals(const QLowEnergyCharacteristic &a,
+ const QLowEnergyCharacteristic &b)
{
- if (d_ptr != other.d_ptr)
+ if (a.d_ptr != b.d_ptr)
return false;
- if ((data && !other.data) || (!data && other.data))
+ if ((a.data && !b.data) || (!a.data && b.data))
return false;
- if (!data)
+ if (!a.data)
return true;
- if (data->handle != other.data->handle)
+ if (a.data->handle != b.data->handle)
return false;
return true;
}
/*!
- Returns \c true if \a other is not equal to this QLowEnergyCharacteristic; otherwise \c false.
-
- Two QLowEnergyCharcteristic instances are considered to be equal if they refer to
- the same characteristic on the same remote Bluetooth Low Energy device or both instances
- have been default-constructed.
- */
-
-bool QLowEnergyCharacteristic::operator!=(const QLowEnergyCharacteristic &other) const
-{
- return !(*this == other);
-}
-
-/*!
Returns \c true if the QLowEnergyCharacteristic object is valid, otherwise returns \c false.
An invalid characteristic object is not associated with any service (default-constructed)
@@ -333,9 +316,8 @@ QLowEnergyHandle QLowEnergyCharacteristic::attributeHandle() const
return data->handle;
}
-
/*!
- Returns the descriptor for \a uuid or an invalid \c QLowEnergyDescriptor instance.
+ Returns the descriptor for \a uuid or an invalid \l QLowEnergyDescriptor instance.
\sa descriptors()
*/
@@ -362,6 +344,60 @@ QLowEnergyDescriptor QLowEnergyCharacteristic::descriptor(const QBluetoothUuid &
}
/*!
+ Returns the Client Characteristic Configuration Descriptor or an
+ invalid \l QLowEnergyDescriptor instance if no
+ Client Characteristic Configuration Descriptor exists.
+
+ BTLE characteristics can support notifications and/or indications.
+ In both cases, the peripheral will inform the central on
+ each change of the characteristic's value. In the BTLE
+ attribute protocol, notification messages are not confirmed
+ by the central, while indications are confirmed.
+ Notifications are considered faster, but unreliable, while
+ indications are slower and more reliable.
+
+ If a characteristic supports notification or indication,
+ these can be enabled by writing special bit patterns to the
+ Client Characteristic Configuration Descriptor.
+ For convenience, these bit patterns are provided as
+ \l QLowEnergyCharacteristic::CCCDDisable,
+ \l QLowEnergyCharacteristic::CCCDEnableNotification, and
+ \l QLowEnergyCharacteristic::CCCDEnableIndication.
+
+ Enabling e.g. notification for a characteristic named
+ \c mycharacteristic in a service called \c myservice
+ could be done using the following code.
+ \code
+ auto cccd = mycharacteristic.clientCharacteristicConfiguration();
+ if (!cccd.isValid()) {
+ // your error handling
+ return error;
+ }
+ myservice->writeDescriptor(cccd, QLowEnergyCharacteristic::CCCDEnableNotification);
+ \endcode
+
+ \note
+ Calling \c characteristic.clientCharacteristicConfiguration() is equivalent to calling
+ \c characteristic.descriptor(QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration).
+
+ \note
+ It is not recommended to use both notifications and indications on the same characteristic.
+ This applies to both server-side when setting up the characteristics, as well as client-side
+ when enabling them. The bluetooth stack behavior differs from platform to platform and the
+ cross-platform behavior will likely be inconsistent. As an example a Bluez Linux client might
+ unconditionally try to enable both mechanisms if both are supported, whereas a macOS client
+ might unconditionally enable just the notifications. If both are needed consider creating two
+ separate characteristics.
+
+ \since 6.2
+ \sa descriptor()
+*/
+QLowEnergyDescriptor QLowEnergyCharacteristic::clientCharacteristicConfiguration() const
+{
+ return descriptor(QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration);
+}
+
+/*!
Returns the list of descriptors belonging to this characteristic; otherwise
an empty list.
@@ -380,7 +416,7 @@ QList<QLowEnergyDescriptor> QLowEnergyCharacteristic::descriptors() const
std::sort(descriptorKeys.begin(), descriptorKeys.end());
- for (const QLowEnergyHandle descHandle : qAsConst(descriptorKeys)) {
+ for (const QLowEnergyHandle descHandle : std::as_const(descriptorKeys)) {
QLowEnergyDescriptor descriptor(d_ptr, data->handle, descHandle);
result.append(descriptor);
}
@@ -388,4 +424,35 @@ QList<QLowEnergyDescriptor> QLowEnergyCharacteristic::descriptors() const
return result;
}
+/*!
+ \variable QLowEnergyCharacteristic::CCCDDisable
+ \since 6.2
+
+ Bit pattern to write into Client Characteristic Configuration Descriptor
+ to disable both notification and indication.
+
+ \sa QLowEnergyCharacteristic::clientCharacteristicConfiguration
+*/
+/*!
+ \variable QLowEnergyCharacteristic::CCCDEnableNotification
+ \since 6.2
+
+ Bit pattern to write into Client Characteristic Configuration Descriptor
+ to enable notification.
+
+ \sa QLowEnergyCharacteristic::clientCharacteristicConfiguration
+*/
+/*!
+ \variable QLowEnergyCharacteristic::CCCDEnableIndication
+ \since 6.2
+
+ Bit pattern to write into Client Characteristic Configuration Descriptor
+ to enable indication.
+
+ \sa QLowEnergyCharacteristic::clientCharacteristicConfiguration
+*/
+const QByteArray QLowEnergyCharacteristic::CCCDDisable = QByteArray::fromHex("0000");
+const QByteArray QLowEnergyCharacteristic::CCCDEnableNotification = QByteArray::fromHex("0100");
+const QByteArray QLowEnergyCharacteristic::CCCDEnableIndication = QByteArray::fromHex("0200");
+
QT_END_NAMESPACE
diff --git a/src/bluetooth/qlowenergycharacteristic.h b/src/bluetooth/qlowenergycharacteristic.h
index fe9b73fa..8219c2d4 100644
--- a/src/bluetooth/qlowenergycharacteristic.h
+++ b/src/bluetooth/qlowenergycharacteristic.h
@@ -1,42 +1,6 @@
-/***************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2016 BlackBerry Limited all rights reserved
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2016 BlackBerry Limited all rights reserved
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QLOWENERGYCHARACTERISTIC_H
#define QLOWENERGYCHARACTERISTIC_H
@@ -73,8 +37,14 @@ public:
~QLowEnergyCharacteristic();
QLowEnergyCharacteristic &operator=(const QLowEnergyCharacteristic &other);
- bool operator==(const QLowEnergyCharacteristic &other) const;
- bool operator!=(const QLowEnergyCharacteristic &other) const;
+ friend bool operator==(const QLowEnergyCharacteristic &a, const QLowEnergyCharacteristic &b)
+ {
+ return equals(a, b);
+ }
+ friend bool operator!=(const QLowEnergyCharacteristic &a, const QLowEnergyCharacteristic &b)
+ {
+ return !equals(a, b);
+ }
QString name() const;
@@ -83,14 +53,20 @@ public:
QByteArray value() const;
QLowEnergyCharacteristic::PropertyTypes properties() const;
- QLowEnergyHandle handle() const;
QLowEnergyDescriptor descriptor(const QBluetoothUuid &uuid) const;
QList<QLowEnergyDescriptor> descriptors() const;
+ QLowEnergyDescriptor clientCharacteristicConfiguration() const;
+
bool isValid() const;
-protected:
+ static const QByteArray CCCDDisable;
+ static const QByteArray CCCDEnableNotification;
+ static const QByteArray CCCDEnableIndication;
+
+private:
+ QLowEnergyHandle handle() const;
QLowEnergyHandle attributeHandle() const;
QSharedPointer<QLowEnergyServicePrivate> d_ptr;
@@ -101,19 +77,19 @@ protected:
friend class QLowEnergyControllerPrivateBluez;
friend class QLowEnergyControllerPrivateBluezDBus;
friend class QLowEnergyControllerPrivateCommon;
- friend class QLowEnergyControllerPrivateWin32;
friend class QLowEnergyControllerPrivateDarwin;
friend class QLowEnergyControllerPrivateWinRT;
- friend class QLowEnergyControllerPrivateWinRTNew;
QLowEnergyCharacteristicPrivate *data = nullptr;
QLowEnergyCharacteristic(QSharedPointer<QLowEnergyServicePrivate> p,
QLowEnergyHandle handle);
+
+ static bool equals(const QLowEnergyCharacteristic &a, const QLowEnergyCharacteristic &b);
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QLowEnergyCharacteristic::PropertyTypes)
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(QLowEnergyCharacteristic)
+QT_DECL_METATYPE_EXTERN(QLowEnergyCharacteristic, Q_BLUETOOTH_EXPORT)
#endif // QLOWENERGYCHARACTERISTIC_H
diff --git a/src/bluetooth/qlowenergycharacteristicdata.cpp b/src/bluetooth/qlowenergycharacteristicdata.cpp
index 700566a6..9c50e102 100644
--- a/src/bluetooth/qlowenergycharacteristicdata.cpp
+++ b/src/bluetooth/qlowenergycharacteristicdata.cpp
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qlowenergycharacteristicdata.h"
@@ -140,6 +104,9 @@ QLowEnergyCharacteristic::PropertyTypes QLowEnergyCharacteristicData::properties
/*! Sets the properties of this characteristic to \a properties. */
void QLowEnergyCharacteristicData::setProperties(QLowEnergyCharacteristic::PropertyTypes properties)
{
+ if ((properties & QLowEnergyCharacteristic::PropertyType::Notify) &&
+ (properties & QLowEnergyCharacteristic::PropertyType::Indicate))
+ qCWarning(QT_BT) << "Both NTF and IND properties set for characteristic" << d->uuid;
d->properties = properties;
}
@@ -254,27 +221,34 @@ bool QLowEnergyCharacteristicData::isValid() const
*/
/*!
- Returns \c true if \a cd1 and \a cd2 are equal with respect to their public state,
- otherwise returns \c false.
+ \brief Returns \c true if \a a and \a b are equal with respect to their public state,
+ otherwise returns \c false.
+ \internal
*/
-bool operator==(const QLowEnergyCharacteristicData &cd1, const QLowEnergyCharacteristicData &cd2)
+bool QLowEnergyCharacteristicData::equals(const QLowEnergyCharacteristicData &a,
+ const QLowEnergyCharacteristicData &b)
{
- return cd1.d == cd2.d || (
- cd1.uuid() == cd2.uuid()
- && cd1.properties() == cd2.properties()
- && cd1.descriptors() == cd2.descriptors()
- && cd1.value() == cd2.value()
- && cd1.readConstraints() == cd2.readConstraints()
- && cd1.writeConstraints() == cd2.writeConstraints()
- && cd1.minimumValueLength() == cd2.maximumValueLength()
- && cd1.maximumValueLength() == cd2.maximumValueLength());
+ return a.d == b.d
+ || (a.uuid() == b.uuid() && a.properties() == b.properties()
+ && a.descriptors() == b.descriptors() && a.value() == b.value()
+ && a.readConstraints() == b.readConstraints()
+ && a.writeConstraints() == b.writeConstraints()
+ && a.minimumValueLength() == b.maximumValueLength()
+ && a.maximumValueLength() == b.maximumValueLength());
}
/*!
- \fn bool operator!=(const QLowEnergyCharacteristicData &cd1,
- const QLowEnergyCharacteristicData &cd2)
- Returns \c true if \a cd1 and \a cd2 are not equal with respect to their public state,
- otherwise returns \c false.
+ \fn bool QLowEnergyCharacteristicData::operator==(const QLowEnergyCharacteristicData &a,
+ const QLowEnergyCharacteristicData &b)
+ \brief Returns \c true if \a a and \a b are equal with respect to their public state,
+ otherwise returns \c false.
+ */
+
+/*!
+ \fn bool QLowEnergyCharacteristicData::operator!=(const QLowEnergyCharacteristicData &a,
+ const QLowEnergyCharacteristicData &b)
+ \brief Returns \c true if \a a and \a b are not equal with respect to their public state,
+ otherwise returns \c false.
*/
QT_END_NAMESPACE
diff --git a/src/bluetooth/qlowenergycharacteristicdata.h b/src/bluetooth/qlowenergycharacteristicdata.h
index cf5de703..e127fee6 100644
--- a/src/bluetooth/qlowenergycharacteristicdata.h
+++ b/src/bluetooth/qlowenergycharacteristicdata.h
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QLOWENERGYCHARACTERISTICDATA_H
#define QLOWENERGYCHARACTERISTICDATA_H
@@ -48,14 +12,22 @@ class QLowEnergyDescriptorData;
struct QLowEnergyCharacteristicDataPrivate;
class Q_BLUETOOTH_EXPORT QLowEnergyCharacteristicData
{
- friend Q_BLUETOOTH_EXPORT bool operator==(const QLowEnergyCharacteristicData &cd1,
- const QLowEnergyCharacteristicData &cd2);
public:
QLowEnergyCharacteristicData();
QLowEnergyCharacteristicData(const QLowEnergyCharacteristicData &other);
~QLowEnergyCharacteristicData();
QLowEnergyCharacteristicData &operator=(const QLowEnergyCharacteristicData &other);
+ friend bool operator==(const QLowEnergyCharacteristicData &a,
+ const QLowEnergyCharacteristicData &b)
+ {
+ return equals(a, b);
+ }
+ friend bool operator!=(const QLowEnergyCharacteristicData &a,
+ const QLowEnergyCharacteristicData &b)
+ {
+ return !equals(a, b);
+ }
QBluetoothUuid uuid() const;
void setUuid(const QBluetoothUuid &uuid);
@@ -82,20 +54,14 @@ public:
bool isValid() const;
- void swap(QLowEnergyCharacteristicData &other) Q_DECL_NOTHROW { qSwap(d, other.d); }
+ void swap(QLowEnergyCharacteristicData &other) noexcept { d.swap(other.d); }
private:
+ static bool equals(const QLowEnergyCharacteristicData &a,
+ const QLowEnergyCharacteristicData &b);
QSharedDataPointer<QLowEnergyCharacteristicDataPrivate> d;
};
-Q_BLUETOOTH_EXPORT bool operator==(const QLowEnergyCharacteristicData &cd1,
- const QLowEnergyCharacteristicData &cd2);
-inline bool operator!=(const QLowEnergyCharacteristicData &cd1,
- const QLowEnergyCharacteristicData &cd2)
-{
- return !(cd1 == cd2);
-}
-
Q_DECLARE_SHARED(QLowEnergyCharacteristicData)
QT_END_NAMESPACE
diff --git a/src/bluetooth/qlowenergyconnectionparameters.cpp b/src/bluetooth/qlowenergyconnectionparameters.cpp
index 95256402..54eab42a 100644
--- a/src/bluetooth/qlowenergyconnectionparameters.cpp
+++ b/src/bluetooth/qlowenergyconnectionparameters.cpp
@@ -1,46 +1,12 @@
-/***************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qlowenergyconnectionparameters.h"
QT_BEGIN_NAMESPACE
+QT_IMPL_METATYPE_EXTERN(QLowEnergyConnectionParameters)
+
class QLowEnergyConnectionParametersPrivate : public QSharedData
{
public:
@@ -214,24 +180,33 @@ int QLowEnergyConnectionParameters::supervisionTimeout() const
*/
/*!
- Returns \a true if \a p1 and \a p2 are equal with respect to their public state,
- otherwise returns false.
+ \brief Returns \a true if \a a and \a b are equal with respect to their public state,
+ otherwise returns false.
+ \internal
*/
-bool operator==(const QLowEnergyConnectionParameters &p1, const QLowEnergyConnectionParameters &p2)
+bool QLowEnergyConnectionParameters::equals(const QLowEnergyConnectionParameters &a,
+ const QLowEnergyConnectionParameters &b)
{
- if (p1.d == p2.d)
+ if (a.d == b.d)
return true;
- return p1.minimumInterval() == p2.minimumInterval()
- && p1.maximumInterval() == p2.maximumInterval()
- && p1.latency() == p2.latency()
- && p1.supervisionTimeout() == p2.supervisionTimeout();
+ return a.minimumInterval() == b.minimumInterval() && a.maximumInterval() == b.maximumInterval()
+ && a.latency() == b.latency() && a.supervisionTimeout() == b.supervisionTimeout();
}
/*!
- \fn bool operator!=(const QLowEnergyConnectionParameters &p1,
- const QLowEnergyConnectionParameters &p2)
- Returns \a true if \a p1 and \a p2 are not equal with respect to their public state,
- otherwise returns false.
+ \fn bool QLowEnergyConnectionParameters::operator!=(
+ const QLowEnergyConnectionParameters &p1,
+ const QLowEnergyConnectionParameters &p2)
+ \brief Returns \c true if \a p1 and \a p2 are not equal with respect to their public state,
+ otherwise returns \c false.
+ */
+
+/*!
+ \fn bool QLowEnergyConnectionParameters::operator==(
+ const QLowEnergyConnectionParameters &p1,
+ const QLowEnergyConnectionParameters &p2)
+ \brief Returns \c true if \a p1 and \a p2 are equal with respect to their public state,
+ otherwise returns \c false.
*/
QT_END_NAMESPACE
diff --git a/src/bluetooth/qlowenergyconnectionparameters.h b/src/bluetooth/qlowenergyconnectionparameters.h
index c765763f..8a30e82a 100644
--- a/src/bluetooth/qlowenergyconnectionparameters.h
+++ b/src/bluetooth/qlowenergyconnectionparameters.h
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QLOWENERGYCONNECTIONPARAMETERS_H
#define QLOWENERGYCONNECTIONPARAMETERS_H
@@ -50,14 +14,22 @@ class QLowEnergyConnectionParametersPrivate;
class Q_BLUETOOTH_EXPORT QLowEnergyConnectionParameters
{
- friend Q_BLUETOOTH_EXPORT bool operator==(const QLowEnergyConnectionParameters &p1,
- const QLowEnergyConnectionParameters &p2);
public:
QLowEnergyConnectionParameters();
QLowEnergyConnectionParameters(const QLowEnergyConnectionParameters &other);
~QLowEnergyConnectionParameters();
QLowEnergyConnectionParameters &operator=(const QLowEnergyConnectionParameters &other);
+ friend bool operator==(const QLowEnergyConnectionParameters &a,
+ const QLowEnergyConnectionParameters &b)
+ {
+ return equals(a, b);
+ }
+ friend bool operator!=(const QLowEnergyConnectionParameters &a,
+ const QLowEnergyConnectionParameters &b)
+ {
+ return !equals(a, b);
+ }
void setIntervalRange(double minimum, double maximum);
double minimumInterval() const;
@@ -69,24 +41,18 @@ public:
void setSupervisionTimeout(int timeout);
int supervisionTimeout() const;
- void swap(QLowEnergyConnectionParameters &other) Q_DECL_NOTHROW { qSwap(d, other.d); }
+ void swap(QLowEnergyConnectionParameters &other) noexcept { d.swap(other.d); }
private:
+ static bool equals(const QLowEnergyConnectionParameters &a,
+ const QLowEnergyConnectionParameters &b);
QSharedDataPointer<QLowEnergyConnectionParametersPrivate> d;
};
-Q_BLUETOOTH_EXPORT bool operator==(const QLowEnergyConnectionParameters &p1,
- const QLowEnergyConnectionParameters &p2);
-inline bool operator!=(const QLowEnergyConnectionParameters &p1,
- const QLowEnergyConnectionParameters &p2)
-{
- return !(p1 == p2);
-}
-
Q_DECLARE_SHARED(QLowEnergyConnectionParameters)
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(QLowEnergyConnectionParameters)
+QT_DECL_METATYPE_EXTERN(QLowEnergyConnectionParameters, Q_BLUETOOTH_EXPORT)
#endif // Include guard
diff --git a/src/bluetooth/qlowenergycontroller.cpp b/src/bluetooth/qlowenergycontroller.cpp
index 06fa0369..ec23f730 100644
--- a/src/bluetooth/qlowenergycontroller.cpp
+++ b/src/bluetooth/qlowenergycontroller.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qlowenergycontroller.h"
@@ -54,14 +18,10 @@
#include "qlowenergycontroller_bluez_p.h"
#elif defined(QT_ANDROID_BLUETOOTH)
#include "qlowenergycontroller_android_p.h"
+#include "android/androidutils_p.h"
#elif defined(QT_WINRT_BLUETOOTH)
#include "qtbluetoothglobal_p.h"
#include "qlowenergycontroller_winrt_p.h"
-#if QT_CONFIG(winrt_btle_no_pairing)
-#include "qlowenergycontroller_winrt_new_p.h"
-#endif
-#elif defined(QT_WIN_BLUETOOTH)
-#include "qlowenergycontroller_win_p.h"
#elif defined(Q_OS_DARWIN)
#include "qlowenergycontroller_darwin_p.h"
#else
@@ -72,8 +32,17 @@
QT_BEGIN_NAMESPACE
+QT_IMPL_METATYPE_EXTERN_TAGGED(QLowEnergyController::Error, QLowEnergyController__Error)
+QT_IMPL_METATYPE_EXTERN_TAGGED(QLowEnergyController::ControllerState,
+ QLowEnergyController__ControllerState)
+QT_IMPL_METATYPE_EXTERN_TAGGED(QLowEnergyController::RemoteAddressType,
+ QLowEnergyController__RemoteAddressType)
+QT_IMPL_METATYPE_EXTERN_TAGGED(QLowEnergyController::Role, QLowEnergyController__Role)
+
Q_DECLARE_LOGGING_CATEGORY(QT_BT)
-Q_DECLARE_LOGGING_CATEGORY(QT_BT_WINRT)
+#if defined(QT_ANDROID_BLUETOOTH)
+Q_DECLARE_LOGGING_CATEGORY(QT_BT_ANDROID)
+#endif
/*!
\class QLowEnergyController
@@ -155,15 +124,16 @@ Q_DECLARE_LOGGING_CATEGORY(QT_BT_WINRT)
\value InvalidBluetoothAdapterError The local Bluetooth device with the address passed to
the constructor of this class cannot be found or
there is no local Bluetooth device.
- \value ConnectionError The attempt to connect to the remote device failed.
- This value was introduced by Qt 5.5.
- \value AdvertisingError The attempt to start advertising failed.
- This value was introduced by Qt 5.7.
- \value RemoteHostClosedError The remote device closed the connection.
- This value was introduced by Qt 5.10.
- \value AuthorizationError The local Bluetooth device closed the connection due to
- insufficient authorization.
- This value was introduced by Qt 5.14.
+ \value [since 5.5] ConnectionError The attempt to connect to the remote device failed.
+ \value [since 5.7] AdvertisingError The attempt to start advertising failed.
+ \value [since 5.10] RemoteHostClosedError The remote device closed the connection.
+ \value [since 5.14] AuthorizationError The local Bluetooth device closed the connection
+ due to insufficient authorization.
+ \value [since 6.4] MissingPermissionsError The operating system requests
+ permissions which were not
+ granted by the user.
+ \value [since 6.5] RssiReadError An attempt to read RSSI (received signal strength indicator)
+ of a remote device finished with error.
*/
/*!
@@ -179,8 +149,7 @@ Q_DECLARE_LOGGING_CATEGORY(QT_BT_WINRT)
\value DiscoveredState The controller has discovered all services offered by the
remote device.
\value ClosingState The controller is about to be disconnected from the remote device.
- \value AdvertisingState The controller is currently advertising data.
- This value was introduced by Qt 5.7.
+ \value [since 5.7] AdvertisingState The controller is currently advertising data.
*/
/*!
@@ -212,7 +181,7 @@ Q_DECLARE_LOGGING_CATEGORY(QT_BT_WINRT)
\sa QLowEnergyController::createCentral()
\sa QLowEnergyController::createPeripheral()
\since 5.7
- \note The peripheral role is currently only supported on Linux. In addition, handling the
+ \note The peripheral role is not supported on Windows. In addition on Linux, handling the
"Signed Write" ATT command on the server side requires BlueZ 5 and kernel version 3.7
or newer.
*/
@@ -224,17 +193,47 @@ Q_DECLARE_LOGGING_CATEGORY(QT_BT_WINRT)
This signal is emitted when the controller successfully connects to the remote
Low Energy device (if the controller is in the \l CentralRole) or if a remote Low Energy
device connected to the controller (if the controller is in the \l PeripheralRole).
- On iOS and OS X this signal is not reliable if the controller is in the \l PeripheralRole
- - the controller only guesses that some central connected to our peripheral as
- soon as this central tries to write/read a characteristic/descriptor.
+ On iOS, macOS, and Android this signal is not reliable if the controller is in the
+ \l PeripheralRole. On iOS and macOS the controller only guesses that some central
+ connected to our peripheral as soon as this central tries to write/read a
+ characteristic/descriptor. On Android the controller monitors all connected GATT
+ devices. On Linux BlueZ DBus peripheral backend the remote is considered connected
+ when it first reads/writes a characteristic or a descriptor.
+*/
+
+/*!
+ \fn void QLowEnergyController::mtuChanged(int mtu)
+
+ This signal is emitted as a result of a successful MTU change. \a mtu
+ represents the new value.
+
+ \note If the controller is in the \l PeripheralRole, the MTU value is negotiated
+ for each client/central device individually. Therefore this signal can be emitted
+ several times in a row for one or several devices.
+
+ \sa mtu()
+*/
+
+/*!
+ \fn void QLowEnergyController::rssiRead(qint16 rssi)
+
+ This signal is emitted after successful read of RSSI (received
+ signal strength indicator) for a connected remote device.
+ \a rssi parameter represents the new value.
+
+ \sa readRssi()
+ \since 6.5
*/
/*!
\fn void QLowEnergyController::disconnected()
This signal is emitted when the controller disconnects from the remote
- Low Energy device or vice versa. On iOS and OS X this signal is unreliable
- if the controller is in the \l PeripheralRole.
+ Low Energy device or vice versa. On iOS and macOS this signal is unreliable
+ if the controller is in the \l PeripheralRole. On Android the signal is emitted
+ when the last connected device is disconnected. On BlueZ DBus backend the controller
+ is considered disconnected when last client which has accessed the attributes has
+ disconnected.
*/
/*!
@@ -247,12 +246,13 @@ Q_DECLARE_LOGGING_CATEGORY(QT_BT_WINRT)
*/
/*!
- \fn void QLowEnergyController::error(QLowEnergyController::Error newError)
+ \fn void QLowEnergyController::errorOccurred(QLowEnergyController::Error newError)
This signal is emitted when an error occurs.
The \a newError parameter describes the error that occurred.
\sa error(), errorString()
+ \since 6.2
*/
/*!
@@ -304,38 +304,58 @@ void registerQLowEnergyControllerMetaType()
}
}
-static QLowEnergyControllerPrivate *privateController(QLowEnergyController::Role role)
+static QLowEnergyControllerPrivate *privateController(
+ QLowEnergyController::Role role,
+ const QBluetoothAddress& localDevice = QBluetoothAddress{})
{
#if QT_CONFIG(bluez) && !defined(QT_BLUEZ_NO_BTLE)
- // The new DBUS implementation only supports Central role for now
- // For Peripheral role support see QTBUG-66909
+ // Central role
+ // The minimum Bluez DBus version for central role is 5.42, otherwise we
+ // fall back to kernel ATT backend. Application can also force the choice
+ // with an environment variable (see bluetoothdVersion())
+ //
+ // Peripheral role
+ // The DBus peripheral backend is the default, and for that we check the presence of
+ // the required DBus APIs and bluez version. The application may opt-out of the DBus
+ // peripheral role by setting the environment variable. The fall-back is the kernel ATT
+ // backend
+ //
+ // ### Qt 7 consider removing the non-dbus bluez (kernel ATT) support
+
+ QString adapterPathWithPeripheralSupport;
+ if (role == QLowEnergyController::PeripheralRole
+ && bluetoothdVersion() >= QVersionNumber(5, 56)
+ && !qEnvironmentVariableIsSet("QT_BLUETOOTH_USE_KERNEL_PERIPHERAL")) {
+ adapterPathWithPeripheralSupport = adapterWithDBusPeripheralInterface(localDevice);
+ }
+
if (role == QLowEnergyController::CentralRole
&& bluetoothdVersion() >= QVersionNumber(5, 42)) {
- qCWarning(QT_BT) << "Using BlueZ LE DBus API";
+ qCDebug(QT_BT) << "Using BlueZ LE DBus API for central";
return new QLowEnergyControllerPrivateBluezDBus();
+ } else if (!adapterPathWithPeripheralSupport.isEmpty()) {
+ qCDebug(QT_BT) << "Using BlueZ LE DBus API for peripheral";
+ return new QLowEnergyControllerPrivateBluezDBus(adapterPathWithPeripheralSupport);
} else {
- qCWarning(QT_BT) << "Using BlueZ kernel ATT interface";
+ qCDebug(QT_BT) << "Using BlueZ kernel ATT interface for"
+ << (role == QLowEnergyController::CentralRole ? "central" : "peripheral");
return new QLowEnergyControllerPrivateBluez();
}
#elif defined(QT_ANDROID_BLUETOOTH)
Q_UNUSED(role);
+ Q_UNUSED(localDevice);
return new QLowEnergyControllerPrivateAndroid();
#elif defined(QT_WINRT_BLUETOOTH)
Q_UNUSED(role);
-#if QT_CONFIG(winrt_btle_no_pairing)
- return createWinRTLowEnergyController();
-#else
- qCDebug(QT_BT_WINRT) << "Using pre 15063 low energy controller";
+ Q_UNUSED(localDevice);
return new QLowEnergyControllerPrivateWinRT();
-#endif
-#elif defined(QT_WIN_BLUETOOTH)
- Q_UNUSED(role);
- return new QLowEnergyControllerPrivateWin32();
#elif defined(Q_OS_DARWIN)
- Q_UNUSED(role)
+ Q_UNUSED(role);
+ Q_UNUSED(localDevice);
return new QLowEnergyControllerPrivateDarwin();
#else
Q_UNUSED(role);
+ Q_UNUSED(localDevice);
return new QLowEnergyControllerPrivateCommon();
#endif
}
@@ -347,91 +367,35 @@ static QLowEnergyControllerPrivate *privateController(QLowEnergyController::Role
remote Bluetooth Low Energy device to which this object
should attempt to connect later on.
- The controller uses the local default Bluetooth adapter for
- the connection management.
-
- \obsolete
- */
-QLowEnergyController::QLowEnergyController(
- const QBluetoothAddress &remoteDevice,
- QObject *parent)
- : QObject(parent)
-{
- // Note: a central created using this ctor is useless
- // on Darwin - no way to use addresses when connecting.
-
- d_ptr = privateController(CentralRole);
-
- Q_D(QLowEnergyController);
- d->q_ptr = this;
- d->role = CentralRole;
- d->remoteDevice = remoteDevice;
- d->localAdapter = QBluetoothLocalDevice().address();
- d->addressType = QLowEnergyController::PublicAddress;
- d->init();
-}
-
-/*!
- Constructs a new instance of this class with \a parent.
-
- The \a remoteDeviceInfo must contain the details of the
- remote Bluetooth Low Energy device to which this object
- should attempt to connect later on.
-
- The controller uses the local default Bluetooth adapter for
- the connection management.
-
- \since 5.5
- \obsolete
-*/
-QLowEnergyController::QLowEnergyController(
- const QBluetoothDeviceInfo &remoteDeviceInfo,
- QObject *parent)
- : QObject(parent)
-{
- d_ptr = privateController(CentralRole);
-
- Q_D(QLowEnergyController);
- d->q_ptr = this;
- d->role = CentralRole;
- d->deviceUuid = remoteDeviceInfo.deviceUuid();
- d->remoteDevice = remoteDeviceInfo.address();
- d->localAdapter = QBluetoothLocalDevice().address();
- d->addressType = QLowEnergyController::PublicAddress;
- d->remoteName = remoteDeviceInfo.name();
- d->init();
-}
-
-/*!
- Constructs a new instance of this class with \a parent.
-
- The \a remoteDevice must contain the address of the
- remote Bluetooth Low Energy device to which this object
- should attempt to connect later on.
-
The connection is established via \a localDevice. If \a localDevice
is invalid, the local default device is automatically selected. If
\a localDevice specifies a local device that is not a local Bluetooth
adapter, \l error() is set to \l InvalidBluetoothAdapterError once
\l connectToDevice() is called.
- \obsolete
+ \note This is only supported on BlueZ
*/
QLowEnergyController::QLowEnergyController(
- const QBluetoothAddress &remoteDevice,
+ const QBluetoothDeviceInfo &remoteDevice,
const QBluetoothAddress &localDevice,
QObject *parent)
: QObject(parent)
{
- // Note: a central create using this ctor is useless on
- // Darwin (CoreBluetooth does not work with addresses).
d_ptr = privateController(CentralRole);
Q_D(QLowEnergyController);
d->q_ptr = this;
d->role = CentralRole;
- d->remoteDevice = remoteDevice;
- d->localAdapter = localDevice;
+ d->deviceUuid = remoteDevice.deviceUuid();
+ d->remoteDevice = remoteDevice.address();
+
+ if (localDevice.isNull())
+ d->localAdapter = QBluetoothLocalDevice().address();
+ else
+ d->localAdapter = localDevice;
+
+ d->addressType = QLowEnergyController::PublicAddress;
+ d->remoteName = remoteDevice.name();
d->init();
}
@@ -448,7 +412,7 @@ QLowEnergyController::QLowEnergyController(
QLowEnergyController *QLowEnergyController::createCentral(const QBluetoothDeviceInfo &remoteDevice,
QObject *parent)
{
- return new QLowEnergyController(remoteDevice, parent);
+ return new QLowEnergyController(remoteDevice, QBluetoothAddress(), parent);
}
/*!
@@ -467,7 +431,7 @@ QLowEnergyController *QLowEnergyController::createCentral(const QBluetoothDevice
\since 5.14
*/
-QLowEnergyController *QLowEnergyController::createCentral(const QBluetoothAddress &remoteDevice,
+QLowEnergyController *QLowEnergyController::createCentral(const QBluetoothDeviceInfo &remoteDevice,
const QBluetoothAddress &localDevice,
QObject *parent)
{
@@ -478,7 +442,8 @@ QLowEnergyController *QLowEnergyController::createCentral(const QBluetoothAddres
/*!
Returns a new object of this class that is in the \l PeripheralRole and has the
parent object \a parent.
- Typically, the next step is to call \l startAdvertising() on the returned object.
+ Typically, the next steps are to add some services and finally
+ call \l startAdvertising() on the returned object.
The controller uses the local default Bluetooth adapter for the connection management.
@@ -487,18 +452,46 @@ QLowEnergyController *QLowEnergyController::createCentral(const QBluetoothAddres
*/
QLowEnergyController *QLowEnergyController::createPeripheral(QObject *parent)
{
- return new QLowEnergyController(parent);
+ return new QLowEnergyController(QBluetoothAddress(), parent);
+}
+
+/*!
+ Returns a new object of this class that is in the \l PeripheralRole and has the
+ parent object \a parent and is using \a localDevice.
+ Typically, the next steps are to add some services and finally
+ call \l startAdvertising() on the returned object.
+
+ The peripheral is created on \a localDevice. If \a localDevice is invalid,
+ the local default device is automatically selected. If \a localDevice specifies
+ a local device that is not a local Bluetooth adapter, \l error() is set to
+ \l InvalidBluetoothAdapterError.
+
+ Selecting \a localDevice is only supported on Linux. On other platform,
+ the parameter is ignored.
+
+ \sa QLowEnergyController::PeripheralRole
+ \since 6.2
+ */
+QLowEnergyController *QLowEnergyController::createPeripheral(const QBluetoothAddress &localDevice,
+ QObject *parent)
+{
+ return new QLowEnergyController(localDevice, parent);
}
-QLowEnergyController::QLowEnergyController(QObject *parent)
+QLowEnergyController::QLowEnergyController(const QBluetoothAddress &localDevice, QObject *parent)
: QObject(parent)
{
- d_ptr = privateController(PeripheralRole);
+ d_ptr = privateController(PeripheralRole, localDevice);
Q_D(QLowEnergyController);
d->q_ptr = this;
d->role = PeripheralRole;
- d->localAdapter = QBluetoothLocalDevice().address();
+
+ if (localDevice.isNull())
+ d->localAdapter = QBluetoothLocalDevice().address();
+ else
+ d->localAdapter = localDevice;
+
d->init();
}
@@ -531,7 +524,7 @@ QBluetoothAddress QLowEnergyController::localAddress() const
For a controller in the \l CentralRole, this value will always be the one passed in when
the controller object was created. For a controller in the \l PeripheralRole, this value
- is the address of the currently connected client device. In particular, this address will
+ is one of the currently connected client device addresses. This address will
be invalid if the controller is not currently in the \l ConnectedState.
*/
QBluetoothAddress QLowEnergyController::remoteAddress() const
@@ -635,6 +628,7 @@ void QLowEnergyController::connectToDevice()
}
if (!d->isValidLocalAdapter()) {
+ qCWarning(QT_BT) << "connectToDevice() LE controller has invalid adapter";
d->setError(QLowEnergyController::InvalidBluetoothAdapterError);
return;
}
@@ -770,8 +764,11 @@ QLowEnergyService *QLowEnergyController::createServiceObject(
the advertised packets may not contain all uuids. The existing limit may have caused the truncation
of uuids. In such cases \a scanResponseData may be used for additional information.
+ On BlueZ DBus backend BlueZ decides if, and which data, to use in a scan response. Therefore
+ all advertisement data is recommended to set in the main \a advertisingData parameter. If both
+ advertisement and scan response data is set, the scan response data is given precedence.
+
If this object is currently not in the \l UnconnectedState, nothing happens.
- \note Advertising will stop automatically once a client connects to the local device.
\since 5.7
\sa stopAdvertising()
@@ -842,6 +839,13 @@ QLowEnergyService *QLowEnergyController::addService(const QLowEnergyServiceData
return nullptr;
}
+#if defined(QT_ANDROID_BLUETOOTH)
+ if (!ensureAndroidPermission(QBluetoothPermission::Access)) {
+ qCWarning(QT_BT_ANDROID) << "addService() failed due to missing permissions";
+ return nullptr;
+ }
+#endif
+
Q_D(QLowEnergyController);
QLowEnergyService *newService = d->addServiceHelper(service);
if (newService)
@@ -867,7 +871,7 @@ QLowEnergyService *QLowEnergyController::addService(const QLowEnergyServiceData
an acknowledged Android bug. Due to this bug Android does not emit the \l connectionUpdated()
signal.
- \note Currently, this functionality is only implemented on Linux and Android.
+ \note Currently, this functionality is only implemented on Linux kernel backend and Android.
\sa connectionUpdated()
\since 5.7
@@ -915,4 +919,65 @@ QLowEnergyController::Role QLowEnergyController::role() const
return d_ptr->role;
}
+/*!
+ Returns the MTU size.
+
+ During connection setup, the ATT MTU size is negotiated.
+ This method provides the result of this negotiation.
+ It can be used to optimize packet sizes in some situations.
+ The maximum amount of data which can be transferred in a single
+ packet is \b {mtu-3} bytes. 3 bytes are required for the ATT
+ protocol header.
+
+ Before the connection setup and MTU negotiation, the
+ default value of \c 23 will be returned.
+
+ Not every platform exposes the MTU value. On those platforms (e.g. Linux)
+ this function always returns \c -1.
+
+ If the controller is in the \l PeripheralRole, there might be several
+ central devices connected to it. In those cases this function returns
+ the MTU of the last connection that was negotiated.
+
+ \since 6.2
+ */
+int QLowEnergyController::mtu() const
+{
+ return d_ptr->mtu();
+}
+
+/*!
+ readRssi() reads RSSI (received signal strength indicator) for a connected remote device.
+ If the read was successful, the RSSI is then reported by rssiRead() signal.
+
+ \note Prior to calling readRssi(), this controller must be connected to a peripheral.
+ This controller must be created using createCentral().
+
+ \note In case Bluetooth backend you are using does not support reading RSSI,
+ the errorOccurred() signal is emitted with an error code QLowEnergyController::RssiReadError.
+ At the moment platforms supporting reading RSSI include Android, iOS and macOS.
+
+ \sa rssiRead(), connectToDevice(), state(), createCentral(), errorOccurred()
+ \since 6.5
+*/
+void QLowEnergyController::readRssi()
+{
+ if (role() != CentralRole) {
+ qCWarning(QT_BT, "Invalid role (peripheral), cannot read RSSI");
+ return d_ptr->setError(RssiReadError); // This also emits.
+ }
+
+ switch (state()) {
+ case UnconnectedState:
+ case ConnectingState:
+ case ClosingState:
+ qCWarning(QT_BT, "Cannot read RSSI while not in 'Connected' state, connect first");
+ return d_ptr->setError(RssiReadError); // Will emit.
+ default:
+ d_ptr->readRssi();
+ }
+}
+
QT_END_NAMESPACE
+
+#include "moc_qlowenergycontroller.cpp"
diff --git a/src/bluetooth/qlowenergycontroller.h b/src/bluetooth/qlowenergycontroller.h
index 37e7b82d..0a42d9ab 100644
--- a/src/bluetooth/qlowenergycontroller.h
+++ b/src/bluetooth/qlowenergycontroller.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QLOWENERGYCONTROLLER_H
#define QLOWENERGYCONTROLLER_H
@@ -45,12 +9,12 @@
#include <QtBluetooth/QBluetoothDeviceInfo>
#include <QtBluetooth/QBluetoothUuid>
#include <QtBluetooth/QLowEnergyAdvertisingData>
+#include <QtBluetooth/QLowEnergyConnectionParameters>
#include <QtBluetooth/QLowEnergyService>
QT_BEGIN_NAMESPACE
class QLowEnergyAdvertisingParameters;
-class QLowEnergyConnectionParameters;
class QLowEnergyControllerPrivate;
class QLowEnergyServiceData;
@@ -67,7 +31,9 @@ public:
ConnectionError,
AdvertisingError,
RemoteHostClosedError,
- AuthorizationError
+ AuthorizationError,
+ MissingPermissionsError,
+ RssiReadError
};
Q_ENUM(Error)
@@ -91,19 +57,13 @@ public:
enum Role { CentralRole, PeripheralRole };
Q_ENUM(Role)
- explicit QLowEnergyController(const QBluetoothAddress &remoteDevice,
- QObject *parent = nullptr); // TODO Qt 6 remove ctor
- explicit QLowEnergyController(const QBluetoothDeviceInfo &remoteDevice,
- QObject *parent = nullptr); // TODO Qt 6 make private
- explicit QLowEnergyController(const QBluetoothAddress &remoteDevice,
- const QBluetoothAddress &localDevice,
- QObject *parent = nullptr); // TODO Qt 6 remove ctor
-
static QLowEnergyController *createCentral(const QBluetoothDeviceInfo &remoteDevice,
QObject *parent = nullptr);
- static QLowEnergyController *createCentral(const QBluetoothAddress &remoteDevice,
+ static QLowEnergyController *createCentral(const QBluetoothDeviceInfo &remoteDevice,
const QBluetoothAddress &localDevice,
QObject *parent = nullptr);
+ static QLowEnergyController *createPeripheral(const QBluetoothAddress &localDevice,
+ QObject *parent = nullptr);
static QLowEnergyController *createPeripheral(QObject *parent = nullptr);
// TODO: Allow to set connection timeout (disconnect when no data has been exchanged for n seconds).
@@ -143,18 +103,31 @@ public:
Role role() const;
+ int mtu() const;
+ void readRssi();
+
Q_SIGNALS:
void connected();
void disconnected();
void stateChanged(QLowEnergyController::ControllerState state);
- void error(QLowEnergyController::Error newError);
+ void errorOccurred(QLowEnergyController::Error newError);
+ void mtuChanged(int mtu);
+ void rssiRead(qint16 rssi);
void serviceDiscovered(const QBluetoothUuid &newService);
void discoveryFinished();
void connectionUpdated(const QLowEnergyConnectionParameters &parameters);
+
private:
- explicit QLowEnergyController(QObject *parent = nullptr); // For the peripheral role.
+ // peripheral role ctor
+ explicit QLowEnergyController(const QBluetoothAddress &localDevice, QObject *parent = nullptr);
+
+ // central role ctors
+ explicit QLowEnergyController(const QBluetoothDeviceInfo &remoteDevice,
+ const QBluetoothAddress &localDevice,
+ QObject *parent = nullptr);
+
Q_DECLARE_PRIVATE(QLowEnergyController)
QLowEnergyControllerPrivate *d_ptr;
@@ -162,9 +135,15 @@ private:
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(QLowEnergyController::Error)
-Q_DECLARE_METATYPE(QLowEnergyController::ControllerState)
-Q_DECLARE_METATYPE(QLowEnergyController::RemoteAddressType)
-Q_DECLARE_METATYPE(QLowEnergyController::Role)
+QT_DECL_METATYPE_EXTERN_TAGGED(QLowEnergyController::Error, QLowEnergyController__Error,
+ Q_BLUETOOTH_EXPORT)
+QT_DECL_METATYPE_EXTERN_TAGGED(QLowEnergyController::ControllerState,
+ QLowEnergyController__ControllerState,
+ Q_BLUETOOTH_EXPORT)
+QT_DECL_METATYPE_EXTERN_TAGGED(QLowEnergyController::RemoteAddressType,
+ QLowEnergyController__RemoteAddressType,
+ Q_BLUETOOTH_EXPORT)
+QT_DECL_METATYPE_EXTERN_TAGGED(QLowEnergyController::Role, QLowEnergyController__Role,
+ Q_BLUETOOTH_EXPORT)
#endif // QLOWENERGYCONTROLLER_H
diff --git a/src/bluetooth/qlowenergycontroller_android.cpp b/src/bluetooth/qlowenergycontroller_android.cpp
index 86e6ade7..b88a2248 100644
--- a/src/bluetooth/qlowenergycontroller_android.cpp
+++ b/src/bluetooth/qlowenergycontroller_android.cpp
@@ -1,46 +1,13 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qlowenergycontroller_android_p.h"
+#include "android/androidutils_p.h"
+#include "android/jni_android_p.h"
+#include <QCoreApplication>
#include <QtCore/QLoggingCategory>
-#include <QtAndroidExtras/QAndroidJniEnvironment>
-#include <QtAndroidExtras/QAndroidJniObject>
+#include <QtCore/QJniEnvironment>
+#include <QtCore/QJniObject>
#include <QtBluetooth/QLowEnergyServiceData>
#include <QtBluetooth/QLowEnergyCharacteristicData>
#include <QtBluetooth/QLowEnergyDescriptorData>
@@ -48,24 +15,23 @@
#include <QtBluetooth/QLowEnergyAdvertisingParameters>
#include <QtBluetooth/QLowEnergyConnectionParameters>
-
QT_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(QT_BT_ANDROID)
-Q_DECLARE_METATYPE(QAndroidJniObject)
+// BT Core v5.3, 3.2.9, Vol 3, Part F
+const int BTLE_MAX_ATTRIBUTE_VALUE_SIZE = 512;
// Conversion: QBluetoothUuid -> java.util.UUID
-static QAndroidJniObject javaUuidfromQtUuid(const QBluetoothUuid& uuid)
+static QJniObject javaUuidfromQtUuid(const QBluetoothUuid& uuid)
{
- QString output = uuid.toString();
// cut off leading and trailing brackets
- output = output.mid(1, output.size()-2);
+ const QString output = uuid.toString(QUuid::WithoutBraces);
- QAndroidJniObject javaString = QAndroidJniObject::fromString(output);
- QAndroidJniObject javaUuid = QAndroidJniObject::callStaticObjectMethod(
- "java/util/UUID", "fromString", "(Ljava/lang/String;)Ljava/util/UUID;",
- javaString.object());
+ QJniObject javaString = QJniObject::fromString(output);
+ QJniObject javaUuid = QJniObject::callStaticMethod<QtJniTypes::UUID>(
+ QtJniTypes::Traits<QtJniTypes::UUID>::className(), "fromString",
+ javaString.object<jstring>());
return javaUuid;
}
@@ -87,25 +53,17 @@ QLowEnergyControllerPrivateAndroid::~QLowEnergyControllerPrivateAndroid()
void QLowEnergyControllerPrivateAndroid::init()
{
- // Android Central/Client support starts with v18
- // Peripheral/Server support requires Android API v21
const bool isPeripheral = (role == QLowEnergyController::PeripheralRole);
- const jint version = QtAndroidPrivate::androidSdkVersion();
if (isPeripheral) {
- if (version < 21) {
- qWarning() << "Qt Bluetooth LE Peripheral support not available"
- "on Android devices below version 21";
- return;
- }
-
- qRegisterMetaType<QAndroidJniObject>();
-
+ qRegisterMetaType<QJniObject>();
hub = new LowEnergyNotificationHub(remoteDevice, isPeripheral, this);
// we only connect to the peripheral role specific signals
// TODO add connections as they get added later on
connect(hub, &LowEnergyNotificationHub::connectionUpdated,
this, &QLowEnergyControllerPrivateAndroid::connectionUpdated);
+ connect(hub, &LowEnergyNotificationHub::mtuChanged,
+ this, &QLowEnergyControllerPrivateAndroid::mtuChanged);
connect(hub, &LowEnergyNotificationHub::advertisementError,
this, &QLowEnergyControllerPrivateAndroid::advertisementError);
connect(hub, &LowEnergyNotificationHub::serverCharacteristicChanged,
@@ -113,16 +71,12 @@ void QLowEnergyControllerPrivateAndroid::init()
connect(hub, &LowEnergyNotificationHub::serverDescriptorWritten,
this, &QLowEnergyControllerPrivateAndroid::serverDescriptorWritten);
} else {
- if (version < 18) {
- qWarning() << "Qt Bluetooth LE Central/Client support not available"
- "on Android devices below version 18";
- return;
- }
-
hub = new LowEnergyNotificationHub(remoteDevice, isPeripheral, this);
// we only connect to the central role specific signals
connect(hub, &LowEnergyNotificationHub::connectionUpdated,
this, &QLowEnergyControllerPrivateAndroid::connectionUpdated);
+ connect(hub, &LowEnergyNotificationHub::mtuChanged,
+ this, &QLowEnergyControllerPrivateAndroid::mtuChanged);
connect(hub, &LowEnergyNotificationHub::servicesDiscovered,
this, &QLowEnergyControllerPrivateAndroid::servicesDiscovered);
connect(hub, &LowEnergyNotificationHub::serviceDetailsDiscoveryFinished,
@@ -137,17 +91,30 @@ void QLowEnergyControllerPrivateAndroid::init()
this, &QLowEnergyControllerPrivateAndroid::descriptorWritten);
connect(hub, &LowEnergyNotificationHub::characteristicChanged,
this, &QLowEnergyControllerPrivateAndroid::characteristicChanged);
+ connect(hub, &LowEnergyNotificationHub::serviceError,
+ this, &QLowEnergyControllerPrivateAndroid::serviceError);
+ connect(hub, &LowEnergyNotificationHub::remoteRssiRead,
+ this, &QLowEnergyControllerPrivateAndroid::remoteRssiRead);
}
}
void QLowEnergyControllerPrivateAndroid::connectToDevice()
{
- if (!hub)
- return; // Android version below v18
+ if (!hub) {
+ qCCritical(QT_BT_ANDROID) << "connectToDevice() LE controller has not been initialized";
+ return;
+ }
+
+ if (!ensureAndroidPermission(QBluetoothPermission::Access)) {
+ // This is unlikely to happen as a valid local adapter is a precondition
+ setError(QLowEnergyController::MissingPermissionsError);
+ qCWarning(QT_BT_ANDROID) << "connectToDevice() failed due to missing permissions";
+ return;
+ }
// required to pass unit test on default backend
if (remoteDevice.isNull()) {
- qWarning() << "Invalid/null remote device address";
+ qCWarning(QT_BT_ANDROID) << "Invalid/null remote device address";
setError(QLowEnergyController::UnknownRemoteDeviceError);
return;
}
@@ -193,6 +160,8 @@ void QLowEnergyControllerPrivateAndroid::disconnectFromDevice()
void QLowEnergyControllerPrivateAndroid::discoverServices()
{
+ // No need to check bluetooth permissions here as 'connected' is a precondition
+
if (hub && hub->javaObject().callMethod<jboolean>("discoverServices")) {
qCDebug(QT_BT_ANDROID) << "Service discovery initiated";
} else {
@@ -202,8 +171,10 @@ void QLowEnergyControllerPrivateAndroid::discoverServices()
}
}
-void QLowEnergyControllerPrivateAndroid::discoverServiceDetails(const QBluetoothUuid &service)
+void QLowEnergyControllerPrivateAndroid::discoverServiceDetails(
+ const QBluetoothUuid &service, QLowEnergyService::DiscoveryMode mode)
{
+ Q_UNUSED(mode);
if (!serviceList.contains(service)) {
qCWarning(QT_BT_ANDROID) << "Discovery of unknown service" << service.toString()
<< "not possible";
@@ -213,22 +184,20 @@ void QLowEnergyControllerPrivateAndroid::discoverServiceDetails(const QBluetooth
if (!hub)
return;
- //cut leading { and trailing } {xxx-xxx}
- QString tempUuid = service.toString();
- tempUuid.chop(1); //remove trailing '}'
- tempUuid.remove(0, 1); //remove first '{'
+ QString tempUuid = service.toString(QUuid::WithoutBraces);
- QAndroidJniEnvironment env;
- QAndroidJniObject uuid = QAndroidJniObject::fromString(tempUuid);
+ QJniEnvironment env;
+ QJniObject uuid = QJniObject::fromString(tempUuid);
+ bool readAllValues = mode == QLowEnergyService::FullDiscovery;
bool result = hub->javaObject().callMethod<jboolean>("discoverServiceDetails",
- "(Ljava/lang/String;)Z",
- uuid.object<jstring>());
+ uuid.object<jstring>(),
+ readAllValues);
if (!result) {
QSharedPointer<QLowEnergyServicePrivate> servicePrivate =
serviceList.value(service);
if (!servicePrivate.isNull()) {
servicePrivate->setError(QLowEnergyService::UnknownError);
- servicePrivate->setState(QLowEnergyService::DiscoveryRequired);
+ servicePrivate->setState(QLowEnergyService::RemoteService);
}
qCWarning(QT_BT_ANDROID) << "Cannot discover details for" << service.toString();
return;
@@ -249,7 +218,7 @@ void QLowEnergyControllerPrivateAndroid::writeCharacteristic(
if (!service->characteristicList.contains(charHandle))
return;
- QAndroidJniEnvironment env;
+ QJniEnvironment env;
jbyteArray payload;
payload = env->NewByteArray(newValue.size());
env->SetByteArrayRegion(payload, 0, newValue.size(),
@@ -262,29 +231,25 @@ void QLowEnergyControllerPrivateAndroid::writeCharacteristic(
<< newValue.toHex() << "(service:" << service->uuid
<< ", writeWithResponse:" << (mode == QLowEnergyService::WriteWithResponse)
<< ", signed:" << (mode == QLowEnergyService::WriteSigned) << ")";
- result = hub->javaObject().callMethod<jboolean>("writeCharacteristic", "(I[BI)Z",
- charHandle, payload, mode);
+ result = hub->javaObject().callMethod<jboolean>("writeCharacteristic",
+ charHandle, payload, jint(mode));
} else { // peripheral mode
qCDebug(QT_BT_ANDROID) << "Write server characteristic with handle " << charHandle
<< newValue.toHex() << "(service:" << service->uuid;
const auto &characteristic = characteristicForHandle(charHandle);
if (characteristic.isValid()) {
- const QAndroidJniObject charUuid = javaUuidfromQtUuid(characteristic.uuid());
+ const QJniObject charUuid = javaUuidfromQtUuid(characteristic.uuid());
result = hub->javaObject().callMethod<jboolean>(
"writeCharacteristic",
- "(Landroid/bluetooth/BluetoothGattService;Ljava/util/UUID;[B)Z",
- service->androidService.object(), charUuid.object(), payload);
+ service->androidService.object<QtJniTypes::BluetoothGattService>(),
+ charUuid.object<QtJniTypes::UUID>(), payload);
+ if (result)
+ service->characteristicList[charHandle].value = newValue;
}
}
}
- if (env->ExceptionOccurred()) {
- env->ExceptionDescribe();
- env->ExceptionClear();
- result = false;
- }
-
env->DeleteLocalRef(payload);
if (!result)
@@ -299,7 +264,7 @@ void QLowEnergyControllerPrivateAndroid::writeDescriptor(
{
Q_ASSERT(!service.isNull());
- QAndroidJniEnvironment env;
+ QJniEnvironment env;
jbyteArray payload;
payload = env->NewByteArray(newValue.size());
env->SetByteArrayRegion(payload, 0, newValue.size(),
@@ -310,7 +275,7 @@ void QLowEnergyControllerPrivateAndroid::writeDescriptor(
if (role == QLowEnergyController::CentralRole) {
qCDebug(QT_BT_ANDROID) << "Write descriptor with handle " << descHandle
<< newValue.toHex() << "(service:" << service->uuid << ")";
- result = hub->javaObject().callMethod<jboolean>("writeDescriptor", "(I[B)Z",
+ result = hub->javaObject().callMethod<jboolean>("writeDescriptor",
descHandle, payload);
} else {
const auto &characteristic = characteristicForHandle(charHandle);
@@ -319,23 +284,19 @@ void QLowEnergyControllerPrivateAndroid::writeDescriptor(
qCDebug(QT_BT_ANDROID) << "Write descriptor" << descriptor.uuid()
<< "(service:" << service->uuid
<< "char: " << characteristic.uuid() << ")";
- const QAndroidJniObject charUuid = javaUuidfromQtUuid(characteristic.uuid());
- const QAndroidJniObject descUuid = javaUuidfromQtUuid(descriptor.uuid());
+ const QJniObject charUuid = javaUuidfromQtUuid(characteristic.uuid());
+ const QJniObject descUuid = javaUuidfromQtUuid(descriptor.uuid());
result = hub->javaObject().callMethod<jboolean>(
- "writeDescriptor",
- "(Landroid/bluetooth/BluetoothGattService;Ljava/util/UUID;Ljava/util/UUID;[B)Z",
- service->androidService.object(), charUuid.object(),
- descUuid.object(), payload);
+ "writeDescriptor",
+ service->androidService.object<QtJniTypes::BluetoothGattService>(),
+ charUuid.object<QtJniTypes::UUID>(), descUuid.object<QtJniTypes::UUID>(),
+ payload);
+ if (result)
+ service->characteristicList[charHandle].descriptorList[descHandle].value = newValue;
}
}
}
- if (env->ExceptionOccurred()) {
- env->ExceptionDescribe();
- env->ExceptionClear();
- result = false;
- }
-
env->DeleteLocalRef(payload);
if (!result)
@@ -351,19 +312,12 @@ void QLowEnergyControllerPrivateAndroid::readCharacteristic(
if (!service->characteristicList.contains(charHandle))
return;
- QAndroidJniEnvironment env;
+ QJniEnvironment env;
bool result = false;
if (hub) {
qCDebug(QT_BT_ANDROID) << "Read characteristic with handle"
<< charHandle << service->uuid;
- result = hub->javaObject().callMethod<jboolean>("readCharacteristic",
- "(I)Z", charHandle);
- }
-
- if (env->ExceptionOccurred()) {
- env->ExceptionDescribe();
- env->ExceptionClear();
- result = false;
+ result = hub->javaObject().callMethod<jboolean>("readCharacteristic", charHandle);
}
if (!result)
@@ -377,19 +331,12 @@ void QLowEnergyControllerPrivateAndroid::readDescriptor(
{
Q_ASSERT(!service.isNull());
- QAndroidJniEnvironment env;
+ QJniEnvironment env;
bool result = false;
if (hub) {
qCDebug(QT_BT_ANDROID) << "Read descriptor with handle"
<< descriptorHandle << service->uuid;
- result = hub->javaObject().callMethod<jboolean>("readDescriptor",
- "(I)Z", descriptorHandle);
- }
-
- if (env->ExceptionOccurred()) {
- env->ExceptionDescribe();
- env->ExceptionClear();
- result = false;
+ result = hub->javaObject().callMethod<jboolean>("readDescriptor", descriptorHandle);
}
if (!result)
@@ -411,6 +358,27 @@ void QLowEnergyControllerPrivateAndroid::connectionUpdated(
centralConnectionUpdated(newState, errorCode);
}
+void QLowEnergyControllerPrivateAndroid::mtuChanged(int mtu)
+{
+ Q_Q(QLowEnergyController);
+ qCDebug(QT_BT_ANDROID) << "MTU updated:"
+ << "mtu:" << mtu;
+ emit q->mtuChanged(mtu);
+}
+
+void QLowEnergyControllerPrivateAndroid::remoteRssiRead(int rssi, bool success)
+{
+ Q_Q(QLowEnergyController);
+ if (success) {
+ // BT Core v5.3, 7.5.4, Vol 4, Part E
+ // The LE RSSI can take values -127..127 => narrowing to qint16 is safe
+ emit q->rssiRead(rssi);
+ } else {
+ qCDebug(QT_BT_ANDROID) << "Reading remote RSSI failed";
+ setError(QLowEnergyController::RssiReadError);
+ }
+}
+
// called if server/peripheral
void QLowEnergyControllerPrivateAndroid::peripheralConnectionUpdated(
QLowEnergyController::ControllerState newState,
@@ -430,19 +398,20 @@ void QLowEnergyControllerPrivateAndroid::peripheralConnectionUpdated(
if (newState == QLowEnergyController::UnconnectedState)
stopAdvertising();
+ // The remote name and address may have changed
+ if (hub) {
+ remoteDevice = QBluetoothAddress(
+ hub->javaObject().callMethod<jstring>("remoteAddress").toString());
+ remoteName = hub->javaObject().callMethod<jstring>("remoteName").toString();
+ }
Q_Q(QLowEnergyController);
+ // Emit (dis)connected if the connection state changes
if (oldState == QLowEnergyController::ConnectedState
&& newState != QLowEnergyController::ConnectedState) {
- remoteDevice.clear();
- remoteName.clear();
emit q->disconnected();
} else if (newState == QLowEnergyController::ConnectedState
&& oldState != QLowEnergyController::ConnectedState) {
- if (hub) {
- remoteDevice = QBluetoothAddress(hub->javaObject().callObjectMethod<jstring>("remoteAddress").toString());
- remoteName = hub->javaObject().callObjectMethod<jstring>("remoteName").toString();
- }
emit q->connected();
}
}
@@ -500,7 +469,7 @@ void QLowEnergyControllerPrivateAndroid::servicesDiscovered(
if (errorCode == QLowEnergyController::NoError) {
//Android delivers all services in one go
- const QStringList list = foundServices.split(QStringLiteral(" "), QString::SkipEmptyParts);
+ const QStringList list = foundServices.split(QChar::Space, Qt::SkipEmptyParts);
for (const QString &entry : list) {
const QBluetoothUuid service(entry);
if (service.isNull())
@@ -541,15 +510,12 @@ void QLowEnergyControllerPrivateAndroid::serviceDetailsDiscoveryFinished(
pointer->endHandle = endHandle;
if (hub && hub->javaObject().isValid()) {
- QAndroidJniObject uuid = QAndroidJniObject::fromString(serviceUuid);
- QAndroidJniObject javaIncludes = hub->javaObject().callObjectMethod(
- "includedServices",
- "(Ljava/lang/String;)Ljava/lang/String;",
- uuid.object<jstring>());
+ QJniObject uuid = QJniObject::fromString(serviceUuid);
+ QJniObject javaIncludes = hub->javaObject().callMethod<jstring>(
+ "includedServices", uuid.object<jstring>());
if (javaIncludes.isValid()) {
const QStringList list = javaIncludes.toString()
- .split(QStringLiteral(" "),
- QString::SkipEmptyParts);
+ .split(QChar::Space, Qt::SkipEmptyParts);
for (const QString &entry : list) {
const QBluetoothUuid service(entry);
if (service.isNull())
@@ -569,7 +535,7 @@ void QLowEnergyControllerPrivateAndroid::serviceDetailsDiscoveryFinished(
qCDebug(QT_BT_ANDROID) << "Service" << serviceUuid << "discovered (start:"
<< startHandle << "end:" << endHandle << ")" << pointer.data();
- pointer->setState(QLowEnergyService::ServiceDiscovered);
+ pointer->setState(QLowEnergyService::RemoteServiceDiscovered);
}
void QLowEnergyControllerPrivateAndroid::characteristicRead(
@@ -593,7 +559,7 @@ void QLowEnergyControllerPrivateAndroid::characteristicRead(
//value handle always one larger than characteristics value handle
charDetails.valueHandle = charHandle + 1;
- if (service->state == QLowEnergyService::ServiceDiscovered) {
+ if (service->state == QLowEnergyService::RemoteServiceDiscovered) {
QLowEnergyCharacteristic characteristic = characteristicForHandle(charHandle);
if (!characteristic.isValid()) {
qCWarning(QT_BT_ANDROID) << "characteristicRead: Cannot find characteristic";
@@ -634,7 +600,7 @@ void QLowEnergyControllerPrivateAndroid::descriptorRead(
if (!entryUpdated) {
qCWarning(QT_BT_ANDROID) << "Cannot find/update descriptor"
<< descUuid << charUuid << serviceUuid;
- } else if (service->state == QLowEnergyService::ServiceDiscovered){
+ } else if (service->state == QLowEnergyService::RemoteServiceDiscovered){
QLowEnergyDescriptor descriptor = descriptorForHandle(descHandle);
if (!descriptor.isValid()) {
qCWarning(QT_BT_ANDROID) << "descriptorRead: Cannot find descriptor";
@@ -701,22 +667,22 @@ void QLowEnergyControllerPrivateAndroid::descriptorWritten(
}
void QLowEnergyControllerPrivateAndroid::serverDescriptorWritten(
- const QAndroidJniObject &jniDesc, const QByteArray &newValue)
+ const QJniObject &jniDesc, const QByteArray &newValue)
{
qCDebug(QT_BT_ANDROID) << "Server descriptor change notification" << newValue.toHex();
// retrieve service, char and desc uuids
- QAndroidJniObject jniChar = jniDesc.callObjectMethod(
- "getCharacteristic", "()Landroid/bluetooth/BluetoothGattCharacteristic;");
+ const QJniObject jniChar = jniDesc.callMethod<QtJniTypes::BluetoothGattCharacteristic>(
+ "getCharacteristic");
if (!jniChar.isValid())
return;
- QAndroidJniObject jniService = jniChar.callObjectMethod(
- "getService", "()Landroid/bluetooth/BluetoothGattService;");
+ const QJniObject jniService =
+ jniChar.callMethod<QtJniTypes::BluetoothGattService>("getService");
if (!jniService.isValid())
return;
- QAndroidJniObject jniUuid = jniService.callObjectMethod("getUuid", "()Ljava/util/UUID;");
+ QJniObject jniUuid = jniService.callMethod<QtJniTypes::UUID>("getUuid");
const QBluetoothUuid serviceUuid(jniUuid.toString());
if (serviceUuid.isNull())
return;
@@ -725,12 +691,12 @@ void QLowEnergyControllerPrivateAndroid::serverDescriptorWritten(
if (!localServices.contains(serviceUuid))
return;
- jniUuid = jniChar.callObjectMethod("getUuid", "()Ljava/util/UUID;");
+ jniUuid = jniChar.callMethod<QtJniTypes::UUID>("getUuid");
const QBluetoothUuid characteristicUuid(jniUuid.toString());
if (characteristicUuid.isNull())
return;
- jniUuid = jniDesc.callObjectMethod("getUuid", "()Ljava/util/UUID;");
+ jniUuid = jniDesc.callMethod<QtJniTypes::UUID>("getUuid");
const QBluetoothUuid descriptorUuid(jniUuid.toString());
if (descriptorUuid.isNull())
return;
@@ -774,7 +740,7 @@ void QLowEnergyControllerPrivateAndroid::characteristicChanged(
return;
qCDebug(QT_BT_ANDROID) << "Characteristic change notification" << service->uuid
- << charHandle << data.toHex();
+ << charHandle << data.toHex() << "length:" << data.size();
QLowEnergyCharacteristic characteristic = characteristicForHandle(charHandle);
if (!characteristic.isValid()) {
@@ -791,17 +757,18 @@ void QLowEnergyControllerPrivateAndroid::characteristicChanged(
}
void QLowEnergyControllerPrivateAndroid::serverCharacteristicChanged(
- const QAndroidJniObject &characteristic, const QByteArray &newValue)
+ const QJniObject &characteristic, const QByteArray &newValue)
{
- qCDebug(QT_BT_ANDROID) << "Server characteristic change notification" << newValue.toHex();
+ qCDebug(QT_BT_ANDROID) << "Server characteristic change notification"
+ << newValue.toHex() << "length:" << newValue.size();
// match characteristic to servicePrivate
- QAndroidJniObject service = characteristic.callObjectMethod(
- "getService", "()Landroid/bluetooth/BluetoothGattService;");
+ QJniObject service = characteristic.callMethod<QtJniTypes::BluetoothGattService>(
+ "getService");
if (!service.isValid())
return;
- QAndroidJniObject jniUuid = service.callObjectMethod("getUuid", "()Ljava/util/UUID;");
+ QJniObject jniUuid = service.callMethod<QtJniTypes::UUID>("getUuid");
QBluetoothUuid serviceUuid(jniUuid.toString());
if (serviceUuid.isNull())
return;
@@ -812,7 +779,7 @@ void QLowEnergyControllerPrivateAndroid::serverCharacteristicChanged(
auto servicePrivate = localServices.value(serviceUuid);
- jniUuid = characteristic.callObjectMethod("getUuid", "()Ljava/util/UUID;");
+ jniUuid = characteristic.callMethod<QtJniTypes::UUID>("getUuid");
QBluetoothUuid characteristicUuid(jniUuid.toString());
if (characteristicUuid.isNull())
return;
@@ -879,7 +846,7 @@ void QLowEnergyControllerPrivateAndroid::advertisementError(int errorCode)
}
error = QLowEnergyController::AdvertisingError;
- emit q->error(error);
+ emit q->errorOccurred(error);
// not relevant states in peripheral mode
Q_ASSERT(state != QLowEnergyController::DiscoveredState);
@@ -903,51 +870,47 @@ void QLowEnergyControllerPrivateAndroid::advertisementError(int errorCode)
}
}
-static QAndroidJniObject javaParcelUuidfromQtUuid(const QBluetoothUuid &uuid)
+static QJniObject javaParcelUuidfromQtUuid(const QBluetoothUuid &uuid)
{
QString output = uuid.toString();
// cut off leading and trailing brackets
output = output.mid(1, output.size()-2);
- QAndroidJniObject javaString = QAndroidJniObject::fromString(output);
- QAndroidJniObject parcelUuid = QAndroidJniObject::callStaticObjectMethod(
- "android/os/ParcelUuid", "fromString",
- "(Ljava/lang/String;)Landroid/os/ParcelUuid;", javaString.object());
+ QJniObject javaString = QJniObject::fromString(output);
+ QJniObject parcelUuid = QJniObject::callStaticMethod<QtJniTypes::ParcelUuid>(
+ QtJniTypes::Traits<QtJniTypes::ParcelUuid>::className(), "fromString",
+ javaString.object<jstring>());
return parcelUuid;
}
-static QAndroidJniObject createJavaAdvertiseData(const QLowEnergyAdvertisingData &data)
+static QJniObject createJavaAdvertiseData(const QLowEnergyAdvertisingData &data)
{
- QAndroidJniObject builder = QAndroidJniObject("android/bluetooth/le/AdvertiseData$Builder");
+ QJniObject builder = QJniObject::construct<QtJniTypes::AdvertiseDataBuilder>();
// device name cannot be set but there is choice to show it or not
- builder = builder.callObjectMethod("setIncludeDeviceName", "(Z)Landroid/bluetooth/le/AdvertiseData$Builder;",
- !data.localName().isEmpty());
- builder = builder.callObjectMethod("setIncludeTxPowerLevel", "(Z)Landroid/bluetooth/le/AdvertiseData$Builder;",
- data.includePowerLevel());
- for (const auto service: data.services())
- {
- builder = builder.callObjectMethod("addServiceUuid",
- "(Landroid/os/ParcelUuid;)Landroid/bluetooth/le/AdvertiseData$Builder;",
- javaParcelUuidfromQtUuid(service).object());
+ builder = builder.callMethod<QtJniTypes::AdvertiseDataBuilder>(
+ "setIncludeDeviceName", !data.localName().isEmpty());
+ builder = builder.callMethod<QtJniTypes::AdvertiseDataBuilder>(
+ "setIncludeTxPowerLevel", data.includePowerLevel());
+ const auto services = data.services();
+ for (const auto &service : services) {
+ builder = builder.callMethod<QtJniTypes::AdvertiseDataBuilder>("addServiceUuid",
+ javaParcelUuidfromQtUuid(service).object<QtJniTypes::ParcelUuid>());
}
if (!data.manufacturerData().isEmpty()) {
- QAndroidJniEnvironment env;
+ QJniEnvironment env;
const qint32 nativeSize = data.manufacturerData().size();
jbyteArray nativeData = env->NewByteArray(nativeSize);
env->SetByteArrayRegion(nativeData, 0, nativeSize,
reinterpret_cast<const jbyte*>(data.manufacturerData().constData()));
- builder = builder.callObjectMethod("addManufacturerData",
- "(I[B)Landroid/bluetooth/le/AdvertiseData$Builder;",
- data.manufacturerId(), nativeData);
+ builder = builder.callMethod<QtJniTypes::AdvertiseDataBuilder>(
+ "addManufacturerData", jint(data.manufacturerId()), nativeData);
env->DeleteLocalRef(nativeData);
- if (env->ExceptionCheck()) {
+ if (!builder.isValid()) {
qCWarning(QT_BT_ANDROID) << "Cannot set manufacturer id/data";
- env->ExceptionDescribe();
- env->ExceptionClear();
}
}
@@ -955,7 +918,7 @@ static QAndroidJniObject createJavaAdvertiseData(const QLowEnergyAdvertisingData
-> Qt assumes rawData() is a global field
-> Android pairs rawData() per service uuid
if (!data.rawData().isEmpty()) {
- QAndroidJniEnvironment env;
+ QJniEnvironment env;
qint32 nativeSize = data.rawData().size();
jbyteArray nativeData = env->NewByteArray(nativeSize);
env->SetByteArrayRegion(nativeData, 0, nativeSize,
@@ -965,21 +928,18 @@ static QAndroidJniObject createJavaAdvertiseData(const QLowEnergyAdvertisingData
data.rawData().object(), nativeData);
env->DeleteLocalRef(nativeData);
- if (env->ExceptionCheck()) {
+ if (env.checkAndClearExceptions()) {
qCWarning(QT_BT_ANDROID) << "Cannot set advertisement raw data";
- env->ExceptionDescribe();
- env->ExceptionClear();
}
}*/
- QAndroidJniObject javaAdvertiseData = builder.callObjectMethod("build",
- "()Landroid/bluetooth/le/AdvertiseData;");
+ QJniObject javaAdvertiseData = builder.callMethod<QtJniTypes::AdvertiseData>("build");
return javaAdvertiseData;
}
-static QAndroidJniObject createJavaAdvertiseSettings(const QLowEnergyAdvertisingParameters &params)
+static QJniObject createJavaAdvertiseSettings(const QLowEnergyAdvertisingParameters &params)
{
- QAndroidJniObject builder = QAndroidJniObject("android/bluetooth/le/AdvertiseSettings$Builder");
+ QJniObject builder = QJniObject::construct<QtJniTypes::AdvertiseSettingsBuilder>();
bool connectable = false;
switch (params.mode())
@@ -993,15 +953,14 @@ static QAndroidJniObject createJavaAdvertiseSettings(const QLowEnergyAdvertising
break;
// intentionally no default case
}
- builder = builder.callObjectMethod("setConnectable", "(Z)Landroid/bluetooth/le/AdvertiseSettings$Builder;",
- connectable);
+ builder = builder.callMethod<QtJniTypes::AdvertiseSettingsBuilder>(
+ "setConnectable", connectable);
/* TODO No Android API for further QLowEnergyAdvertisingParameters options
* Android TxPowerLevel, AdvertiseMode and Timeout not mappable to Qt
*/
- QAndroidJniObject javaAdvertiseSettings = builder.callObjectMethod("build",
- "()Landroid/bluetooth/le/AdvertiseSettings;");
+ QJniObject javaAdvertiseSettings = builder.callMethod<QtJniTypes::AdvertiseSettings>("build");
return javaAdvertiseSettings;
}
@@ -1012,7 +971,14 @@ void QLowEnergyControllerPrivateAndroid::startAdvertising(const QLowEnergyAdvert
{
setState(QLowEnergyController::AdvertisingState);
- if (!hub->javaObject().isValid()) {
+ if (!ensureAndroidPermission(QBluetoothPermission::Access | QBluetoothPermission::Advertise)) {
+ qCWarning(QT_BT_ANDROID) << "startAdvertising() failed due to missing permissions";
+ setError(QLowEnergyController::MissingPermissionsError);
+ setState(QLowEnergyController::UnconnectedState);
+ return;
+ }
+
+ if (!hub || !hub->javaObject().isValid()) {
qCWarning(QT_BT_ANDROID) << "Cannot initiate QtBluetoothLEServer";
setError(QLowEnergyController::AdvertisingError);
setState(QLowEnergyController::UnconnectedState);
@@ -1020,13 +986,14 @@ void QLowEnergyControllerPrivateAndroid::startAdvertising(const QLowEnergyAdvert
}
// Pass on advertisingData, scanResponse & AdvertiseSettings
- QAndroidJniObject jAdvertiseData = createJavaAdvertiseData(advertisingData);
- QAndroidJniObject jScanResponse = createJavaAdvertiseData(scanResponseData);
- QAndroidJniObject jAdvertiseSettings = createJavaAdvertiseSettings(params);
+ QJniObject jAdvertiseData = createJavaAdvertiseData(advertisingData);
+ QJniObject jScanResponse = createJavaAdvertiseData(scanResponseData);
+ QJniObject jAdvertiseSettings = createJavaAdvertiseSettings(params);
const bool result = hub->javaObject().callMethod<jboolean>("startAdvertising",
- "(Landroid/bluetooth/le/AdvertiseData;Landroid/bluetooth/le/AdvertiseData;Landroid/bluetooth/le/AdvertiseSettings;)Z",
- jAdvertiseData.object(), jScanResponse.object(), jAdvertiseSettings.object());
+ jAdvertiseData.object<QtJniTypes::AdvertiseData>(),
+ jScanResponse.object<QtJniTypes::AdvertiseData>(),
+ jAdvertiseSettings.object<QtJniTypes::AdvertiseSettings>());
if (!result) {
setError(QLowEnergyController::AdvertisingError);
setState(QLowEnergyController::UnconnectedState);
@@ -1041,7 +1008,6 @@ void QLowEnergyControllerPrivateAndroid::stopAdvertising()
void QLowEnergyControllerPrivateAndroid::requestConnectionUpdate(const QLowEnergyConnectionParameters &params)
{
- // Possible since Android v21
// Android does not permit specification of specific latency or min/max
// connection intervals (see BluetoothGatt.requestConnectionPriority()
// In fact, each device manufacturer is permitted to change those values via a config
@@ -1057,7 +1023,7 @@ void QLowEnergyControllerPrivateAndroid::requestConnectionUpdate(const QLowEnerg
}
const bool result = hub->javaObject().callMethod<jboolean>("requestConnectionUpdatePriority",
- "(D)Z", params.minimumInterval());
+ params.minimumInterval());
if (!result)
qCWarning(QT_BT_ANDROID) << "Cannot set connection update priority";
}
@@ -1070,56 +1036,60 @@ static int setupCharPermissions(const QLowEnergyCharacteristicData &charData)
int permission = 0;
if (charData.properties() & QLowEnergyCharacteristic::Read) {
if (int(charData.readConstraints()) == 0 // nothing is equivalent to simple read
- || (charData.readConstraints() & QBluetooth::AttAuthorizationRequired)) {
- permission |= QAndroidJniObject::getStaticField<jint>(
- "android/bluetooth/BluetoothGattCharacteristic",
- "PERMISSION_READ");
+ || (charData.readConstraints()
+ & QBluetooth::AttAccessConstraint::AttAuthorizationRequired)) {
+ permission |= QJniObject::getStaticField<jint>(
+ QtJniTypes::Traits<QtJniTypes::BluetoothGattCharacteristic>::className(),
+ "PERMISSION_READ");
}
- if (charData.readConstraints() & QBluetooth::AttAuthenticationRequired) {
- permission |= QAndroidJniObject::getStaticField<jint>(
- "android/bluetooth/BluetoothGattCharacteristic",
- "PERMISSION_READ_ENCRYPTED");
+ if (charData.readConstraints()
+ & QBluetooth::AttAccessConstraint::AttAuthenticationRequired) {
+ permission |= QJniObject::getStaticField<jint>(
+ QtJniTypes::Traits<QtJniTypes::BluetoothGattCharacteristic>::className(),
+ "PERMISSION_READ_ENCRYPTED");
}
- if (charData.readConstraints() & QBluetooth::AttEncryptionRequired) {
- permission |= QAndroidJniObject::getStaticField<jint>(
- "android/bluetooth/BluetoothGattCharacteristic",
- "PERMISSION_READ_ENCRYPTED_MITM");
+ if (charData.readConstraints() & QBluetooth::AttAccessConstraint::AttEncryptionRequired) {
+ permission |= QJniObject::getStaticField<jint>(
+ QtJniTypes::Traits<QtJniTypes::BluetoothGattCharacteristic>::className(),
+ "PERMISSION_READ_ENCRYPTED_MITM");
}
}
if (charData.properties() &
(QLowEnergyCharacteristic::Write|QLowEnergyCharacteristic::WriteNoResponse) ) {
if (int(charData.writeConstraints()) == 0 // no flag is equivalent ti simple write
- || (charData.writeConstraints() & QBluetooth::AttAuthorizationRequired)) {
- permission |= QAndroidJniObject::getStaticField<jint>(
- "android/bluetooth/BluetoothGattCharacteristic",
- "PERMISSION_WRITE");
+ || (charData.writeConstraints()
+ & QBluetooth::AttAccessConstraint::AttAuthorizationRequired)) {
+ permission |= QJniObject::getStaticField<jint>(
+ QtJniTypes::Traits<QtJniTypes::BluetoothGattCharacteristic>::className(),
+ "PERMISSION_WRITE");
}
- if (charData.writeConstraints() & QBluetooth::AttAuthenticationRequired) {
- permission |= QAndroidJniObject::getStaticField<jint>(
- "android/bluetooth/BluetoothGattCharacteristic",
- "PERMISSION_WRITE_ENCRYPTED");
+ if (charData.writeConstraints()
+ & QBluetooth::AttAccessConstraint::AttAuthenticationRequired) {
+ permission |= QJniObject::getStaticField<jint>(
+ QtJniTypes::Traits<QtJniTypes::BluetoothGattCharacteristic>::className(),
+ "PERMISSION_WRITE_ENCRYPTED");
}
- if (charData.writeConstraints() & QBluetooth::AttEncryptionRequired) {
- permission |= QAndroidJniObject::getStaticField<jint>(
- "android/bluetooth/BluetoothGattCharacteristic",
- "PERMISSION_WRITE_ENCRYPTED_MITM");
+ if (charData.writeConstraints() & QBluetooth::AttAccessConstraint::AttEncryptionRequired) {
+ permission |= QJniObject::getStaticField<jint>(
+ QtJniTypes::Traits<QtJniTypes::BluetoothGattCharacteristic>::className(),
+ "PERMISSION_WRITE_ENCRYPTED_MITM");
}
}
if (charData.properties() & QLowEnergyCharacteristic::WriteSigned) {
- if (charData.writeConstraints() & QBluetooth::AttEncryptionRequired) {
- permission |= QAndroidJniObject::getStaticField<jint>(
- "android/bluetooth/BluetoothGattCharacteristic",
- "PERMISSION_WRITE_SIGNED_MITM");
+ if (charData.writeConstraints() & QBluetooth::AttAccessConstraint::AttEncryptionRequired) {
+ permission |= QJniObject::getStaticField<jint>(
+ QtJniTypes::Traits<QtJniTypes::BluetoothGattCharacteristic>::className(),
+ "PERMISSION_WRITE_SIGNED_MITM");
} else {
- permission |= QAndroidJniObject::getStaticField<jint>(
- "android/bluetooth/BluetoothGattCharacteristic",
- "PERMISSION_WRITE_SIGNED");
+ permission |= QJniObject::getStaticField<jint>(
+ QtJniTypes::Traits<QtJniTypes::BluetoothGattCharacteristic>::className(),
+ "PERMISSION_WRITE_SIGNED");
}
}
@@ -1135,43 +1105,47 @@ static int setupDescPermissions(const QLowEnergyDescriptorData &descData)
if (descData.isReadable()) {
if (int(descData.readConstraints()) == 0 // empty is equivalent to simple read
- || (descData.readConstraints() & QBluetooth::AttAuthorizationRequired)) {
- permissions |= QAndroidJniObject::getStaticField<jint>(
- "android/bluetooth/BluetoothGattDescriptor",
- "PERMISSION_READ");
+ || (descData.readConstraints()
+ & QBluetooth::AttAccessConstraint::AttAuthorizationRequired)) {
+ permissions |= QJniObject::getStaticField<jint>(
+ QtJniTypes::Traits<QtJniTypes::BluetoothGattDescriptor>::className(),
+ "PERMISSION_READ");
}
- if (descData.readConstraints() & QBluetooth::AttAuthenticationRequired) {
- permissions |= QAndroidJniObject::getStaticField<jint>(
- "android/bluetooth/BluetoothGattDescriptor",
- "PERMISSION_READ_ENCRYPTED");
+ if (descData.readConstraints()
+ & QBluetooth::AttAccessConstraint::AttAuthenticationRequired) {
+ permissions |= QJniObject::getStaticField<jint>(
+ QtJniTypes::Traits<QtJniTypes::BluetoothGattDescriptor>::className(),
+ "PERMISSION_READ_ENCRYPTED");
}
- if (descData.readConstraints() & QBluetooth::AttEncryptionRequired) {
- permissions |= QAndroidJniObject::getStaticField<jint>(
- "android/bluetooth/BluetoothGattDescriptor",
- "PERMISSION_READ_ENCRYPTED_MITM");
+ if (descData.readConstraints() & QBluetooth::AttAccessConstraint::AttEncryptionRequired) {
+ permissions |= QJniObject::getStaticField<jint>(
+ QtJniTypes::Traits<QtJniTypes::BluetoothGattDescriptor>::className(),
+ "PERMISSION_READ_ENCRYPTED_MITM");
}
}
if (descData.isWritable()) {
if (int(descData.readConstraints()) == 0 // empty is equivalent to simple read
- || (descData.readConstraints() & QBluetooth::AttAuthorizationRequired)) {
- permissions |= QAndroidJniObject::getStaticField<jint>(
- "android/bluetooth/BluetoothGattDescriptor",
- "PERMISSION_WRITE");
+ || (descData.readConstraints()
+ & QBluetooth::AttAccessConstraint::AttAuthorizationRequired)) {
+ permissions |= QJniObject::getStaticField<jint>(
+ QtJniTypes::Traits<QtJniTypes::BluetoothGattDescriptor>::className(),
+ "PERMISSION_WRITE");
}
- if (descData.readConstraints() & QBluetooth::AttAuthenticationRequired) {
- permissions |= QAndroidJniObject::getStaticField<jint>(
- "android/bluetooth/BluetoothGattDescriptor",
- "PERMISSION_WRITE_ENCRYPTED");
+ if (descData.readConstraints()
+ & QBluetooth::AttAccessConstraint::AttAuthenticationRequired) {
+ permissions |= QJniObject::getStaticField<jint>(
+ QtJniTypes::Traits<QtJniTypes::BluetoothGattDescriptor>::className(),
+ "PERMISSION_WRITE_ENCRYPTED");
}
- if (descData.readConstraints() & QBluetooth::AttEncryptionRequired) {
- permissions |= QAndroidJniObject::getStaticField<jint>(
- "android/bluetooth/BluetoothGattDescriptor",
- "PERMISSION_WRITE_ENCRYPTED_MITM");
+ if (descData.readConstraints() & QBluetooth::AttAccessConstraint::AttEncryptionRequired) {
+ permissions |= QJniObject::getStaticField<jint>(
+ QtJniTypes::Traits<QtJniTypes::BluetoothGattDescriptor>::className(),
+ "PERMISSION_WRITE_ENCRYPTED_MITM");
}
}
@@ -1186,23 +1160,23 @@ void QLowEnergyControllerPrivateAndroid::addToGenericAttributeList(const QLowEne
return;
// create BluetoothGattService object
- jint sType = QAndroidJniObject::getStaticField<jint>(
- "android/bluetooth/BluetoothGattService", "SERVICE_TYPE_PRIMARY");
+ jint sType = QJniObject::getStaticField<jint>(
+ QtJniTypes::Traits<QtJniTypes::BluetoothGattService>::className(),
+ "SERVICE_TYPE_PRIMARY");
if (serviceData.type() == QLowEnergyServiceData::ServiceTypeSecondary)
- sType = QAndroidJniObject::getStaticField<jint>(
- "android/bluetooth/BluetoothGattService", "SERVICE_TYPE_SECONDARY");
+ sType = QJniObject::getStaticField<jint>(
+ QtJniTypes::Traits<QtJniTypes::BluetoothGattService>::className(),
+ "SERVICE_TYPE_SECONDARY");
- service->androidService = QAndroidJniObject("android/bluetooth/BluetoothGattService",
- "(Ljava/util/UUID;I)V",
- javaUuidfromQtUuid(service->uuid).object(), sType);
+ service->androidService = QJniObject::construct<QtJniTypes::BluetoothGattService>(
+ javaUuidfromQtUuid(service->uuid).object<QtJniTypes::UUID>(), sType);
// add included services, which must have been added earlier already
const QList<QLowEnergyService*> includedServices = serviceData.includedServices();
for (const auto includedServiceEntry: includedServices) {
//TODO test this end-to-end
- const jboolean result = service->androidService.callMethod<jboolean>(
- "addService", "(Landroid/bluetooth/BluetoothGattService;)Z",
- includedServiceEntry->d_ptr->androidService.object());
+ const jboolean result = service->androidService.callMethod<jboolean>("addService",
+ includedServiceEntry->d_ptr->androidService.object<QtJniTypes::BluetoothGattService>());
if (!result)
qWarning(QT_BT_ANDROID) << "Cannot add included service " << includedServiceEntry->serviceUuid()
<< "to current service" << service->uuid;
@@ -1211,31 +1185,51 @@ void QLowEnergyControllerPrivateAndroid::addToGenericAttributeList(const QLowEne
// add characteristics
const QList<QLowEnergyCharacteristicData> serviceCharsData = serviceData.characteristics();
for (const auto &charData: serviceCharsData) {
- QAndroidJniObject javaChar = QAndroidJniObject("android/bluetooth/BluetoothGattCharacteristic",
- "(Ljava/util/UUID;II)V",
- javaUuidfromQtUuid(charData.uuid()).object(),
- int(charData.properties()),
- setupCharPermissions(charData));
- QAndroidJniEnvironment env;
+ // User may have set minimum and/or maximum characteristic value size. Enforce
+ // them here. If the user has not defined these limits, the default values 0..INT_MAX
+ // do not limit anything. If the sizes are violated here (ie. when adding the
+ // characteristics), regard it as a programming error.
+ if (charData.value().size() < charData.minimumValueLength() ||
+ charData.value().size() > charData.maximumValueLength()) {
+ qWarning() << "Warning: Ignoring characteristic" << charData.uuid()
+ << "with invalid length:" << charData.value().size()
+ << "(minimum:" << charData.minimumValueLength()
+ << "maximum:" << charData.maximumValueLength() << ").";
+ continue;
+ }
+
+ // Issue a warning if the attribute length exceeds the bluetooth standard limit.
+ if (charData.value().size() > BTLE_MAX_ATTRIBUTE_VALUE_SIZE) {
+ qCWarning(QT_BT_ANDROID) << "Warning: characteristic" << charData.uuid() << "size"
+ << "exceeds the standard: " << BTLE_MAX_ATTRIBUTE_VALUE_SIZE
+ << ", value size:" << charData.value().size();
+ }
+
+ QJniObject javaChar = QJniObject::construct<QtJniTypes::QtBtGattCharacteristic>(
+ javaUuidfromQtUuid(charData.uuid()).object<QtJniTypes::UUID>(),
+ int(charData.properties()),
+ setupCharPermissions(charData),
+ charData.minimumValueLength(),
+ charData.maximumValueLength());
+
+ QJniEnvironment env;
jbyteArray jb = env->NewByteArray(charData.value().size());
env->SetByteArrayRegion(jb, 0, charData.value().size(), (jbyte*)charData.value().data());
- jboolean success = javaChar.callMethod<jboolean>("setValue", "([B)Z", jb);
+ jboolean success = javaChar.callMethod<jboolean>("setLocalValue", jb);
if (!success)
qCWarning(QT_BT_ANDROID) << "Cannot setup initial characteristic value for " << charData.uuid();
-
env->DeleteLocalRef(jb);
const QList<QLowEnergyDescriptorData> descriptorList = charData.descriptors();
for (const auto &descData: descriptorList) {
- QAndroidJniObject javaDesc = QAndroidJniObject("android/bluetooth/BluetoothGattDescriptor",
- "(Ljava/util/UUID;I)V",
- javaUuidfromQtUuid(descData.uuid()).object(),
- setupDescPermissions(descData));
+ QJniObject javaDesc = QJniObject::construct<QtJniTypes::QtBtGattDescriptor>(
+ javaUuidfromQtUuid(descData.uuid()).object<QtJniTypes::UUID>(),
+ setupDescPermissions(descData));
jb = env->NewByteArray(descData.value().size());
env->SetByteArrayRegion(jb, 0, descData.value().size(), (jbyte*)descData.value().data());
- success = javaDesc.callMethod<jboolean>("setValue", "([B)Z", jb);
+ success = javaDesc.callMethod<jboolean>("setLocalValue", jb);
if (!success) {
qCWarning(QT_BT_ANDROID) << "Cannot setup initial descriptor value for "
<< descData.uuid() << "(char" << charData.uuid()
@@ -1246,8 +1240,7 @@ void QLowEnergyControllerPrivateAndroid::addToGenericAttributeList(const QLowEne
success = javaChar.callMethod<jboolean>("addDescriptor",
- "(Landroid/bluetooth/BluetoothGattDescriptor;)Z",
- javaDesc.object());
+ javaDesc.object<QtJniTypes::BluetoothGattDescriptor>());
if (!success) {
qCWarning(QT_BT_ANDROID) << "Cannot add descriptor" << descData.uuid()
<< "to service" << service->uuid << "(char:"
@@ -1256,8 +1249,8 @@ void QLowEnergyControllerPrivateAndroid::addToGenericAttributeList(const QLowEne
}
success = service->androidService.callMethod<jboolean>(
- "addCharacteristic",
- "(Landroid/bluetooth/BluetoothGattCharacteristic;)Z", javaChar.object());
+ "addCharacteristic",
+ javaChar.object<QtJniTypes::BluetoothGattCharacteristic>());
if (!success) {
qCWarning(QT_BT_ANDROID) << "Cannot add characteristic" << charData.uuid()
<< "to service" << service->uuid;
@@ -1265,8 +1258,28 @@ void QLowEnergyControllerPrivateAndroid::addToGenericAttributeList(const QLowEne
}
hub->javaObject().callMethod<void>("addService",
- "(Landroid/bluetooth/BluetoothGattService;)V",
- service->androidService.object());
+ service->androidService.object<QtJniTypes::BluetoothGattService>());
+}
+
+int QLowEnergyControllerPrivateAndroid::mtu() const
+{
+ if (!hub) {
+ qCWarning(QT_BT_ANDROID) << "could not determine MTU, hub is does not exist";
+ return -1;
+ } else {
+ int result = hub->javaObject().callMethod<int>("mtu");
+ qCDebug(QT_BT_ANDROID) << "MTU found to be" << result;
+ return result;
+ }
+}
+
+void QLowEnergyControllerPrivateAndroid::readRssi()
+{
+ if (!hub || !hub->javaObject().callMethod<jboolean>("readRemoteRssi")) {
+ qCWarning(QT_BT_ANDROID) << "request to read RSSI failed";
+ setError(QLowEnergyController::RssiReadError);
+ return;
+ }
}
QT_END_NAMESPACE
diff --git a/src/bluetooth/qlowenergycontroller_android_p.h b/src/bluetooth/qlowenergycontroller_android_p.h
index f05c63ca..6f1bbfaa 100644
--- a/src/bluetooth/qlowenergycontroller_android_p.h
+++ b/src/bluetooth/qlowenergycontroller_android_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QLOWENERGYCONTROLLERPRIVATEANDROID_P_H
#define QLOWENERGYCONTROLLERPRIVATEANDROID_P_H
@@ -54,13 +18,12 @@
#include <qglobal.h>
#include <QtCore/QQueue>
-#include <QtCore/QVector>
#include <QtBluetooth/qbluetooth.h>
#include <QtBluetooth/qlowenergycharacteristic.h>
#include "qlowenergycontroller.h"
#include "qlowenergycontrollerbase_p.h"
-#include <QtAndroidExtras/QAndroidJniObject>
+#include <QtCore/QJniObject>
#include "android/lowenergynotificationhub_p.h"
#include <functional>
@@ -74,8 +37,6 @@ class LowEnergyNotificationHub;
extern void registerQLowEnergyControllerMetaType();
-class QLeAdvertiser;
-
class QLowEnergyControllerPrivateAndroid final : public QLowEnergyControllerPrivate
{
Q_OBJECT
@@ -89,7 +50,8 @@ public:
void disconnectFromDevice() override;
void discoverServices() override;
- void discoverServiceDetails(const QBluetoothUuid &service) override;
+ void discoverServiceDetails(const QBluetoothUuid &service,
+ QLowEnergyService::DiscoveryMode mode) override;
void startAdvertising(const QLowEnergyAdvertisingParameters &params,
const QLowEnergyAdvertisingData &advertisingData,
@@ -117,6 +79,9 @@ public:
void addToGenericAttributeList(const QLowEnergyServiceData &service,
QLowEnergyHandle startHandle) override;
+ int mtu() const override;
+ void readRssi() override;
+
private:
LowEnergyNotificationHub *hub;
@@ -124,6 +89,8 @@ private:
private slots:
void connectionUpdated(QLowEnergyController::ControllerState newState,
QLowEnergyController::Error errorCode);
+ void mtuChanged(int mtu);
+ void remoteRssiRead(int rssi, bool success);
void servicesDiscovered(QLowEnergyController::Error errorCode,
const QString &foundServices);
void serviceDetailsDiscoveryFinished(const QString& serviceUuid,
@@ -137,9 +104,9 @@ private slots:
QLowEnergyService::ServiceError errorCode);
void descriptorWritten(int descHandle, const QByteArray &data,
QLowEnergyService::ServiceError errorCode);
- void serverDescriptorWritten(const QAndroidJniObject &jniDesc, const QByteArray &newValue);
+ void serverDescriptorWritten(const QJniObject &jniDesc, const QByteArray &newValue);
void characteristicChanged(int charHandle, const QByteArray &data);
- void serverCharacteristicChanged(const QAndroidJniObject &jniChar, const QByteArray &newValue);
+ void serverCharacteristicChanged(const QJniObject &jniChar, const QByteArray &newValue);
void serviceError(int attributeHandle, QLowEnergyService::ServiceError errorCode);
void advertisementError(int errorCode);
diff --git a/src/bluetooth/qlowenergycontroller_bluez.cpp b/src/bluetooth/qlowenergycontroller_bluez.cpp
index 13d70ef3..6f0c9858 100644
--- a/src/bluetooth/qlowenergycontroller_bluez.cpp
+++ b/src/bluetooth/qlowenergycontroller_bluez.cpp
@@ -1,48 +1,12 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Copyright (C) 2016 Javier S. Pedro <maemo@javispedro.com>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// Copyright (C) 2016 Javier S. Pedro <maemo@javispedro.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "lecmaccalculator_p.h"
#include "qlowenergycontroller_bluez_p.h"
#include "qbluetoothsocketbase_p.h"
#include "qbluetoothsocket_bluez_p.h"
-#include "qleadvertiser_p.h"
+#include "qleadvertiser_bluez_p.h"
#include "bluez/bluez_data_p.h"
#include "bluez/hcimanager_p.h"
#include "bluez/objectmanager_p.h"
@@ -50,11 +14,6 @@
#include "bluez/bluez5_helper_p.h"
#include "bluez/bluetoothmanagement_p.h"
-// Bluez 4
-#include "bluez/adapter_p.h"
-#include "bluez/device_p.h"
-#include "bluez/manager_p.h"
-
#include <QtCore/QFileInfo>
#include <QtCore/QLoggingCategory>
#include <QtCore/QSettings>
@@ -74,44 +33,14 @@
#include <sys/socket.h>
#include <unistd.h>
-#define ATT_DEFAULT_LE_MTU 23
-#define ATT_MAX_LE_MTU 0x200
+constexpr quint16 ATT_DEFAULT_LE_MTU = 23;
+constexpr quint16 ATT_MAX_LE_MTU = 0x200;
#define GATT_PRIMARY_SERVICE quint16(0x2800)
#define GATT_SECONDARY_SERVICE quint16(0x2801)
#define GATT_INCLUDED_SERVICE quint16(0x2802)
#define GATT_CHARACTERISTIC quint16(0x2803)
-// GATT commands
-#define ATT_OP_ERROR_RESPONSE 0x1
-#define ATT_OP_EXCHANGE_MTU_REQUEST 0x2 //send own mtu
-#define ATT_OP_EXCHANGE_MTU_RESPONSE 0x3 //receive server MTU
-#define ATT_OP_FIND_INFORMATION_REQUEST 0x4 //discover individual attribute info
-#define ATT_OP_FIND_INFORMATION_RESPONSE 0x5
-#define ATT_OP_FIND_BY_TYPE_VALUE_REQUEST 0x6
-#define ATT_OP_FIND_BY_TYPE_VALUE_RESPONSE 0x7
-#define ATT_OP_READ_BY_TYPE_REQUEST 0x8 //discover characteristics
-#define ATT_OP_READ_BY_TYPE_RESPONSE 0x9
-#define ATT_OP_READ_REQUEST 0xA //read characteristic & descriptor values
-#define ATT_OP_READ_RESPONSE 0xB
-#define ATT_OP_READ_BLOB_REQUEST 0xC //read values longer than MTU-1
-#define ATT_OP_READ_BLOB_RESPONSE 0xD
-#define ATT_OP_READ_MULTIPLE_REQUEST 0xE
-#define ATT_OP_READ_MULTIPLE_RESPONSE 0xF
-#define ATT_OP_READ_BY_GROUP_REQUEST 0x10 //discover services
-#define ATT_OP_READ_BY_GROUP_RESPONSE 0x11
-#define ATT_OP_WRITE_REQUEST 0x12 //write characteristic with response
-#define ATT_OP_WRITE_RESPONSE 0x13
-#define ATT_OP_PREPARE_WRITE_REQUEST 0x16 //write values longer than MTU-3 -> queueing
-#define ATT_OP_PREPARE_WRITE_RESPONSE 0x17
-#define ATT_OP_EXECUTE_WRITE_REQUEST 0x18 //write values longer than MTU-3 -> execute queue
-#define ATT_OP_EXECUTE_WRITE_RESPONSE 0x19
-#define ATT_OP_HANDLE_VAL_NOTIFICATION 0x1b //informs about value change
-#define ATT_OP_HANDLE_VAL_INDICATION 0x1d //informs about value change -> requires reply
-#define ATT_OP_HANDLE_VAL_CONFIRMATION 0x1e //answer for ATT_OP_HANDLE_VAL_INDICATION
-#define ATT_OP_WRITE_COMMAND 0x52 //write characteristic without response
-#define ATT_OP_SIGNED_WRITE_COMMAND 0xD2
-
//GATT command sizes in bytes
#define ERROR_RESPONSE_HEADER_SIZE 5
#define FIND_INFO_REQUEST_HEADER_SIZE 5
@@ -124,34 +53,6 @@
#define EXECUTE_WRITE_HEADER_SIZE 2
#define MTU_EXCHANGE_HEADER_SIZE 3
-// GATT error codes
-#define ATT_ERROR_INVALID_HANDLE 0x01
-#define ATT_ERROR_READ_NOT_PERM 0x02
-#define ATT_ERROR_WRITE_NOT_PERM 0x03
-#define ATT_ERROR_INVALID_PDU 0x04
-#define ATT_ERROR_INSUF_AUTHENTICATION 0x05
-#define ATT_ERROR_REQUEST_NOT_SUPPORTED 0x06
-#define ATT_ERROR_INVALID_OFFSET 0x07
-#define ATT_ERROR_INSUF_AUTHORIZATION 0x08
-#define ATT_ERROR_PREPARE_QUEUE_FULL 0x09
-#define ATT_ERROR_ATTRIBUTE_NOT_FOUND 0x0A
-#define ATT_ERROR_ATTRIBUTE_NOT_LONG 0x0B
-#define ATT_ERROR_INSUF_ENCR_KEY_SIZE 0x0C
-#define ATT_ERROR_INVAL_ATTR_VALUE_LEN 0x0D
-#define ATT_ERROR_UNLIKELY 0x0E
-#define ATT_ERROR_INSUF_ENCRYPTION 0x0F
-#define ATT_ERROR_UNSUPPRTED_GROUP_TYPE 0x10
-#define ATT_ERROR_INSUF_RESOURCES 0x11
-#define ATT_ERROR_APPLICATION_START 0x80
-//------------------------------------------
-// The error codes in this block are
-// implementation specific errors
-
-#define ATT_ERROR_REQUEST_STALLED 0x81
-
-//------------------------------------------
-#define ATT_ERROR_APPLICATION_END 0x9f
-
#define APPEND_VALUE true
#define NEW_VALUE false
@@ -163,81 +64,68 @@ using namespace QBluetooth;
const int maxPrepareQueueSize = 1024;
-static inline QBluetoothUuid convert_uuid128(const quint128 *p)
-{
- quint128 dst_hostOrder, dst_bigEndian;
-
- // Bluetooth LE data comes as little endian
- // uuids are constructed using high endian
- btoh128(p, &dst_hostOrder);
- hton128(&dst_hostOrder, &dst_bigEndian);
-
- // convert to Qt's own data type
- quint128 qtdst;
- memcpy(&qtdst, &dst_bigEndian, sizeof(quint128));
-
- return QBluetoothUuid(qtdst);
-}
-
static void dumpErrorInformation(const QByteArray &response)
{
const char *data = response.constData();
- if (response.size() != 5 || data[0] != ATT_OP_ERROR_RESPONSE) {
+ if (response.size() != 5
+ || (static_cast<QBluezConst::AttCommand>(data[0])
+ != QBluezConst::AttCommand::ATT_OP_ERROR_RESPONSE)) {
qCWarning(QT_BT_BLUEZ) << QLatin1String("Not a valid error response");
return;
}
- quint8 lastCommand = data[1];
+ QBluezConst::AttCommand lastCommand = static_cast<QBluezConst::AttCommand>(data[1]);
quint16 handle = bt_get_le16(&data[2]);
- quint8 errorCode = data[4];
+ QBluezConst::AttError errorCode = static_cast<QBluezConst::AttError>(data[4]);
QString errorString;
switch (errorCode) {
- case ATT_ERROR_INVALID_HANDLE:
+ case QBluezConst::AttError::ATT_ERROR_INVALID_HANDLE:
errorString = QStringLiteral("invalid handle"); break;
- case ATT_ERROR_READ_NOT_PERM:
+ case QBluezConst::AttError::ATT_ERROR_READ_NOT_PERM:
errorString = QStringLiteral("not readable attribute - permissions"); break;
- case ATT_ERROR_WRITE_NOT_PERM:
+ case QBluezConst::AttError::ATT_ERROR_WRITE_NOT_PERM:
errorString = QStringLiteral("not writable attribute - permissions"); break;
- case ATT_ERROR_INVALID_PDU:
+ case QBluezConst::AttError::ATT_ERROR_INVALID_PDU:
errorString = QStringLiteral("PDU invalid"); break;
- case ATT_ERROR_INSUF_AUTHENTICATION:
+ case QBluezConst::AttError::ATT_ERROR_INSUF_AUTHENTICATION:
errorString = QStringLiteral("needs authentication - permissions"); break;
- case ATT_ERROR_REQUEST_NOT_SUPPORTED:
+ case QBluezConst::AttError::ATT_ERROR_REQUEST_NOT_SUPPORTED:
errorString = QStringLiteral("server does not support request"); break;
- case ATT_ERROR_INVALID_OFFSET:
+ case QBluezConst::AttError::ATT_ERROR_INVALID_OFFSET:
errorString = QStringLiteral("offset past end of attribute"); break;
- case ATT_ERROR_INSUF_AUTHORIZATION:
+ case QBluezConst::AttError::ATT_ERROR_INSUF_AUTHORIZATION:
errorString = QStringLiteral("need authorization - permissions"); break;
- case ATT_ERROR_PREPARE_QUEUE_FULL:
+ case QBluezConst::AttError::ATT_ERROR_PREPARE_QUEUE_FULL:
errorString = QStringLiteral("run out of prepare queue space"); break;
- case ATT_ERROR_ATTRIBUTE_NOT_FOUND:
+ case QBluezConst::AttError::ATT_ERROR_ATTRIBUTE_NOT_FOUND:
errorString = QStringLiteral("no attribute in given range found"); break;
- case ATT_ERROR_ATTRIBUTE_NOT_LONG:
+ case QBluezConst::AttError::ATT_ERROR_ATTRIBUTE_NOT_LONG:
errorString = QStringLiteral("attribute not read/written using read blob"); break;
- case ATT_ERROR_INSUF_ENCR_KEY_SIZE:
+ case QBluezConst::AttError::ATT_ERROR_INSUF_ENCR_KEY_SIZE:
errorString = QStringLiteral("need encryption key size - permissions"); break;
- case ATT_ERROR_INVAL_ATTR_VALUE_LEN:
+ case QBluezConst::AttError::ATT_ERROR_INVAL_ATTR_VALUE_LEN:
errorString = QStringLiteral("written value is invalid size"); break;
- case ATT_ERROR_UNLIKELY:
+ case QBluezConst::AttError::ATT_ERROR_UNLIKELY:
errorString = QStringLiteral("unlikely error"); break;
- case ATT_ERROR_INSUF_ENCRYPTION:
+ case QBluezConst::AttError::ATT_ERROR_INSUF_ENCRYPTION:
errorString = QStringLiteral("needs encryption - permissions"); break;
- case ATT_ERROR_UNSUPPRTED_GROUP_TYPE:
+ case QBluezConst::AttError::ATT_ERROR_UNSUPPRTED_GROUP_TYPE:
errorString = QStringLiteral("unsupported group type"); break;
- case ATT_ERROR_INSUF_RESOURCES:
+ case QBluezConst::AttError::ATT_ERROR_INSUF_RESOURCES:
errorString = QStringLiteral("insufficient resources to complete request"); break;
default:
- if (errorCode >= ATT_ERROR_APPLICATION_START && errorCode <= ATT_ERROR_APPLICATION_END)
- errorString = QStringLiteral("application error: %1").arg(errorCode);
+ if (errorCode >= QBluezConst::AttError::ATT_ERROR_APPLICATION_START
+ && errorCode <= QBluezConst::AttError::ATT_ERROR_APPLICATION_END)
+ errorString =
+ QStringLiteral("application error: %1").arg(static_cast<quint8>(errorCode));
else
errorString = QStringLiteral("unknown error code");
break;
}
- qCDebug(QT_BT_BLUEZ) << "Error1:" << errorString
- << "last command:" << Qt::hex << lastCommand
- << "handle:" << handle;
+ qCDebug(QT_BT_BLUEZ) << "Error:" << errorCode << "Error description:" << errorString
+ << "last command:" << lastCommand << "handle:" << handle;
}
static int getUuidSize(const QBluetoothUuid &uuid)
@@ -252,22 +140,22 @@ template<typename T> static void putDataAndIncrement(const T &src, char *&dst)
}
template<> void putDataAndIncrement(const QBluetoothUuid &uuid, char *&dst)
{
- const int uuidSize = getUuidSize(uuid);
- if (uuidSize == 2) {
- putBtData(uuid.toUInt16(), dst);
+ bool ok;
+ quint16 uuid16 = uuid.toUInt16(&ok);
+ if (ok) {
+ putBtData(uuid16, dst);
+ dst += sizeof(uuid16);
} else {
- quint128 hostOrder;
- quint128 qtUuidOrder = uuid.toUInt128();
- ntoh128(&qtUuidOrder, &hostOrder);
- putBtData(hostOrder, dst);
+ QUuid::Id128Bytes btOrder = uuid.toBytes(QSysInfo::LittleEndian);
+ memcpy(dst, btOrder.data, sizeof(btOrder));
+ dst += sizeof(btOrder);
}
- dst += uuidSize;
}
template<> void putDataAndIncrement(const QByteArray &value, char *&dst)
{
using namespace std;
- memcpy(dst, value.constData(), value.count());
- dst += value.count();
+ memcpy(dst, value.constData(), value.size());
+ dst += value.size();
}
QLowEnergyControllerPrivateBluez::QLowEnergyControllerPrivateBluez()
@@ -283,27 +171,31 @@ QLowEnergyControllerPrivateBluez::QLowEnergyControllerPrivateBluez()
void QLowEnergyControllerPrivateBluez::init()
{
- hciManager = new HciManager(localAdapter, this);
- if (!hciManager->isValid())
+ // The HCI manager is shared between this class and the advertiser
+ hciManager = std::make_shared<HciManager>(localAdapter);
+
+ if (!hciManager->isValid()){
+ setError(QLowEnergyController::InvalidBluetoothAdapterError);
return;
+ }
- hciManager->monitorEvent(HciManager::EncryptChangeEvent);
- connect(hciManager, SIGNAL(encryptionChangedEvent(QBluetoothAddress,bool)),
+ hciManager->monitorEvent(HciManager::HciEvent::EVT_ENCRYPT_CHANGE);
+ connect(hciManager.get(), SIGNAL(encryptionChangedEvent(QBluetoothAddress,bool)),
this, SLOT(encryptionChangedEvent(QBluetoothAddress,bool)));
- hciManager->monitorEvent(HciManager::LeMetaEvent);
+ hciManager->monitorEvent(HciManager::HciEvent::EVT_LE_META_EVENT);
hciManager->monitorAclPackets();
- connect(hciManager, &HciManager::connectionComplete, [this](quint16 handle) {
+ connect(hciManager.get(), &HciManager::connectionComplete, this, [this](quint16 handle) {
connectionHandle = handle;
qCDebug(QT_BT_BLUEZ) << "received connection complete event, handle:" << handle;
});
- connect(hciManager, &HciManager::connectionUpdate,
+ connect(hciManager.get(), &HciManager::connectionUpdate, this,
[this](quint16 handle, const QLowEnergyConnectionParameters &params) {
if (handle == connectionHandle)
emit q_ptr->connectionUpdated(params);
}
);
- connect(hciManager, &HciManager::signatureResolvingKeyReceived,
- [this](quint16 handle, bool remoteKey, const quint128 &csrk) {
+ connect(hciManager.get(), &HciManager::signatureResolvingKeyReceived, this,
+ [this](quint16 handle, bool remoteKey, const QUuid::Id128Bytes &csrk) {
if (handle != connectionHandle)
return;
if ((remoteKey && role == QLowEnergyController::CentralRole)
@@ -333,7 +225,6 @@ void QLowEnergyControllerPrivateBluez::init()
requestTimer->setInterval(gattRequestTimeout);
connect(requestTimer, &QTimer::timeout,
this, &QLowEnergyControllerPrivateBluez::handleGattRequestTimeout);
- qRegisterMetaTypeStreamOperators<QBluetoothUuid>();
}
}
}
@@ -351,60 +242,65 @@ void QLowEnergyControllerPrivateBluez::handleGattRequestTimeout()
const Request currentRequest = openRequests.dequeue();
requestPending = false; // reset pending flag
- qCWarning(QT_BT_BLUEZ).nospace() << "****** Request type 0x" << Qt::hex << currentRequest.command
- << " to server/peripheral timed out";
+ qCWarning(QT_BT_BLUEZ).nospace() << "****** Request type 0x" << currentRequest.command
+ << " to server/peripheral timed out";
qCWarning(QT_BT_BLUEZ) << "****** Looks like the characteristic or descriptor does NOT act in"
<< "accordance to Bluetooth 4.x spec.";
qCWarning(QT_BT_BLUEZ) << "****** Please check server implementation."
<< "Continuing under reservation.";
- quint8 command = currentRequest.command;
- const auto createRequestErrorMessage = [](quint8 opcodeWithError,
- QLowEnergyHandle handle) {
+ QBluezConst::AttCommand command = currentRequest.command;
+ const auto createRequestErrorMessage = [](QBluezConst::AttCommand opcodeWithError,
+ QLowEnergyHandle handle) {
QByteArray errorPackage(ERROR_RESPONSE_HEADER_SIZE, Qt::Uninitialized);
- errorPackage[0] = ATT_OP_ERROR_RESPONSE;
- errorPackage[1] = opcodeWithError; // e.g. ATT_OP_READ_REQUEST
+ errorPackage[0] = static_cast<quint8>(QBluezConst::AttCommand::ATT_OP_ERROR_RESPONSE);
+ errorPackage[1] = static_cast<quint8>(
+ opcodeWithError); // e.g. QBluezConst::AttCommand::ATT_OP_READ_REQUEST
putBtData(handle, errorPackage.data() + 2); //
- errorPackage[4] = ATT_ERROR_REQUEST_STALLED;
+ errorPackage[4] = static_cast<quint8>(QBluezConst::AttError::ATT_ERROR_REQUEST_STALLED);
return errorPackage;
};
switch (command) {
- case ATT_OP_EXCHANGE_MTU_REQUEST: // MTU change request
+ case QBluezConst::AttCommand::ATT_OP_EXCHANGE_MTU_REQUEST: // MTU change request
// never received reply to MTU request
// it is safe to skip and go to next request
break;
- case ATT_OP_READ_BY_GROUP_REQUEST: // primary or secondary service discovery
- case ATT_OP_READ_BY_TYPE_REQUEST: // characteristic or included service discovery
+ case QBluezConst::AttCommand::ATT_OP_READ_BY_GROUP_REQUEST: // primary or secondary service
+ // discovery
+ case QBluezConst::AttCommand::ATT_OP_READ_BY_TYPE_REQUEST: // characteristic or included
+ // service discovery
// jump back into usual response handling with custom error code
// 2nd param "0" as required by spec
processReply(currentRequest, createRequestErrorMessage(command, 0));
break;
- case ATT_OP_READ_REQUEST: // read descriptor or characteristic value
- case ATT_OP_READ_BLOB_REQUEST: // read long descriptor or characteristic
- case ATT_OP_WRITE_REQUEST: // write descriptor or characteristic
+ case QBluezConst::AttCommand::ATT_OP_READ_REQUEST: // read descriptor or characteristic
+ // value
+ case QBluezConst::AttCommand::ATT_OP_READ_BLOB_REQUEST: // read long descriptor or
+ // characteristic
+ case QBluezConst::AttCommand::ATT_OP_WRITE_REQUEST: // write descriptor or characteristic
{
uint handleData = currentRequest.reference.toUInt();
const QLowEnergyHandle charHandle = (handleData & 0xffff);
const QLowEnergyHandle descriptorHandle = ((handleData >> 16) & 0xffff);
processReply(currentRequest, createRequestErrorMessage(command,
descriptorHandle ? descriptorHandle : charHandle));
- }
- break;
- case ATT_OP_FIND_INFORMATION_REQUEST: // get descriptor information
+ } break;
+ case QBluezConst::AttCommand::ATT_OP_FIND_INFORMATION_REQUEST: // get descriptor information
processReply(currentRequest, createRequestErrorMessage(
command, currentRequest.reference2.toUInt()));
break;
- case ATT_OP_PREPARE_WRITE_REQUEST: // prepare to write long desc or char
- case ATT_OP_EXECUTE_WRITE_REQUEST: // execute long write of desc or char
+ case QBluezConst::AttCommand::ATT_OP_PREPARE_WRITE_REQUEST: // prepare to write long desc or
+ // char
+ case QBluezConst::AttCommand::ATT_OP_EXECUTE_WRITE_REQUEST: // execute long write of desc or
+ // char
{
uint handleData = currentRequest.reference.toUInt();
const QLowEnergyHandle attrHandle = (handleData & 0xffff);
processReply(currentRequest,
createRequestErrorMessage(command, attrHandle));
- }
- break;
+ } break;
default:
// not a command used by central role implementation
qCWarning(QT_BT_BLUEZ) << "Missing response for ATT peripheral command: "
@@ -421,6 +317,7 @@ QLowEnergyControllerPrivateBluez::~QLowEnergyControllerPrivateBluez()
{
closeServerSocket();
delete cmacCalculator;
+ cmacCalculator = nullptr;
}
class ServerSocket
@@ -479,7 +376,7 @@ void QLowEnergyControllerPrivateBluez::startAdvertising(const QLowEnergyAdvertis
{
qCDebug(QT_BT_BLUEZ) << "Starting to advertise";
if (!advertiser) {
- advertiser = new QLeAdvertiserBluez(params, advertisingData, scanResponseData, *hciManager,
+ advertiser = new QLeAdvertiserBluez(params, advertisingData, scanResponseData, hciManager,
this);
connect(advertiser, &QLeAdvertiser::errorOccurred, this,
&QLowEnergyControllerPrivateBluez::handleAdvertisingError);
@@ -543,15 +440,8 @@ void QLowEnergyControllerPrivateBluez::connectToDevice()
// check for active running connections
// BlueZ 5.37+ (maybe even earlier versions) can have pending BTLE connections
// Only one active L2CP socket to CID 0x4 possible at a time
- // this check is not performed for BlueZ 4 based platforms as bluetoothd
- // does not support BTLE management
-
- if (!isBluez5()) {
- establishL2cpClientSocket();
- return;
- }
- QVector<quint16> activeHandles = hciManager->activeLowEnergyConnections();
+ QList<quint16> activeHandles = hciManager->activeLowEnergyConnections();
if (!activeHandles.isEmpty()) {
qCWarning(QT_BT_BLUEZ) << "Cannot connect due to pending active LE connections";
@@ -561,7 +451,7 @@ void QLowEnergyControllerPrivateBluez::connectToDevice()
this, &QLowEnergyControllerPrivateBluez::activeConnectionTerminationDone);
}
- QVector<QBluetoothAddress> connectedAddresses;
+ QList<QBluetoothAddress> connectedAddresses;
for (const auto handle: activeHandles) {
const QBluetoothAddress addr = hciManager->addressForConnectionHandle(handle);
if (!addr.isNull())
@@ -584,7 +474,7 @@ void QLowEnergyControllerPrivateBluez::activeConnectionTerminationDone()
qCDebug(QT_BT_BLUEZ) << "RemoteDeviceManager finished attempting"
<< "to close external connections";
- QVector<quint16> activeHandles = hciManager->activeLowEnergyConnections();
+ QList<quint16> activeHandles = hciManager->activeLowEnergyConnections();
if (!activeHandles.isEmpty()) {
qCWarning(QT_BT_BLUEZ) << "Cannot close pending external BTLE connections. Aborting connect attempt";
setError(QLowEnergyController::ConnectionError);
@@ -606,8 +496,8 @@ void QLowEnergyControllerPrivateBluez::establishL2cpClientSocket()
l2cpSocket = new QBluetoothSocket(QBluetoothServiceInfo::L2capProtocol, this);
connect(l2cpSocket, SIGNAL(connected()), this, SLOT(l2cpConnected()));
connect(l2cpSocket, SIGNAL(disconnected()), this, SLOT(l2cpDisconnected()));
- connect(l2cpSocket, SIGNAL(error(QBluetoothSocket::SocketError)),
- this, SLOT(l2cpErrorChanged(QBluetoothSocket::SocketError)));
+ connect(l2cpSocket, SIGNAL(errorOccurred(QBluetoothSocket::SocketError)), this,
+ SLOT(l2cpErrorChanged(QBluetoothSocket::SocketError)));
connect(l2cpSocket, SIGNAL(readyRead()), this, SLOT(l2cpReadyRead()));
quint32 addressTypeToUse = (addressType == QLowEnergyController::PublicAddress)
@@ -663,7 +553,7 @@ void QLowEnergyControllerPrivateBluez::createServicesForCentralIfRequired()
return; //nothing to do
//do not add the services each time we start a connection
- if (localServices.contains(QBluetoothUuid(QBluetoothUuid::GenericAccess)))
+ if (localServices.contains(QBluetoothUuid(QBluetoothUuid::ServiceClassUuid::GenericAccess)))
return;
qCDebug(QT_BT_BLUEZ) << "Creating default GAP/GATT services";
@@ -672,22 +562,22 @@ void QLowEnergyControllerPrivateBluez::createServicesForCentralIfRequired()
//for now the values are static
QLowEnergyServiceData gapServiceData;
gapServiceData.setType(QLowEnergyServiceData::ServiceTypePrimary);
- gapServiceData.setUuid(QBluetoothUuid::GenericAccess);
+ gapServiceData.setUuid(QBluetoothUuid::ServiceClassUuid::GenericAccess);
QLowEnergyCharacteristicData gapDeviceName;
- gapDeviceName.setUuid(QBluetoothUuid::DeviceName);
+ gapDeviceName.setUuid(QBluetoothUuid::CharacteristicType::DeviceName);
gapDeviceName.setProperties(QLowEnergyCharacteristic::Read);
QBluetoothLocalDevice mainAdapter;
gapDeviceName.setValue(mainAdapter.name().toLatin1()); //static name
QLowEnergyCharacteristicData gapAppearance;
- gapAppearance.setUuid(QBluetoothUuid::Appearance);
+ gapAppearance.setUuid(QBluetoothUuid::CharacteristicType::Appearance);
gapAppearance.setProperties(QLowEnergyCharacteristic::Read);
gapAppearance.setValue(QByteArray::fromHex("80")); // Generic Computer (0x80)
QLowEnergyCharacteristicData gapPrivacyFlag;
- gapPrivacyFlag.setUuid(QBluetoothUuid::PeripheralPrivacyFlag);
+ gapPrivacyFlag.setUuid(QBluetoothUuid::CharacteristicType::PeripheralPrivacyFlag);
gapPrivacyFlag.setProperties(QLowEnergyCharacteristic::Read);
gapPrivacyFlag.setValue(QByteArray::fromHex("00")); // disable privacy
@@ -702,16 +592,16 @@ void QLowEnergyControllerPrivateBluez::createServicesForCentralIfRequired()
QLowEnergyServiceData gattServiceData;
gattServiceData.setType(QLowEnergyServiceData::ServiceTypePrimary);
- gattServiceData.setUuid(QBluetoothUuid::GenericAttribute);
+ gattServiceData.setUuid(QBluetoothUuid::ServiceClassUuid::GenericAttribute);
QLowEnergyCharacteristicData serviceChangedChar;
- serviceChangedChar.setUuid(QBluetoothUuid::ServiceChanged);
+ serviceChangedChar.setUuid(QBluetoothUuid::CharacteristicType::ServiceChanged);
serviceChangedChar.setProperties(QLowEnergyCharacteristic::Indicate);
//arbitrary range of 2 bit handle range (1-4
serviceChangedChar.setValue(QByteArray::fromHex("0104"));
const QLowEnergyDescriptorData clientConfig(
- QBluetoothUuid::ClientCharacteristicConfiguration,
+ QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration,
QByteArray(2, 0));
serviceChangedChar.addDescriptor(clientConfig);
gattServiceData.addCharacteristic(serviceChangedChar);
@@ -765,22 +655,22 @@ void QLowEnergyControllerPrivateBluez::l2cpDisconnected()
void QLowEnergyControllerPrivateBluez::l2cpErrorChanged(QBluetoothSocket::SocketError e)
{
switch (e) {
- case QBluetoothSocket::HostNotFoundError:
+ case QBluetoothSocket::SocketError::HostNotFoundError:
setError(QLowEnergyController::UnknownRemoteDeviceError);
qCDebug(QT_BT_BLUEZ) << "The passed remote device address cannot be found";
break;
- case QBluetoothSocket::NetworkError:
+ case QBluetoothSocket::SocketError::NetworkError:
setError(QLowEnergyController::NetworkError);
qCDebug(QT_BT_BLUEZ) << "Network IO error while talking to LE device";
break;
- case QBluetoothSocket::RemoteHostClosedError:
+ case QBluetoothSocket::SocketError::RemoteHostClosedError:
setError(QLowEnergyController::RemoteHostClosedError);
qCDebug(QT_BT_BLUEZ) << "Remote host closed the connection";
break;
- case QBluetoothSocket::UnknownSocketError:
- case QBluetoothSocket::UnsupportedProtocolError:
- case QBluetoothSocket::OperationError:
- case QBluetoothSocket::ServiceNotFoundError:
+ case QBluetoothSocket::SocketError::UnknownSocketError:
+ case QBluetoothSocket::SocketError::UnsupportedProtocolError:
+ case QBluetoothSocket::SocketError::OperationError:
+ case QBluetoothSocket::SocketError::ServiceNotFoundError:
default:
// these errors shouldn't happen -> as it means
// the code in this file has bugs
@@ -836,18 +726,17 @@ void QLowEnergyControllerPrivateBluez::l2cpReadyRead()
if (incomingPacket.isEmpty())
return;
- const quint8 command = incomingPacket.constData()[0];
+ const QBluezConst::AttCommand command =
+ static_cast<QBluezConst::AttCommand>(incomingPacket.constData()[0]);
switch (command) {
- case ATT_OP_HANDLE_VAL_NOTIFICATION:
- {
+ case QBluezConst::AttCommand::ATT_OP_HANDLE_VAL_NOTIFICATION: {
processUnsolicitedReply(incomingPacket);
return;
}
- case ATT_OP_HANDLE_VAL_INDICATION:
- {
+ case QBluezConst::AttCommand::ATT_OP_HANDLE_VAL_INDICATION: {
//send confirmation
QByteArray packet;
- packet.append(static_cast<char>(ATT_OP_HANDLE_VAL_CONFIRMATION));
+ packet.append(static_cast<quint8>(QBluezConst::AttCommand::ATT_OP_HANDLE_VAL_CONFIRMATION));
sendPacket(packet);
processUnsolicitedReply(incomingPacket);
@@ -855,42 +744,42 @@ void QLowEnergyControllerPrivateBluez::l2cpReadyRead()
}
//--------------------------------------------------
// Peripheral side packet handling
- case ATT_OP_EXCHANGE_MTU_REQUEST:
+ case QBluezConst::AttCommand::ATT_OP_EXCHANGE_MTU_REQUEST:
handleExchangeMtuRequest(incomingPacket);
return;
- case ATT_OP_FIND_INFORMATION_REQUEST:
+ case QBluezConst::AttCommand::ATT_OP_FIND_INFORMATION_REQUEST:
handleFindInformationRequest(incomingPacket);
return;
- case ATT_OP_FIND_BY_TYPE_VALUE_REQUEST:
+ case QBluezConst::AttCommand::ATT_OP_FIND_BY_TYPE_VALUE_REQUEST:
handleFindByTypeValueRequest(incomingPacket);
return;
- case ATT_OP_READ_BY_TYPE_REQUEST:
+ case QBluezConst::AttCommand::ATT_OP_READ_BY_TYPE_REQUEST:
handleReadByTypeRequest(incomingPacket);
return;
- case ATT_OP_READ_REQUEST:
+ case QBluezConst::AttCommand::ATT_OP_READ_REQUEST:
handleReadRequest(incomingPacket);
return;
- case ATT_OP_READ_BLOB_REQUEST:
+ case QBluezConst::AttCommand::ATT_OP_READ_BLOB_REQUEST:
handleReadBlobRequest(incomingPacket);
return;
- case ATT_OP_READ_MULTIPLE_REQUEST:
+ case QBluezConst::AttCommand::ATT_OP_READ_MULTIPLE_REQUEST:
handleReadMultipleRequest(incomingPacket);
return;
- case ATT_OP_READ_BY_GROUP_REQUEST:
+ case QBluezConst::AttCommand::ATT_OP_READ_BY_GROUP_REQUEST:
handleReadByGroupTypeRequest(incomingPacket);
return;
- case ATT_OP_WRITE_REQUEST:
- case ATT_OP_WRITE_COMMAND:
- case ATT_OP_SIGNED_WRITE_COMMAND:
+ case QBluezConst::AttCommand::ATT_OP_WRITE_REQUEST:
+ case QBluezConst::AttCommand::ATT_OP_WRITE_COMMAND:
+ case QBluezConst::AttCommand::ATT_OP_SIGNED_WRITE_COMMAND:
handleWriteRequestOrCommand(incomingPacket);
return;
- case ATT_OP_PREPARE_WRITE_REQUEST:
+ case QBluezConst::AttCommand::ATT_OP_PREPARE_WRITE_REQUEST:
handlePrepareWriteRequest(incomingPacket);
return;
- case ATT_OP_EXECUTE_WRITE_REQUEST:
+ case QBluezConst::AttCommand::ATT_OP_EXECUTE_WRITE_REQUEST:
handleExecuteWriteRequest(incomingPacket);
return;
- case ATT_OP_HANDLE_VAL_CONFIRMATION:
+ case QBluezConst::AttCommand::ATT_OP_HANDLE_VAL_CONFIRMATION:
if (indicationInFlight) {
indicationInFlight = false;
sendNextIndication();
@@ -945,8 +834,8 @@ void QLowEnergyControllerPrivateBluez::encryptionChangedEvent(
Q_ASSERT(!openRequests.isEmpty());
Request failedRequest = openRequests.takeFirst();
- if (failedRequest.command == ATT_OP_WRITE_REQUEST) {
- // Failing write requests trigger some sort of response
+ if (failedRequest.command == QBluezConst::AttCommand::ATT_OP_WRITE_REQUEST) {
+ // Failing write requests trigger some sort of response
uint ref = failedRequest.reference.toUInt();
const QLowEnergyHandle charHandle = (ref & 0xffff);
const QLowEnergyHandle descriptorHandle = ((ref >> 16) & 0xffff);
@@ -959,7 +848,7 @@ void QLowEnergyControllerPrivateBluez::encryptionChangedEvent(
else
service->setError(QLowEnergyService::DescriptorWriteError);
}
- } else if (failedRequest.command == ATT_OP_PREPARE_WRITE_REQUEST) {
+ } else if (failedRequest.command == QBluezConst::AttCommand::ATT_OP_PREPARE_WRITE_REQUEST) {
uint handleData = failedRequest.reference.toUInt();
const QLowEnergyHandle attrHandle = (handleData & 0xffff);
const QByteArray newValue = failedRequest.reference2.toByteArray();
@@ -1020,10 +909,11 @@ QLowEnergyHandle parseReadByTypeCharDiscovery(
(QLowEnergyCharacteristic::PropertyTypes)(data[2] & 0xff);
charData->valueHandle = bt_get_le16(&data[3]);
+ // Bluetooth LE data comes as little endian
if (elementLength == 7) // 16 bit uuid
charData->uuid = QBluetoothUuid(bt_get_le16(&data[5]));
else
- charData->uuid = convert_uuid128((quint128 *)&data[5]);
+ charData->uuid = QUuid::fromBytes(&data[5], QSysInfo::LittleEndian);
qCDebug(QT_BT_BLUEZ) << "Found handle:" << Qt::hex << attributeHandle
<< "properties:" << charData->properties
@@ -1051,7 +941,7 @@ QLowEnergyHandle parseReadByTypeIncludeDiscovery(
if (elementLength == 8) //16 bit uuid
foundServices->append(QBluetoothUuid(bt_get_le16(&data[6])));
else
- foundServices->append(convert_uuid128((quint128 *) &data[6]));
+ foundServices->append(QUuid::fromBytes(&data[6], QSysInfo::LittleEndian));
qCDebug(QT_BT_BLUEZ) << "Found included service: " << Qt::hex
<< attributeHandle << "uuid:" << *foundServices;
@@ -1064,40 +954,39 @@ void QLowEnergyControllerPrivateBluez::processReply(
{
Q_Q(QLowEnergyController);
- quint8 command = response.constData()[0];
+ QBluezConst::AttCommand command = static_cast<QBluezConst::AttCommand>(response.constData()[0]);
bool isErrorResponse = false;
// if error occurred 2. byte is previous request type
- if (command == ATT_OP_ERROR_RESPONSE) {
+ if (command == QBluezConst::AttCommand::ATT_OP_ERROR_RESPONSE) {
dumpErrorInformation(response);
- command = response.constData()[1];
+ command = static_cast<QBluezConst::AttCommand>(response.constData()[1]);
isErrorResponse = true;
}
switch (command) {
- case ATT_OP_EXCHANGE_MTU_REQUEST: // in case of error
- case ATT_OP_EXCHANGE_MTU_RESPONSE:
- {
- Q_ASSERT(request.command == ATT_OP_EXCHANGE_MTU_REQUEST);
+ case QBluezConst::AttCommand::ATT_OP_EXCHANGE_MTU_REQUEST: // in case of error
+ case QBluezConst::AttCommand::ATT_OP_EXCHANGE_MTU_RESPONSE: {
+ Q_ASSERT(request.command == QBluezConst::AttCommand::ATT_OP_EXCHANGE_MTU_REQUEST);
+ quint16 oldMtuSize = mtuSize;
if (isErrorResponse) {
mtuSize = ATT_DEFAULT_LE_MTU;
- break;
- }
-
- const char *data = response.constData();
- quint16 mtu = bt_get_le16(&data[1]);
- mtuSize = mtu;
- if (mtuSize < ATT_DEFAULT_LE_MTU)
- mtuSize = ATT_DEFAULT_LE_MTU;
+ } else {
+ const char *data = response.constData();
+ quint16 mtu = bt_get_le16(&data[1]);
+ mtuSize = mtu;
+ if (mtuSize < ATT_DEFAULT_LE_MTU)
+ mtuSize = ATT_DEFAULT_LE_MTU;
- qCDebug(QT_BT_BLUEZ) << "Server MTU:" << mtu << "resulting mtu:" << mtuSize;
- }
- break;
- case ATT_OP_READ_BY_GROUP_REQUEST: // in case of error
- case ATT_OP_READ_BY_GROUP_RESPONSE:
- {
+ qCDebug(QT_BT_BLUEZ) << "Server MTU:" << mtu << "resulting mtu:" << mtuSize;
+ }
+ if (oldMtuSize != mtuSize)
+ emit q->mtuChanged(mtuSize);
+ } break;
+ case QBluezConst::AttCommand::ATT_OP_READ_BY_GROUP_REQUEST: // in case of error
+ case QBluezConst::AttCommand::ATT_OP_READ_BY_GROUP_RESPONSE: {
// Discovering services
- Q_ASSERT(request.command == ATT_OP_READ_BY_GROUP_REQUEST);
+ Q_ASSERT(request.command == QBluezConst::AttCommand::ATT_OP_READ_BY_GROUP_REQUEST);
const quint16 type = request.reference.toUInt();
@@ -1124,7 +1013,7 @@ void QLowEnergyControllerPrivateBluez::processReply(
if (elementLength == 6) //16 bit uuid
uuid = QBluetoothUuid(bt_get_le16(&data[offset+4]));
else if (elementLength == 20) //128 bit uuid
- uuid = convert_uuid128((quint128 *)&data[offset+4]);
+ uuid = QUuid::fromBytes(&data[offset+4], QSysInfo::LittleEndian);
//else -> do nothing
offset += elementLength;
@@ -1157,13 +1046,11 @@ void QLowEnergyControllerPrivateBluez::processReply(
sendReadByGroupRequest(0x0001, 0xFFFF, GATT_SECONDARY_SERVICE);
}
}
- }
- break;
- case ATT_OP_READ_BY_TYPE_REQUEST: //in case of error
- case ATT_OP_READ_BY_TYPE_RESPONSE:
- {
+ } break;
+ case QBluezConst::AttCommand::ATT_OP_READ_BY_TYPE_REQUEST: // in case of error
+ case QBluezConst::AttCommand::ATT_OP_READ_BY_TYPE_RESPONSE: {
// Discovering characteristics
- Q_ASSERT(request.command == ATT_OP_READ_BY_TYPE_REQUEST);
+ Q_ASSERT(request.command == QBluezConst::AttCommand::ATT_OP_READ_BY_TYPE_REQUEST);
QSharedPointer<QLowEnergyServicePrivate> p =
request.reference.value<QSharedPointer<QLowEnergyServicePrivate> >();
@@ -1179,7 +1066,7 @@ void QLowEnergyControllerPrivateBluez::processReply(
} else {
// discovery finished since the service doesn't have any
// characteristics
- p->setState(QLowEnergyService::ServiceDiscovered);
+ p->setState(QLowEnergyService::RemoteServiceDiscovered);
}
} else if (attributeType == GATT_INCLUDED_SERVICE) {
// finished up include discovery
@@ -1217,7 +1104,7 @@ void QLowEnergyControllerPrivateBluez::processReply(
lastHandle = parseReadByTypeIncludeDiscovery(
&includedServices, &data[offset], elementLength);
p->includedServices = includedServices;
- for (const QBluetoothUuid &uuid : qAsConst(includedServices)) {
+ for (const QBluetoothUuid &uuid : std::as_const(includedServices)) {
if (serviceList.contains(uuid))
serviceList[uuid]->type |= QLowEnergyService::IncludedService;
}
@@ -1232,13 +1119,11 @@ void QLowEnergyControllerPrivateBluez::processReply(
else
readServiceValues(p->uuid, true);
}
- }
- break;
- case ATT_OP_READ_REQUEST: //error case
- case ATT_OP_READ_RESPONSE:
- {
+ } break;
+ case QBluezConst::AttCommand::ATT_OP_READ_REQUEST: // error case
+ case QBluezConst::AttCommand::ATT_OP_READ_RESPONSE: {
//Reading characteristics and descriptors
- Q_ASSERT(request.command == ATT_OP_READ_REQUEST);
+ Q_ASSERT(request.command == QBluezConst::AttCommand::ATT_OP_READ_REQUEST);
uint handleData = request.reference.toUInt();
const QLowEnergyHandle charHandle = (handleData & 0xffff);
@@ -1247,11 +1132,12 @@ void QLowEnergyControllerPrivateBluez::processReply(
QSharedPointer<QLowEnergyServicePrivate> service = serviceForHandle(charHandle);
Q_ASSERT(!service.isNull());
bool isServiceDiscoveryRun
- = !(service->state == QLowEnergyService::ServiceDiscovered);
+ = !(service->state == QLowEnergyService::RemoteServiceDiscovered);
if (isErrorResponse) {
Q_ASSERT(!encryptionChangePending);
- encryptionChangePending = increaseEncryptLevelfRequired(response.constData()[4]);
+ QBluezConst::AttError err = static_cast<QBluezConst::AttError>(response.constData()[4]);
+ encryptionChangePending = increaseEncryptLevelfRequired(err);
if (encryptionChangePending) {
// Just requested a security level change.
// Retry the same command again once the change has happened
@@ -1301,15 +1187,13 @@ void QLowEnergyControllerPrivateBluez::processReply(
if (!descriptorHandle)
discoverServiceDescriptors(service->uuid);
else
- service->setState(QLowEnergyService::ServiceDiscovered);
+ service->setState(QLowEnergyService::RemoteServiceDiscovered);
}
- }
- break;
- case ATT_OP_READ_BLOB_REQUEST: //error case
- case ATT_OP_READ_BLOB_RESPONSE:
- {
+ } break;
+ case QBluezConst::AttCommand::ATT_OP_READ_BLOB_REQUEST: // error case
+ case QBluezConst::AttCommand::ATT_OP_READ_BLOB_RESPONSE: {
//Reading characteristic or descriptor with value longer value than MTU
- Q_ASSERT(request.command == ATT_OP_READ_BLOB_REQUEST);
+ Q_ASSERT(request.command == QBluezConst::AttCommand::ATT_OP_READ_BLOB_REQUEST);
uint handleData = request.reference.toUInt();
const QLowEnergyHandle charHandle = (handleData & 0xffff);
@@ -1336,7 +1220,7 @@ void QLowEnergyControllerPrivateBluez::processReply(
readServiceValuesByOffset(handleData, length,
request.reference2.toBool());
break;
- } else if (service->state == QLowEnergyService::ServiceDiscovered) {
+ } else if (service->state == QLowEnergyService::RemoteServiceDiscovered) {
// readCharacteristic() or readDescriptor() ongoing
if (!descriptorHandle) {
QLowEnergyCharacteristic ch(service, charHandle);
@@ -1351,7 +1235,7 @@ void QLowEnergyControllerPrivateBluez::processReply(
qWarning() << "READ BLOB for char:" << charHandle
<< "descriptor:" << descriptorHandle << "on service"
<< service->uuid.toString() << "failed (service discovery run:"
- << (service->state == QLowEnergyService::ServiceDiscovered) << ")";
+ << (service->state == QLowEnergyService::RemoteServiceDiscovered) << ")";
}
if (request.reference2.toBool()) {
@@ -1361,16 +1245,14 @@ void QLowEnergyControllerPrivateBluez::processReply(
if (!descriptorHandle)
discoverServiceDescriptors(service->uuid);
else
- service->setState(QLowEnergyService::ServiceDiscovered);
+ service->setState(QLowEnergyService::RemoteServiceDiscovered);
}
- }
- break;
- case ATT_OP_FIND_INFORMATION_REQUEST: //error case
- case ATT_OP_FIND_INFORMATION_RESPONSE:
- {
+ } break;
+ case QBluezConst::AttCommand::ATT_OP_FIND_INFORMATION_REQUEST: // error case
+ case QBluezConst::AttCommand::ATT_OP_FIND_INFORMATION_RESPONSE: {
//Discovering descriptors
- Q_ASSERT(request.command == ATT_OP_FIND_INFORMATION_REQUEST);
+ Q_ASSERT(request.command == QBluezConst::AttCommand::ATT_OP_FIND_INFORMATION_REQUEST);
/* packet format:
* <opcode><format>[<handle><descriptor_uuid>]+
@@ -1390,7 +1272,7 @@ void QLowEnergyControllerPrivateBluez::processReply(
Q_ASSERT(!p.isNull());
if (isErrorResponse) {
- if (keys.count() == 1) {
+ if (keys.size() == 1) {
// no more descriptors to discover
readServiceValues(p->uuid, false); //read descriptor values
} else {
@@ -1418,7 +1300,7 @@ void QLowEnergyControllerPrivateBluez::processReply(
const quint16 numElements = (response.size() - 2) / elementLength;
quint16 offset = 2;
- QLowEnergyHandle descriptorHandle;
+ QLowEnergyHandle descriptorHandle {};
QBluetoothUuid uuid;
const char *data = response.constData();
for (int i = 0; i < numElements; i++) {
@@ -1427,7 +1309,7 @@ void QLowEnergyControllerPrivateBluez::processReply(
if (format == 0x01)
uuid = QBluetoothUuid(bt_get_le16(&data[offset+2]));
else if (format == 0x02)
- uuid = convert_uuid128((quint128 *)&data[offset+2]);
+ uuid = QUuid::fromBytes(&data[offset+2], QSysInfo::LittleEndian);
offset += elementLength;
@@ -1458,7 +1340,7 @@ void QLowEnergyControllerPrivateBluez::processReply(
}
const QLowEnergyHandle nextPotentialHandle = descriptorHandle + 1;
- if (keys.count() == 1) {
+ if (keys.size() == 1) {
// Reached last characteristic of service
// The endhandle of a service is always the last handle of
@@ -1481,13 +1363,11 @@ void QLowEnergyControllerPrivateBluez::processReply(
keys.removeFirst();
discoverNextDescriptor(p, keys, nextPotentialHandle);
}
- }
- break;
- case ATT_OP_WRITE_REQUEST: //error case
- case ATT_OP_WRITE_RESPONSE:
- {
+ } break;
+ case QBluezConst::AttCommand::ATT_OP_WRITE_REQUEST: // error case
+ case QBluezConst::AttCommand::ATT_OP_WRITE_RESPONSE: {
//Write command response
- Q_ASSERT(request.command == ATT_OP_WRITE_REQUEST);
+ Q_ASSERT(request.command == QBluezConst::AttCommand::ATT_OP_WRITE_REQUEST);
uint ref = request.reference.toUInt();
const QLowEnergyHandle charHandle = (ref & 0xffff);
@@ -1499,7 +1379,8 @@ void QLowEnergyControllerPrivateBluez::processReply(
if (isErrorResponse) {
Q_ASSERT(!encryptionChangePending);
- encryptionChangePending = increaseEncryptLevelfRequired(response.constData()[4]);
+ QBluezConst::AttError err = static_cast<QBluezConst::AttError>(response.constData()[4]);
+ encryptionChangePending = increaseEncryptLevelfRequired(err);
if (encryptionChangePending) {
openRequests.prepend(request);
break;
@@ -1523,13 +1404,11 @@ void QLowEnergyControllerPrivateBluez::processReply(
QLowEnergyDescriptor descriptor(service, charHandle, descriptorHandle);
emit service->descriptorWritten(descriptor, newValue);
}
- }
- break;
- case ATT_OP_PREPARE_WRITE_REQUEST: //error case
- case ATT_OP_PREPARE_WRITE_RESPONSE:
- {
+ } break;
+ case QBluezConst::AttCommand::ATT_OP_PREPARE_WRITE_REQUEST: // error case
+ case QBluezConst::AttCommand::ATT_OP_PREPARE_WRITE_RESPONSE: {
//Prepare write command response
- Q_ASSERT(request.command == ATT_OP_PREPARE_WRITE_REQUEST);
+ Q_ASSERT(request.command == QBluezConst::AttCommand::ATT_OP_PREPARE_WRITE_REQUEST);
uint handleData = request.reference.toUInt();
const QLowEnergyHandle attrHandle = (handleData & 0xffff);
@@ -1538,7 +1417,8 @@ void QLowEnergyControllerPrivateBluez::processReply(
if (isErrorResponse) {
Q_ASSERT(!encryptionChangePending);
- encryptionChangePending = increaseEncryptLevelfRequired(response.constData()[4]);
+ QBluezConst::AttError err = static_cast<QBluezConst::AttError>(response.constData()[4]);
+ encryptionChangePending = increaseEncryptLevelfRequired(err);
if (encryptionChangePending) {
openRequests.prepend(request);
break;
@@ -1552,14 +1432,12 @@ void QLowEnergyControllerPrivateBluez::processReply(
sendExecuteWriteRequest(attrHandle, newValue, false);
}
}
- }
- break;
- case ATT_OP_EXECUTE_WRITE_REQUEST: //error case
- case ATT_OP_EXECUTE_WRITE_RESPONSE:
- {
+ } break;
+ case QBluezConst::AttCommand::ATT_OP_EXECUTE_WRITE_REQUEST: // error case
+ case QBluezConst::AttCommand::ATT_OP_EXECUTE_WRITE_RESPONSE: {
// right now used in connection with long characteristic/descriptor value writes
// not catering for reliable writes
- Q_ASSERT(request.command == ATT_OP_EXECUTE_WRITE_REQUEST);
+ Q_ASSERT(request.command == QBluezConst::AttCommand::ATT_OP_EXECUTE_WRITE_REQUEST);
uint handleData = request.reference.toUInt();
const QLowEnergyHandle attrHandle = handleData & 0xffff;
@@ -1589,8 +1467,7 @@ void QLowEnergyControllerPrivateBluez::processReply(
emit service->characteristicWritten(ch, newValue);
}
}
- }
- break;
+ } break;
default:
qCDebug(QT_BT_BLUEZ) << "Unknown packet: " << response.toHex();
break;
@@ -1608,7 +1485,7 @@ void QLowEnergyControllerPrivateBluez::sendReadByGroupRequest(
//call for primary and secondary services
quint8 packet[GRP_TYPE_REQ_HEADER_SIZE];
- packet[0] = ATT_OP_READ_BY_GROUP_REQUEST;
+ packet[0] = static_cast<quint8>(QBluezConst::AttCommand::ATT_OP_READ_BY_GROUP_REQUEST);
putBtData(start, &packet[1]);
putBtData(end, &packet[3]);
putBtData(type, &packet[5]);
@@ -1620,14 +1497,15 @@ void QLowEnergyControllerPrivateBluez::sendReadByGroupRequest(
Request request;
request.payload = data;
- request.command = ATT_OP_READ_BY_GROUP_REQUEST;
+ request.command = QBluezConst::AttCommand::ATT_OP_READ_BY_GROUP_REQUEST;
request.reference = type;
openRequests.enqueue(request);
sendNextPendingRequest();
}
-void QLowEnergyControllerPrivateBluez::discoverServiceDetails(const QBluetoothUuid &service)
+void QLowEnergyControllerPrivateBluez::discoverServiceDetails(const QBluetoothUuid &service,
+ QLowEnergyService::DiscoveryMode mode)
{
if (!serviceList.contains(service)) {
qCWarning(QT_BT_BLUEZ) << "Discovery of unknown service" << service.toString()
@@ -1636,6 +1514,7 @@ void QLowEnergyControllerPrivateBluez::discoverServiceDetails(const QBluetoothUu
}
QSharedPointer<QLowEnergyServicePrivate> serviceData = serviceList.value(service);
+ serviceData->mode = mode;
serviceData->characteristicList.clear();
sendReadByTypeRequest(serviceData, serviceData->startHandle, GATT_INCLUDED_SERVICE);
}
@@ -1646,7 +1525,7 @@ void QLowEnergyControllerPrivateBluez::sendReadByTypeRequest(
{
quint8 packet[READ_BY_TYPE_REQ_HEADER_SIZE];
- packet[0] = ATT_OP_READ_BY_TYPE_REQUEST;
+ packet[0] = static_cast<quint8>(QBluezConst::AttCommand::ATT_OP_READ_BY_TYPE_REQUEST);
putBtData(nextHandle, &packet[1]);
putBtData(serviceData->endHandle, &packet[3]);
putBtData(attributeType, &packet[5]);
@@ -1659,7 +1538,7 @@ void QLowEnergyControllerPrivateBluez::sendReadByTypeRequest(
Request request;
request.payload = data;
- request.command = ATT_OP_READ_BY_TYPE_REQUEST;
+ request.command = QBluezConst::AttCommand::ATT_OP_READ_BY_TYPE_REQUEST;
request.reference = QVariant::fromValue(serviceData);
request.reference2 = attributeType;
openRequests.enqueue(request);
@@ -1691,6 +1570,16 @@ void QLowEnergyControllerPrivateBluez::readServiceValues(
QSharedPointer<QLowEnergyServicePrivate> service = serviceList.value(serviceUuid);
+ if (service->mode == QLowEnergyService::SkipValueDiscovery) {
+ if (readCharacteristics) {
+ // -> continue with descriptor discovery
+ discoverServiceDescriptors(service->uuid);
+ } else {
+ service->setState(QLowEnergyService::RemoteServiceDiscovered);
+ }
+ return;
+ }
+
// pair.first -> target attribute
// pair.second -> context information for read request
QPair<QLowEnergyHandle, quint32> pair;
@@ -1735,14 +1624,14 @@ void QLowEnergyControllerPrivateBluez::readServiceValues(
discoverServiceDescriptors(service->uuid);
} else {
// characteristic w/o descriptors
- service->setState(QLowEnergyService::ServiceDiscovered);
+ service->setState(QLowEnergyService::RemoteServiceDiscovered);
}
return;
}
- for (int i = 0; i < targetHandles.count(); i++) {
+ for (qsizetype i = 0; i < targetHandles.size(); i++) {
pair = targetHandles.at(i);
- packet[0] = ATT_OP_READ_REQUEST;
+ packet[0] = static_cast<quint8>(QBluezConst::AttCommand::ATT_OP_READ_REQUEST);
putBtData(pair.first, &packet[1]);
QByteArray data(READ_REQUEST_HEADER_SIZE, Qt::Uninitialized);
@@ -1750,10 +1639,10 @@ void QLowEnergyControllerPrivateBluez::readServiceValues(
Request request;
request.payload = data;
- request.command = ATT_OP_READ_REQUEST;
+ request.command = QBluezConst::AttCommand::ATT_OP_READ_REQUEST;
request.reference = pair.second;
// last entry?
- request.reference2 = QVariant((bool)(i + 1 == targetHandles.count()));
+ request.reference2 = QVariant((bool)(i + 1 == targetHandles.size()));
openRequests.enqueue(request);
}
@@ -1777,7 +1666,7 @@ void QLowEnergyControllerPrivateBluez::readServiceValuesByOffset(
const QLowEnergyHandle descriptorHandle = ((handleData >> 16) & 0xffff);
QByteArray data(READ_BLOB_REQUEST_HEADER_SIZE, Qt::Uninitialized);
- data[0] = ATT_OP_READ_BLOB_REQUEST;
+ data[0] = static_cast<quint8>(QBluezConst::AttCommand::ATT_OP_READ_BLOB_REQUEST);
QLowEnergyHandle handleToRead = charHandle;
if (descriptorHandle) {
@@ -1803,7 +1692,7 @@ void QLowEnergyControllerPrivateBluez::readServiceValuesByOffset(
Request request;
request.payload = data;
- request.command = ATT_OP_READ_BLOB_REQUEST;
+ request.command = QBluezConst::AttCommand::ATT_OP_READ_BLOB_REQUEST;
request.reference = handleData;
request.reference2 = isLastValue;
openRequests.prepend(request);
@@ -1818,7 +1707,7 @@ void QLowEnergyControllerPrivateBluez::discoverServiceDescriptors(
if (service->characteristicList.isEmpty()) { // service has no characteristics
// implies that characteristic & descriptor discovery can be skipped
- service->setState(QLowEnergyService::ServiceDiscovered);
+ service->setState(QLowEnergyService::RemoteServiceDiscovered);
return;
}
@@ -1832,7 +1721,8 @@ void QLowEnergyControllerPrivateBluez::discoverServiceDescriptors(
void QLowEnergyControllerPrivateBluez::processUnsolicitedReply(const QByteArray &payload)
{
const char *data = payload.constData();
- bool isNotification = (data[0] == ATT_OP_HANDLE_VAL_NOTIFICATION);
+ bool isNotification = (static_cast<QBluezConst::AttCommand>(data[0])
+ == QBluezConst::AttCommand::ATT_OP_HANDLE_VAL_NOTIFICATION);
const QLowEnergyHandle changedHandle = bt_get_le16(&data[1]);
if (QT_BT_BLUEZ().isDebugEnabled()) {
@@ -1858,15 +1748,15 @@ void QLowEnergyControllerPrivateBluez::exchangeMTU()
qCDebug(QT_BT_BLUEZ) << "Exchanging MTU";
quint8 packet[MTU_EXCHANGE_HEADER_SIZE];
- packet[0] = ATT_OP_EXCHANGE_MTU_REQUEST;
- putBtData(quint16(ATT_MAX_LE_MTU), &packet[1]);
+ packet[0] = static_cast<quint8>(QBluezConst::AttCommand::ATT_OP_EXCHANGE_MTU_REQUEST);
+ putBtData(ATT_MAX_LE_MTU, &packet[1]);
QByteArray data(MTU_EXCHANGE_HEADER_SIZE, Qt::Uninitialized);
memcpy(data.data(), packet, MTU_EXCHANGE_HEADER_SIZE);
Request request;
request.payload = data;
- request.command = ATT_OP_EXCHANGE_MTU_REQUEST;
+ request.command = QBluezConst::AttCommand::ATT_OP_EXCHANGE_MTU_REQUEST;
openRequests.enqueue(request);
sendNextPendingRequest();
@@ -1904,7 +1794,7 @@ int QLowEnergyControllerPrivateBluez::securityLevel() const
if (optval & L2CAP_LM_SECURE)
level = BT_SECURITY_HIGH;
- qDebug() << "Current l2cp sec level (old):" << level;
+ qCDebug(QT_BT_BLUEZ) << "Current l2cp sec level (old):" << level;
return level;
}
@@ -1951,7 +1841,7 @@ bool QLowEnergyControllerPrivateBluez::setSecurityLevel(int level)
}
if (setsockopt(socket, SOL_L2CAP, L2CAP_LM, &optval, sizeof(optval)) == 0) {
- qDebug(QT_BT_BLUEZ) << "Old l2cp sec level:" << optval;
+ qCDebug(QT_BT_BLUEZ) << "Old l2cp sec level:" << optval;
return true;
}
@@ -1970,11 +1860,11 @@ void QLowEnergyControllerPrivateBluez::discoverNextDescriptor(
<< pendingCharHandles << startingHandle;
quint8 packet[FIND_INFO_REQUEST_HEADER_SIZE];
- packet[0] = ATT_OP_FIND_INFORMATION_REQUEST;
+ packet[0] = static_cast<quint8>(QBluezConst::AttCommand::ATT_OP_FIND_INFORMATION_REQUEST);
const QLowEnergyHandle charStartHandle = startingHandle;
QLowEnergyHandle charEndHandle = 0;
- if (pendingCharHandles.count() == 1) //single characteristic
+ if (pendingCharHandles.size() == 1) //single characteristic
charEndHandle = serviceData->endHandle;
else
charEndHandle = pendingCharHandles[1] - 1;
@@ -1987,7 +1877,7 @@ void QLowEnergyControllerPrivateBluez::discoverNextDescriptor(
Request request;
request.payload = data;
- request.command = ATT_OP_FIND_INFORMATION_REQUEST;
+ request.command = QBluezConst::AttCommand::ATT_OP_FIND_INFORMATION_REQUEST;
request.reference = QVariant::fromValue<QList<QLowEnergyHandle> >(pendingCharHandles);
request.reference2 = startingHandle;
openRequests.enqueue(request);
@@ -2014,7 +1904,7 @@ void QLowEnergyControllerPrivateBluez::sendNextPrepareWriteRequest(
}
quint8 packet[PREPARE_WRITE_HEADER_SIZE];
- packet[0] = ATT_OP_PREPARE_WRITE_REQUEST;
+ packet[0] = static_cast<quint8>(QBluezConst::AttCommand::ATT_OP_PREPARE_WRITE_REQUEST);
putBtData(targetHandle, &packet[1]); // attribute handle
putBtData(offset, &packet[3]); // offset into newValue
@@ -2022,9 +1912,9 @@ void QLowEnergyControllerPrivateBluez::sendNextPrepareWriteRequest(
<< Qt::hex << handle;
- const int maxAvailablePayload = mtuSize - PREPARE_WRITE_HEADER_SIZE;
- const int requiredPayload = qMin(newValue.size() - offset, maxAvailablePayload);
- const int dataSize = PREPARE_WRITE_HEADER_SIZE + requiredPayload;
+ const qsizetype maxAvailablePayload = qsizetype(mtuSize) - PREPARE_WRITE_HEADER_SIZE;
+ const qsizetype requiredPayload = (std::min)(newValue.size() - offset, maxAvailablePayload);
+ const qsizetype dataSize = PREPARE_WRITE_HEADER_SIZE + requiredPayload;
Q_ASSERT((offset + requiredPayload) <= newValue.size());
Q_ASSERT(dataSize <= mtuSize);
@@ -2036,7 +1926,7 @@ void QLowEnergyControllerPrivateBluez::sendNextPrepareWriteRequest(
Request request;
request.payload = data;
- request.command = ATT_OP_PREPARE_WRITE_REQUEST;
+ request.command = QBluezConst::AttCommand::ATT_OP_PREPARE_WRITE_REQUEST;
request.reference = (handle | ((offset + requiredPayload) << 16));
request.reference2 = newValue;
openRequests.enqueue(request);
@@ -2055,7 +1945,7 @@ void QLowEnergyControllerPrivateBluez::sendExecuteWriteRequest(
bool isCancelation)
{
quint8 packet[EXECUTE_WRITE_HEADER_SIZE];
- packet[0] = ATT_OP_EXECUTE_WRITE_REQUEST;
+ packet[0] = static_cast<quint8>(QBluezConst::AttCommand::ATT_OP_EXECUTE_WRITE_REQUEST);
if (isCancelation)
packet[1] = 0x00; // cancel pending write prepare requests
else
@@ -2069,7 +1959,7 @@ void QLowEnergyControllerPrivateBluez::sendExecuteWriteRequest(
Request request;
request.payload = data;
- request.command = ATT_OP_EXECUTE_WRITE_REQUEST;
+ request.command = QBluezConst::AttCommand::ATT_OP_EXECUTE_WRITE_REQUEST;
request.reference = (attrHandle | ((isCancelation ? 0x00 : 0x01) << 16));
request.reference2 = newValue;
openRequests.prepend(request);
@@ -2137,7 +2027,7 @@ void QLowEnergyControllerPrivateBluez::readCharacteristic(
}
quint8 packet[READ_REQUEST_HEADER_SIZE];
- packet[0] = ATT_OP_READ_REQUEST;
+ packet[0] = static_cast<quint8>(QBluezConst::AttCommand::ATT_OP_READ_REQUEST);
putBtData(charDetails.valueHandle, &packet[1]);
QByteArray data(READ_REQUEST_HEADER_SIZE, Qt::Uninitialized);
@@ -2147,10 +2037,10 @@ void QLowEnergyControllerPrivateBluez::readCharacteristic(
Request request;
request.payload = data;
- request.command = ATT_OP_READ_REQUEST;
+ request.command = QBluezConst::AttCommand::ATT_OP_READ_REQUEST;
request.reference = charHandle;
// reference2 not really required but false prevents service discovery
- // code from running in ATT_OP_READ_RESPONSE handler
+ // code from running in QBluezConst::AttCommand::ATT_OP_READ_RESPONSE handler
request.reference2 = false;
openRequests.enqueue(request);
@@ -2172,7 +2062,7 @@ void QLowEnergyControllerPrivateBluez::readDescriptor(
return;
quint8 packet[READ_REQUEST_HEADER_SIZE];
- packet[0] = ATT_OP_READ_REQUEST;
+ packet[0] = static_cast<quint8>(QBluezConst::AttCommand::ATT_OP_READ_REQUEST);
putBtData(descriptorHandle, &packet[1]);
QByteArray data(READ_REQUEST_HEADER_SIZE, Qt::Uninitialized);
@@ -2182,10 +2072,10 @@ void QLowEnergyControllerPrivateBluez::readDescriptor(
Request request;
request.payload = data;
- request.command = ATT_OP_READ_REQUEST;
+ request.command = QBluezConst::AttCommand::ATT_OP_READ_REQUEST;
request.reference = (charHandle | (descriptorHandle << 16));
// reference2 not really required but false prevents service discovery
- // code from running in ATT_OP_READ_RESPONSE handler
+ // code from running in QBluezConst::AttCommand::ATT_OP_READ_RESPONSE handler
request.reference2 = false;
openRequests.enqueue(request);
@@ -2196,18 +2086,19 @@ void QLowEnergyControllerPrivateBluez::readDescriptor(
* Returns true if the encryption change was successfully requested.
* The request is triggered if we got a related ATT error.
*/
-bool QLowEnergyControllerPrivateBluez::increaseEncryptLevelfRequired(quint8 errorCode)
+bool QLowEnergyControllerPrivateBluez::increaseEncryptLevelfRequired(
+ QBluezConst::AttError errorCode)
{
if (securityLevelValue == BT_SECURITY_HIGH)
return false;
switch (errorCode) {
- case ATT_ERROR_INSUF_ENCRYPTION:
- case ATT_ERROR_INSUF_AUTHENTICATION:
- case ATT_ERROR_INSUF_ENCR_KEY_SIZE:
+ case QBluezConst::AttError::ATT_ERROR_INSUF_ENCRYPTION:
+ case QBluezConst::AttError::ATT_ERROR_INSUF_AUTHENTICATION:
+ case QBluezConst::AttError::ATT_ERROR_INSUF_ENCR_KEY_SIZE:
if (!hciManager->isValid())
return false;
- if (!hciManager->monitorEvent(HciManager::EncryptChangeEvent))
+ if (!hciManager->monitorEvent(HciManager::HciEvent::EVT_ENCRYPT_CHANGE))
return false;
if (securityLevelValue != BT_SECURITY_HIGH) {
qCDebug(QT_BT_BLUEZ) << "Requesting encrypted link";
@@ -2236,11 +2127,12 @@ bool QLowEnergyControllerPrivateBluez::checkPacketSize(const QByteArray &packet,
{
if (maxSize == -1)
maxSize = minSize;
- if (Q_LIKELY(packet.count() >= minSize && packet.count() <= maxSize))
+ if (Q_LIKELY(packet.size() >= minSize && packet.size() <= maxSize))
return true;
qCWarning(QT_BT_BLUEZ) << "client request of type" << packet.at(0)
- << "has unexpected packet size" << packet.count();
- sendErrorResponse(packet.at(0), 0, ATT_ERROR_INVALID_PDU);
+ << "has unexpected packet size" << packet.size();
+ sendErrorResponse(static_cast<QBluezConst::AttCommand>(packet.at(0)), 0,
+ QBluezConst::AttError::ATT_ERROR_INVALID_PDU);
return false;
}
@@ -2248,16 +2140,18 @@ bool QLowEnergyControllerPrivateBluez::checkHandle(const QByteArray &packet, QLo
{
if (handle != 0 && handle <= lastLocalHandle)
return true;
- sendErrorResponse(packet.at(0), handle, ATT_ERROR_INVALID_HANDLE);
+ sendErrorResponse(static_cast<QBluezConst::AttCommand>(packet.at(0)), handle,
+ QBluezConst::AttError::ATT_ERROR_INVALID_HANDLE);
return false;
}
-bool QLowEnergyControllerPrivateBluez::checkHandlePair(quint8 request, QLowEnergyHandle startingHandle,
- QLowEnergyHandle endingHandle)
+bool QLowEnergyControllerPrivateBluez::checkHandlePair(QBluezConst::AttCommand request,
+ QLowEnergyHandle startingHandle,
+ QLowEnergyHandle endingHandle)
{
if (startingHandle == 0 || startingHandle > endingHandle) {
qCDebug(QT_BT_BLUEZ) << "handle range invalid";
- sendErrorResponse(request, startingHandle, ATT_ERROR_INVALID_HANDLE);
+ sendErrorResponse(request, startingHandle, QBluezConst::AttError::ATT_ERROR_INVALID_HANDLE);
return false;
}
return true;
@@ -2271,20 +2165,21 @@ void QLowEnergyControllerPrivateBluez::handleExchangeMtuRequest(const QByteArray
return;
if (receivedMtuExchangeRequest) { // Client must only send this once per connection.
qCDebug(QT_BT_BLUEZ) << "Client sent extraneous MTU exchange packet";
- sendErrorResponse(packet.at(0), 0, ATT_ERROR_REQUEST_NOT_SUPPORTED);
+ sendErrorResponse(static_cast<QBluezConst::AttCommand>(packet.at(0)), 0,
+ QBluezConst::AttError::ATT_ERROR_REQUEST_NOT_SUPPORTED);
return;
}
receivedMtuExchangeRequest = true;
// Send reply.
QByteArray reply(MTU_EXCHANGE_HEADER_SIZE, Qt::Uninitialized);
- reply[0] = ATT_OP_EXCHANGE_MTU_RESPONSE;
- putBtData(static_cast<quint16>(ATT_MAX_LE_MTU), reply.data() + 1);
+ reply[0] = static_cast<quint8>(QBluezConst::AttCommand::ATT_OP_EXCHANGE_MTU_RESPONSE);
+ putBtData(ATT_MAX_LE_MTU, reply.data() + 1);
sendPacket(reply);
// Apply requested MTU.
const quint16 clientRxMtu = bt_get_le16(packet.constData() + 1);
- mtuSize = qMax<quint16>(ATT_DEFAULT_LE_MTU, qMin<quint16>(clientRxMtu, ATT_MAX_LE_MTU));
+ mtuSize = std::clamp(clientRxMtu, ATT_DEFAULT_LE_MTU, ATT_MAX_LE_MTU);
qCDebug(QT_BT_BLUEZ) << "MTU request from client:" << clientRxMtu
<< "effective client RX MTU:" << mtuSize;
qCDebug(QT_BT_BLUEZ) << "Sending server RX MTU" << ATT_MAX_LE_MTU;
@@ -2300,19 +2195,22 @@ void QLowEnergyControllerPrivateBluez::handleFindInformationRequest(const QByteA
const QLowEnergyHandle endingHandle = bt_get_le16(packet.constData() + 3);
qCDebug(QT_BT_BLUEZ) << "client sends find information request; start:" << startingHandle
<< "end:" << endingHandle;
- if (!checkHandlePair(packet.at(0), startingHandle, endingHandle))
+ if (!checkHandlePair(static_cast<QBluezConst::AttCommand>(packet.at(0)), startingHandle,
+ endingHandle))
return;
- QVector<Attribute> results = getAttributes(startingHandle, endingHandle);
+ QList<Attribute> results = getAttributes(startingHandle, endingHandle);
if (results.isEmpty()) {
- sendErrorResponse(packet.at(0), startingHandle, ATT_ERROR_ATTRIBUTE_NOT_FOUND);
+ sendErrorResponse(static_cast<QBluezConst::AttCommand>(packet.at(0)), startingHandle,
+ QBluezConst::AttError::ATT_ERROR_ATTRIBUTE_NOT_FOUND);
return;
}
ensureUniformUuidSizes(results);
QByteArray responsePrefix(2, Qt::Uninitialized);
const int uuidSize = getUuidSize(results.first().type);
- responsePrefix[0] = ATT_OP_FIND_INFORMATION_RESPONSE;
+ responsePrefix[0] =
+ static_cast<quint8>(QBluezConst::AttCommand::ATT_OP_FIND_INFORMATION_RESPONSE);
responsePrefix[1] = uuidSize == 2 ? 0x1 : 0x2;
const int elementSize = sizeof(QLowEnergyHandle) + uuidSize;
const auto elemWriter = [](const Attribute &attr, char *&data) {
@@ -2332,24 +2230,27 @@ void QLowEnergyControllerPrivateBluez::handleFindByTypeValueRequest(const QByteA
const QLowEnergyHandle startingHandle = bt_get_le16(packet.constData() + 1);
const QLowEnergyHandle endingHandle = bt_get_le16(packet.constData() + 3);
const quint16 type = bt_get_le16(packet.constData() + 5);
- const QByteArray value = QByteArray::fromRawData(packet.constData() + 7, packet.count() - 7);
+ const QByteArray value = QByteArray::fromRawData(packet.constData() + 7, packet.size() - 7);
qCDebug(QT_BT_BLUEZ) << "client sends find by type value request; start:" << startingHandle
<< "end:" << endingHandle << "type:" << type
<< "value:" << value.toHex();
- if (!checkHandlePair(packet.at(0), startingHandle, endingHandle))
+ if (!checkHandlePair(static_cast<QBluezConst::AttCommand>(packet.at(0)), startingHandle,
+ endingHandle))
return;
const auto predicate = [value, this, type](const Attribute &attr) {
return attr.type == QBluetoothUuid(type) && attr.value == value
- && checkReadPermissions(attr) == 0;
+ && checkReadPermissions(attr) == QBluezConst::AttError::ATT_ERROR_NO_ERROR;
};
- const QVector<Attribute> results = getAttributes(startingHandle, endingHandle, predicate);
+ const QList<Attribute> results = getAttributes(startingHandle, endingHandle, predicate);
if (results.isEmpty()) {
- sendErrorResponse(packet.at(0), startingHandle, ATT_ERROR_ATTRIBUTE_NOT_FOUND);
+ sendErrorResponse(static_cast<QBluezConst::AttCommand>(packet.at(0)), startingHandle,
+ QBluezConst::AttError::ATT_ERROR_ATTRIBUTE_NOT_FOUND);
return;
}
- QByteArray responsePrefix(1, ATT_OP_FIND_BY_TYPE_VALUE_RESPONSE);
+ QByteArray responsePrefix(
+ 1, static_cast<quint8>(QBluezConst::AttCommand::ATT_OP_FIND_BY_TYPE_VALUE_RESPONSE));
const int elemSize = 2 * sizeof(QLowEnergyHandle);
const auto elemWriter = [](const Attribute &attr, char *&data) {
putDataAndIncrement(attr.handle, data);
@@ -2367,42 +2268,47 @@ void QLowEnergyControllerPrivateBluez::handleReadByTypeRequest(const QByteArray
const QLowEnergyHandle startingHandle = bt_get_le16(packet.constData() + 1);
const QLowEnergyHandle endingHandle = bt_get_le16(packet.constData() + 3);
const void * const typeStart = packet.constData() + 5;
- const bool is16BitUuid = packet.count() == 7;
- const bool is128BitUuid = packet.count() == 21;
+ const bool is16BitUuid = packet.size() == 7;
+ const bool is128BitUuid = packet.size() == 21;
QBluetoothUuid type;
if (is16BitUuid) {
type = QBluetoothUuid(bt_get_le16(typeStart));
} else if (is128BitUuid) {
- type = QBluetoothUuid(convert_uuid128(reinterpret_cast<const quint128 *>(typeStart)));
+ type = QUuid::fromBytes(typeStart, QSysInfo::LittleEndian);
} else {
- qCWarning(QT_BT_BLUEZ) << "read by type request has invalid packet size" << packet.count();
- sendErrorResponse(packet.at(0), 0, ATT_ERROR_INVALID_PDU);
+ qCWarning(QT_BT_BLUEZ) << "read by type request has invalid packet size" << packet.size();
+ sendErrorResponse(static_cast<QBluezConst::AttCommand>(packet.at(0)), 0,
+ QBluezConst::AttError::ATT_ERROR_INVALID_PDU);
return;
}
qCDebug(QT_BT_BLUEZ) << "client sends read by type request, start:" << startingHandle
<< "end:" << endingHandle << "type:" << type;
- if (!checkHandlePair(packet.at(0), startingHandle, endingHandle))
+ if (!checkHandlePair(static_cast<QBluezConst::AttCommand>(packet.at(0)), startingHandle,
+ endingHandle))
return;
// Get all attributes with matching type.
- QVector<Attribute> results = getAttributes(startingHandle, endingHandle,
- [type](const Attribute &attr) { return attr.type == type; });
+ QList<Attribute> results =
+ getAttributes(startingHandle, endingHandle,
+ [type](const Attribute &attr) { return attr.type == type; });
ensureUniformValueSizes(results);
if (results.isEmpty()) {
- sendErrorResponse(packet.at(0), startingHandle, ATT_ERROR_ATTRIBUTE_NOT_FOUND);
+ sendErrorResponse(static_cast<QBluezConst::AttCommand>(packet.at(0)), startingHandle,
+ QBluezConst::AttError::ATT_ERROR_ATTRIBUTE_NOT_FOUND);
return;
}
- const int error = checkReadPermissions(results);
- if (error) {
- sendErrorResponse(packet.at(0), results.first().handle, error);
+ const QBluezConst::AttError error = checkReadPermissions(results);
+ if (error != QBluezConst::AttError::ATT_ERROR_NO_ERROR) {
+ sendErrorResponse(static_cast<QBluezConst::AttCommand>(packet.at(0)),
+ results.first().handle, error);
return;
}
- const int elementSize = sizeof(QLowEnergyHandle) + results.first().value.count();
+ const qsizetype elementSize = sizeof(QLowEnergyHandle) + results.first().value.size();
QByteArray responsePrefix(2, Qt::Uninitialized);
- responsePrefix[0] = ATT_OP_READ_BY_TYPE_RESPONSE;
+ responsePrefix[0] = static_cast<quint8>(QBluezConst::AttCommand::ATT_OP_READ_BY_TYPE_RESPONSE);
responsePrefix[1] = elementSize;
const auto elemWriter = [](const Attribute &attr, char *&data) {
putDataAndIncrement(attr.handle, data);
@@ -2423,15 +2329,16 @@ void QLowEnergyControllerPrivateBluez::handleReadRequest(const QByteArray &packe
if (!checkHandle(packet, handle))
return;
const Attribute &attribute = localAttributes.at(handle);
- const int permissionsError = checkReadPermissions(attribute);
- if (permissionsError) {
- sendErrorResponse(packet.at(0), handle, permissionsError);
+ const QBluezConst::AttError permissionsError = checkReadPermissions(attribute);
+ if (permissionsError != QBluezConst::AttError::ATT_ERROR_NO_ERROR) {
+ sendErrorResponse(static_cast<QBluezConst::AttCommand>(packet.at(0)), handle,
+ permissionsError);
return;
}
- const int sentValueLength = qMin(attribute.value.count(), mtuSize - 1);
+ const qsizetype sentValueLength = (std::min)(attribute.value.size(), qsizetype(mtuSize) - 1);
QByteArray response(1 + sentValueLength, Qt::Uninitialized);
- response[0] = ATT_OP_READ_RESPONSE;
+ response[0] = static_cast<quint8>(QBluezConst::AttCommand::ATT_OP_READ_RESPONSE);
using namespace std;
memcpy(response.data() + 1, attribute.value.constData(), sentValueLength);
qCDebug(QT_BT_BLUEZ) << "sending response:" << response.toHex();
@@ -2452,25 +2359,29 @@ void QLowEnergyControllerPrivateBluez::handleReadBlobRequest(const QByteArray &p
if (!checkHandle(packet, handle))
return;
const Attribute &attribute = localAttributes.at(handle);
- const int permissionsError = checkReadPermissions(attribute);
- if (permissionsError) {
- sendErrorResponse(packet.at(0), handle, permissionsError);
+ const QBluezConst::AttError permissionsError = checkReadPermissions(attribute);
+ if (permissionsError != QBluezConst::AttError::ATT_ERROR_NO_ERROR) {
+ sendErrorResponse(static_cast<QBluezConst::AttCommand>(packet.at(0)), handle,
+ permissionsError);
return;
}
- if (valueOffset > attribute.value.count()) {
- sendErrorResponse(packet.at(0), handle, ATT_ERROR_INVALID_OFFSET);
+ if (valueOffset > attribute.value.size()) {
+ sendErrorResponse(static_cast<QBluezConst::AttCommand>(packet.at(0)), handle,
+ QBluezConst::AttError::ATT_ERROR_INVALID_OFFSET);
return;
}
- if (attribute.value.count() <= mtuSize - 3) {
- sendErrorResponse(packet.at(0), handle, ATT_ERROR_ATTRIBUTE_NOT_LONG);
+ if (attribute.value.size() <= mtuSize - 3) {
+ sendErrorResponse(static_cast<QBluezConst::AttCommand>(packet.at(0)), handle,
+ QBluezConst::AttError::ATT_ERROR_ATTRIBUTE_NOT_LONG);
return;
}
// Yes, this value can be zero.
- const int sentValueLength = qMin(attribute.value.count() - valueOffset, mtuSize - 1);
+ const qsizetype sentValueLength = (std::min)(attribute.value.size() - valueOffset,
+ qsizetype(mtuSize) - 1);
QByteArray response(1 + sentValueLength, Qt::Uninitialized);
- response[0] = ATT_OP_READ_BLOB_RESPONSE;
+ response[0] = static_cast<quint8>(QBluezConst::AttCommand::ATT_OP_READ_BLOB_RESPONSE);
using namespace std;
memcpy(response.data() + 1, attribute.value.constData() + valueOffset, sentValueLength);
qCDebug(QT_BT_BLUEZ) << "sending response:" << response.toHex();
@@ -2483,30 +2394,33 @@ void QLowEnergyControllerPrivateBluez::handleReadMultipleRequest(const QByteArra
if (!checkPacketSize(packet, 5, mtuSize))
return;
- QVector<QLowEnergyHandle> handles((packet.count() - 1) / sizeof(QLowEnergyHandle));
+ QList<QLowEnergyHandle> handles((packet.size() - 1) / sizeof(QLowEnergyHandle));
auto *packetPtr = reinterpret_cast<const QLowEnergyHandle *>(packet.constData() + 1);
- for (int i = 0; i < handles.count(); ++i, ++packetPtr)
+ for (qsizetype i = 0; i < handles.size(); ++i, ++packetPtr)
handles[i] = bt_get_le16(packetPtr);
qCDebug(QT_BT_BLUEZ) << "client sends read multiple request for handles" << handles;
const auto it = std::find_if(handles.constBegin(), handles.constEnd(),
[this](QLowEnergyHandle handle) { return handle >= lastLocalHandle; });
if (it != handles.constEnd()) {
- sendErrorResponse(packet.at(0), *it, ATT_ERROR_INVALID_HANDLE);
+ sendErrorResponse(static_cast<QBluezConst::AttCommand>(packet.at(0)), *it,
+ QBluezConst::AttError::ATT_ERROR_INVALID_HANDLE);
return;
}
- const QVector<Attribute> results = getAttributes(handles.first(), handles.last());
- QByteArray response(1, ATT_OP_READ_MULTIPLE_RESPONSE);
+ const QList<Attribute> results = getAttributes(handles.first(), handles.last());
+ QByteArray response(
+ 1, static_cast<quint8>(QBluezConst::AttCommand::ATT_OP_READ_MULTIPLE_RESPONSE));
for (const Attribute &attr : results) {
- const int error = checkReadPermissions(attr);
- if (error) {
- sendErrorResponse(packet.at(0), attr.handle, error);
+ const QBluezConst::AttError error = checkReadPermissions(attr);
+ if (error != QBluezConst::AttError::ATT_ERROR_NO_ERROR) {
+ sendErrorResponse(static_cast<QBluezConst::AttCommand>(packet.at(0)), attr.handle,
+ error);
return;
}
// Note: We do not abort if no more values fit into the packet, because we still have to
// report possible permission errors for the other handles.
- response += attr.value.left(mtuSize - response.count());
+ response += attr.value.left(mtuSize - response.size());
}
qCDebug(QT_BT_BLUEZ) << "sending response:" << response.toHex();
@@ -2521,48 +2435,54 @@ void QLowEnergyControllerPrivateBluez::handleReadByGroupTypeRequest(const QByteA
return;
const QLowEnergyHandle startingHandle = bt_get_le16(packet.constData() + 1);
const QLowEnergyHandle endingHandle = bt_get_le16(packet.constData() + 3);
- const bool is16BitUuid = packet.count() == 7;
- const bool is128BitUuid = packet.count() == 21;
+ const bool is16BitUuid = packet.size() == 7;
+ const bool is128BitUuid = packet.size() == 21;
const void * const typeStart = packet.constData() + 5;
QBluetoothUuid type;
if (is16BitUuid) {
type = QBluetoothUuid(bt_get_le16(typeStart));
} else if (is128BitUuid) {
- type = QBluetoothUuid(convert_uuid128(reinterpret_cast<const quint128 *>(typeStart)));
+ type = QUuid::fromBytes(typeStart, QSysInfo::LittleEndian);
} else {
qCWarning(QT_BT_BLUEZ) << "read by group type request has invalid packet size"
- << packet.count();
- sendErrorResponse(packet.at(0), 0, ATT_ERROR_INVALID_PDU);
+ << packet.size();
+ sendErrorResponse(static_cast<QBluezConst::AttCommand>(packet.at(0)), 0,
+ QBluezConst::AttError::ATT_ERROR_INVALID_PDU);
return;
}
qCDebug(QT_BT_BLUEZ) << "client sends read by group type request, start:" << startingHandle
<< "end:" << endingHandle << "type:" << type;
- if (!checkHandlePair(packet.at(0), startingHandle, endingHandle))
+ if (!checkHandlePair(static_cast<QBluezConst::AttCommand>(packet.at(0)), startingHandle,
+ endingHandle))
return;
if (type != QBluetoothUuid(static_cast<quint16>(GATT_PRIMARY_SERVICE))
&& type != QBluetoothUuid(static_cast<quint16>(GATT_SECONDARY_SERVICE))) {
- sendErrorResponse(packet.at(0), startingHandle, ATT_ERROR_UNSUPPRTED_GROUP_TYPE);
+ sendErrorResponse(static_cast<QBluezConst::AttCommand>(packet.at(0)), startingHandle,
+ QBluezConst::AttError::ATT_ERROR_UNSUPPRTED_GROUP_TYPE);
return;
}
- QVector<Attribute> results = getAttributes(startingHandle, endingHandle,
- [type](const Attribute &attr) { return attr.type == type; });
+ QList<Attribute> results =
+ getAttributes(startingHandle, endingHandle,
+ [type](const Attribute &attr) { return attr.type == type; });
if (results.isEmpty()) {
- sendErrorResponse(packet.at(0), startingHandle, ATT_ERROR_ATTRIBUTE_NOT_FOUND);
+ sendErrorResponse(static_cast<QBluezConst::AttCommand>(packet.at(0)), startingHandle,
+ QBluezConst::AttError::ATT_ERROR_ATTRIBUTE_NOT_FOUND);
return;
}
- const int error = checkReadPermissions(results);
- if (error) {
- sendErrorResponse(packet.at(0), results.first().handle, error);
+ const QBluezConst::AttError error = checkReadPermissions(results);
+ if (error != QBluezConst::AttError::ATT_ERROR_NO_ERROR) {
+ sendErrorResponse(static_cast<QBluezConst::AttCommand>(packet.at(0)),
+ results.first().handle, error);
return;
}
ensureUniformValueSizes(results);
- const int elementSize = 2 * sizeof(QLowEnergyHandle) + results.first().value.count();
+ const qsizetype elementSize = 2 * sizeof(QLowEnergyHandle) + results.first().value.size();
QByteArray responsePrefix(2, Qt::Uninitialized);
- responsePrefix[0] = ATT_OP_READ_BY_GROUP_RESPONSE;
+ responsePrefix[0] = static_cast<quint8>(QBluezConst::AttCommand::ATT_OP_READ_BY_GROUP_RESPONSE);
responsePrefix[1] = elementSize;
const auto elemWriter = [](const Attribute &attr, char *&data) {
putDataAndIncrement(attr.handle, data);
@@ -2579,7 +2499,7 @@ void QLowEnergyControllerPrivateBluez::updateLocalAttributeValue(
QLowEnergyDescriptor &descriptor)
{
localAttributes[handle].value = value;
- for (const auto &service : qAsConst(localServices)) {
+ for (const auto &service : std::as_const(localServices)) {
if (handle < service->startHandle || handle > service->endHandle)
continue;
for (auto charIt = service->characteristicList.begin();
@@ -2613,8 +2533,8 @@ void QLowEnergyControllerPrivateBluez::writeCharacteristicForPeripheral(
const QLowEnergyHandle valueHandle = charData.valueHandle;
Q_ASSERT(valueHandle <= lastLocalHandle);
Attribute &attribute = localAttributes[valueHandle];
- if (newValue.count() < attribute.minLength || newValue.count() > attribute.maxLength) {
- qCWarning(QT_BT_BLUEZ) << "ignoring value of invalid length" << newValue.count()
+ if (newValue.size() < attribute.minLength || newValue.size() > attribute.maxLength) {
+ qCWarning(QT_BT_BLUEZ) << "ignoring value of invalid length" << newValue.size()
<< "for attribute" << valueHandle;
return;
}
@@ -2625,14 +2545,14 @@ void QLowEnergyControllerPrivateBluez::writeCharacteristicForPeripheral(
= attribute.properties & QLowEnergyCharacteristic::Indicate;
if (!hasNotifyProperty && !hasIndicateProperty)
return;
- for (const QLowEnergyServicePrivate::DescData &desc : qAsConst(charData.descriptorList)) {
- if (desc.uuid != QBluetoothUuid::ClientCharacteristicConfiguration)
+ for (const QLowEnergyServicePrivate::DescData &desc : std::as_const(charData.descriptorList)) {
+ if (desc.uuid != QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration)
continue;
// Notify/indicate currently connected client.
const bool isConnected = state == QLowEnergyController::ConnectedState;
if (isConnected) {
- Q_ASSERT(desc.value.count() == 2);
+ Q_ASSERT(desc.value.size() == 2);
quint16 configValue = bt_get_le16(desc.value.constData());
if (isNotificationEnabled(configValue) && hasNotifyProperty) {
sendNotification(valueHandle);
@@ -2648,7 +2568,7 @@ void QLowEnergyControllerPrivateBluez::writeCharacteristicForPeripheral(
for (auto it = clientConfigData.begin(); it != clientConfigData.end(); ++it) {
if (isConnected && it.key() == remoteDevice.toUInt64())
continue;
- QVector<ClientConfigurationData> &configDataList = it.value();
+ QList<ClientConfigurationData> &configDataList = it.value();
for (ClientConfigurationData &configData : configDataList) {
if (configData.charValueHandle != valueHandle)
continue;
@@ -2669,9 +2589,9 @@ void QLowEnergyControllerPrivateBluez::writeCharacteristicForCentral(const QShar
const QByteArray &newValue,
QLowEnergyService::WriteMode mode)
{
- QByteArray packet(WRITE_REQUEST_HEADER_SIZE + newValue.count(), Qt::Uninitialized);
+ QByteArray packet(WRITE_REQUEST_HEADER_SIZE + newValue.size(), Qt::Uninitialized);
putBtData(valueHandle, packet.data() + 1);
- memcpy(packet.data() + 3, newValue.constData(), newValue.count());
+ memcpy(packet.data() + 3, newValue.constData(), newValue.size());
bool writeWithResponse = false;
switch (mode) {
case QLowEnergyService::WriteWithResponse:
@@ -2681,14 +2601,14 @@ void QLowEnergyControllerPrivateBluez::writeCharacteristicForCentral(const QShar
return;
}
// write value fits into single package
- packet[0] = ATT_OP_WRITE_REQUEST;
+ packet[0] = static_cast<quint8>(QBluezConst::AttCommand::ATT_OP_WRITE_REQUEST);
writeWithResponse = true;
break;
case QLowEnergyService::WriteWithoutResponse:
- packet[0] = ATT_OP_WRITE_COMMAND;
+ packet[0] = static_cast<quint8>(QBluezConst::AttCommand::ATT_OP_WRITE_COMMAND);
break;
case QLowEnergyService::WriteSigned:
- packet[0] = ATT_OP_SIGNED_WRITE_COMMAND;
+ packet[0] = static_cast<quint8>(QBluezConst::AttCommand::ATT_OP_SIGNED_WRITE_COMMAND);
if (!isBonded()) {
qCWarning(QT_BT_BLUEZ) << "signed write not possible: requires bond between devices";
service->setError(QLowEnergyService::CharacteristicWriteError);
@@ -2708,14 +2628,14 @@ void QLowEnergyControllerPrivateBluez::writeCharacteristicForCentral(const QShar
++signingDataIt.value().counter;
packet = LeCmacCalculator::createFullMessage(packet, signingDataIt.value().counter);
const quint64 mac = LeCmacCalculator().calculateMac(packet, signingDataIt.value().key);
- packet.resize(packet.count() + sizeof mac);
- putBtData(mac, packet.data() + packet.count() - sizeof mac);
+ packet.resize(packet.size() + sizeof mac);
+ putBtData(mac, packet.data() + packet.size() - sizeof mac);
storeSignCounter(LocalSigningKey);
break;
}
qCDebug(QT_BT_BLUEZ) << "Writing characteristic" << Qt::hex << charHandle
- << "(size:" << packet.count() << "with response:"
+ << "(size:" << packet.size() << "with response:"
<< (mode == QLowEnergyService::WriteWithResponse)
<< "signed:" << (mode == QLowEnergyService::WriteSigned) << ")";
@@ -2729,7 +2649,7 @@ void QLowEnergyControllerPrivateBluez::writeCharacteristicForCentral(const QShar
Request request;
request.payload = packet;
- request.command = ATT_OP_WRITE_REQUEST;
+ request.command = QBluezConst::AttCommand::ATT_OP_WRITE_REQUEST;
request.reference = charHandle;
request.reference2 = newValue;
openRequests.enqueue(request);
@@ -2745,8 +2665,8 @@ void QLowEnergyControllerPrivateBluez::writeDescriptorForPeripheral(
{
Q_ASSERT(descriptorHandle <= lastLocalHandle);
Attribute &attribute = localAttributes[descriptorHandle];
- if (newValue.count() < attribute.minLength || newValue.count() > attribute.maxLength) {
- qCWarning(QT_BT_BLUEZ) << "invalid value of size" << newValue.count()
+ if (newValue.size() < attribute.minLength || newValue.size() > attribute.maxLength) {
+ qCWarning(QT_BT_BLUEZ) << "invalid value of size" << newValue.size()
<< "for attribute" << descriptorHandle;
return;
}
@@ -2766,10 +2686,10 @@ void QLowEnergyControllerPrivateBluez::writeDescriptorForCentral(
}
quint8 packet[WRITE_REQUEST_HEADER_SIZE];
- packet[0] = ATT_OP_WRITE_REQUEST;
+ packet[0] = static_cast<quint8>(QBluezConst::AttCommand::ATT_OP_WRITE_REQUEST);
putBtData(descriptorHandle, &packet[1]);
- const int size = WRITE_REQUEST_HEADER_SIZE + newValue.size();
+ const qsizetype size = WRITE_REQUEST_HEADER_SIZE + newValue.size();
QByteArray data(size, Qt::Uninitialized);
memcpy(data.data(), packet, WRITE_REQUEST_HEADER_SIZE);
memcpy(&(data.data()[WRITE_REQUEST_HEADER_SIZE]), newValue.constData(), newValue.size());
@@ -2779,7 +2699,7 @@ void QLowEnergyControllerPrivateBluez::writeDescriptorForCentral(
Request request;
request.payload = data;
- request.command = ATT_OP_WRITE_REQUEST;
+ request.command = QBluezConst::AttCommand::ATT_OP_WRITE_REQUEST;
request.reference = (charHandle | (descriptorHandle << 16));
request.reference2 = newValue;
openRequests.enqueue(request);
@@ -2791,8 +2711,10 @@ void QLowEnergyControllerPrivateBluez::handleWriteRequestOrCommand(const QByteAr
{
// Spec v4.2, Vol 3, Part F, 3.4.5.1-3
- const bool isRequest = packet.at(0) == ATT_OP_WRITE_REQUEST;
- const bool isSigned = quint8(packet.at(0)) == quint8(ATT_OP_SIGNED_WRITE_COMMAND);
+ const bool isRequest = static_cast<QBluezConst::AttCommand>(packet.at(0))
+ == QBluezConst::AttCommand::ATT_OP_WRITE_REQUEST;
+ const bool isSigned = static_cast<QBluezConst::AttCommand>(packet.at(0))
+ == QBluezConst::AttCommand::ATT_OP_SIGNED_WRITE_COMMAND;
if (!checkPacketSize(packet, isSigned ? 15 : 3, mtuSize))
return;
const QLowEnergyHandle handle = bt_get_le16(packet.constData() + 1);
@@ -2806,9 +2728,10 @@ void QLowEnergyControllerPrivateBluez::handleWriteRequestOrCommand(const QByteAr
const QLowEnergyCharacteristic::PropertyType type = isRequest
? QLowEnergyCharacteristic::Write : isSigned
? QLowEnergyCharacteristic::WriteSigned : QLowEnergyCharacteristic::WriteNoResponse;
- const int permissionsError = checkPermissions(attribute, type);
- if (permissionsError) {
- sendErrorResponse(packet.at(0), handle, permissionsError);
+ const QBluezConst::AttError permissionsError = checkPermissions(attribute, type);
+ if (permissionsError != QBluezConst::AttError::ATT_ERROR_NO_ERROR) {
+ sendErrorResponse(static_cast<QBluezConst::AttCommand>(packet.at(0)), handle,
+ permissionsError);
return;
}
@@ -2828,7 +2751,7 @@ void QLowEnergyControllerPrivateBluez::handleWriteRequestOrCommand(const QByteAr
return;
}
- const quint32 signCounter = getBtData<quint32>(packet.data() + packet.count() - 12);
+ const quint32 signCounter = getBtData<quint32>(packet.data() + packet.size() - 12);
if (signCounter < signingDataIt.value().counter + 1) {
qCWarning(QT_BT_BLUEZ) << "Client's' sign counter" << signCounter
<< "not greater than local sign counter"
@@ -2837,8 +2760,8 @@ void QLowEnergyControllerPrivateBluez::handleWriteRequestOrCommand(const QByteAr
return;
}
- const quint64 macFromClient = getBtData<quint64>(packet.data() + packet.count() - 8);
- const bool signatureCorrect = verifyMac(packet.left(packet.count() - 12),
+ const quint64 macFromClient = getBtData<quint64>(packet.data() + packet.size() - 8);
+ const bool signatureCorrect = verifyMac(packet.left(packet.size() - 12),
signingDataIt.value().key, signCounter, macFromClient);
if (!signatureCorrect) {
qCWarning(QT_BT_BLUEZ) << "Signed Write packet has wrong signature, disconnecting";
@@ -2848,13 +2771,14 @@ void QLowEnergyControllerPrivateBluez::handleWriteRequestOrCommand(const QByteAr
signingDataIt.value().counter = signCounter;
storeSignCounter(RemoteSigningKey);
- valueLength = packet.count() - 15;
+ valueLength = packet.size() - 15;
} else {
- valueLength = packet.count() - 3;
+ valueLength = packet.size() - 3;
}
if (valueLength > attribute.maxLength) {
- sendErrorResponse(packet.at(0), handle, ATT_ERROR_INVAL_ATTR_VALUE_LEN);
+ sendErrorResponse(static_cast<QBluezConst::AttCommand>(packet.at(0)), handle,
+ QBluezConst::AttError::ATT_ERROR_INVAL_ATTR_VALUE_LEN);
return;
}
@@ -2869,7 +2793,8 @@ void QLowEnergyControllerPrivateBluez::handleWriteRequestOrCommand(const QByteAr
updateLocalAttributeValue(handle, value, characteristic, descriptor);
if (isRequest) {
- const QByteArray response = QByteArray(1, ATT_OP_WRITE_RESPONSE);
+ const QByteArray response =
+ QByteArray(1, static_cast<quint8>(QBluezConst::AttCommand::ATT_OP_WRITE_RESPONSE));
sendPacket(response);
}
@@ -2893,13 +2818,16 @@ void QLowEnergyControllerPrivateBluez::handlePrepareWriteRequest(const QByteArra
if (!checkHandle(packet, handle))
return;
const Attribute &attribute = localAttributes.at(handle);
- const int permissionsError = checkPermissions(attribute, QLowEnergyCharacteristic::Write);
- if (permissionsError) {
- sendErrorResponse(packet.at(0), handle, permissionsError);
+ const QBluezConst::AttError permissionsError =
+ checkPermissions(attribute, QLowEnergyCharacteristic::Write);
+ if (permissionsError != QBluezConst::AttError::ATT_ERROR_NO_ERROR) {
+ sendErrorResponse(static_cast<QBluezConst::AttCommand>(packet.at(0)), handle,
+ permissionsError);
return;
}
- if (openPrepareWriteRequests.count() >= maxPrepareQueueSize) {
- sendErrorResponse(packet.at(0), handle, ATT_ERROR_PREPARE_QUEUE_FULL);
+ if (openPrepareWriteRequests.size() >= maxPrepareQueueSize) {
+ sendErrorResponse(static_cast<QBluezConst::AttCommand>(packet.at(0)), handle,
+ QBluezConst::AttError::ATT_ERROR_PREPARE_QUEUE_FULL);
return;
}
@@ -2908,7 +2836,7 @@ void QLowEnergyControllerPrivateBluez::handlePrepareWriteRequest(const QByteArra
packet.mid(5));
QByteArray response = packet;
- response[0] = ATT_OP_PREPARE_WRITE_RESPONSE;
+ response[0] = static_cast<quint8>(QBluezConst::AttCommand::ATT_OP_PREPARE_WRITE_RESPONSE);
sendPacket(response);
}
@@ -2922,20 +2850,23 @@ void QLowEnergyControllerPrivateBluez::handleExecuteWriteRequest(const QByteArra
qCDebug(QT_BT_BLUEZ) << "client sends execute write request; flag is"
<< (cancel ? "cancel" : "flush");
- QVector<WriteRequest> requests = openPrepareWriteRequests;
+ QList<WriteRequest> requests = openPrepareWriteRequests;
openPrepareWriteRequests.clear();
- QVector<QLowEnergyCharacteristic> characteristics;
- QVector<QLowEnergyDescriptor> descriptors;
+ QList<QLowEnergyCharacteristic> characteristics;
+ QList<QLowEnergyDescriptor> descriptors;
if (!cancel) {
- for (const WriteRequest &request : qAsConst(requests)) {
+ for (const WriteRequest &request : std::as_const(requests)) {
Attribute &attribute = localAttributes[request.handle];
- if (request.valueOffset > attribute.value.count()) {
- sendErrorResponse(packet.at(0), request.handle, ATT_ERROR_INVALID_OFFSET);
+ if (request.valueOffset > attribute.value.size()) {
+ sendErrorResponse(static_cast<QBluezConst::AttCommand>(packet.at(0)),
+ request.handle, QBluezConst::AttError::ATT_ERROR_INVALID_OFFSET);
return;
}
const QByteArray newValue = attribute.value.left(request.valueOffset) + request.value;
- if (newValue.count() > attribute.maxLength) {
- sendErrorResponse(packet.at(0), request.handle, ATT_ERROR_INVAL_ATTR_VALUE_LEN);
+ if (newValue.size() > attribute.maxLength) {
+ sendErrorResponse(static_cast<QBluezConst::AttCommand>(packet.at(0)),
+ request.handle,
+ QBluezConst::AttError::ATT_ERROR_INVAL_ATTR_VALUE_LEN);
return;
}
QLowEnergyCharacteristic characteristic;
@@ -2952,36 +2883,42 @@ void QLowEnergyControllerPrivateBluez::handleExecuteWriteRequest(const QByteArra
}
}
- sendPacket(QByteArray(1, ATT_OP_EXECUTE_WRITE_RESPONSE));
+ sendPacket(QByteArray(
+ 1, static_cast<quint8>(QBluezConst::AttCommand::ATT_OP_EXECUTE_WRITE_RESPONSE)));
- for (const QLowEnergyCharacteristic &characteristic : qAsConst(characteristics))
+ for (const QLowEnergyCharacteristic &characteristic : std::as_const(characteristics))
emit characteristic.d_ptr->characteristicChanged(characteristic, characteristic.value());
- for (const QLowEnergyDescriptor &descriptor : qAsConst(descriptors))
+ for (const QLowEnergyDescriptor &descriptor : std::as_const(descriptors))
emit descriptor.d_ptr->descriptorWritten(descriptor, descriptor.value());
}
-void QLowEnergyControllerPrivateBluez::sendErrorResponse(quint8 request, quint16 handle, quint8 code)
+void QLowEnergyControllerPrivateBluez::sendErrorResponse(QBluezConst::AttCommand request,
+ quint16 handle, QBluezConst::AttError code)
{
// An ATT command never receives an error response.
- if (request == ATT_OP_WRITE_COMMAND || request == ATT_OP_SIGNED_WRITE_COMMAND)
+ if (request == QBluezConst::AttCommand::ATT_OP_WRITE_COMMAND
+ || request == QBluezConst::AttCommand::ATT_OP_SIGNED_WRITE_COMMAND)
return;
QByteArray packet(ERROR_RESPONSE_HEADER_SIZE, Qt::Uninitialized);
- packet[0] = ATT_OP_ERROR_RESPONSE;
- packet[1] = request;
+ packet[0] = static_cast<quint8>(QBluezConst::AttCommand::ATT_OP_ERROR_RESPONSE);
+ packet[1] = static_cast<quint8>(request);
putBtData(handle, packet.data() + 2);
- packet[4] = code;
- qCWarning(QT_BT_BLUEZ) << "sending error response; request:" << request << "handle:" << handle
- << "code:" << code;
+ packet[4] = static_cast<quint8>(code);
+ qCWarning(QT_BT_BLUEZ) << "sending error response; request:"
+ << request << "handle:" << handle
+ << "code:" << code;
sendPacket(packet);
}
-void QLowEnergyControllerPrivateBluez::sendListResponse(const QByteArray &packetStart, int elemSize,
- const QVector<Attribute> &attributes, const ElemWriter &elemWriter)
+void QLowEnergyControllerPrivateBluez::sendListResponse(const QByteArray &packetStart,
+ qsizetype elemSize,
+ const QList<Attribute> &attributes,
+ const ElemWriter &elemWriter)
{
- const int offset = packetStart.count();
- const int elemCount = qMin(attributes.count(), (mtuSize - offset) / elemSize);
- const int totalPacketSize = offset + elemCount * elemSize;
+ const qsizetype offset = packetStart.size();
+ const qsizetype elemCount = (std::min)(attributes.size(), (mtuSize - offset) / elemSize);
+ const qsizetype totalPacketSize = offset + elemCount * elemSize;
QByteArray response(totalPacketSize, Qt::Uninitialized);
using namespace std;
memcpy(response.data(), packetStart.constData(), offset);
@@ -2994,25 +2931,24 @@ void QLowEnergyControllerPrivateBluez::sendListResponse(const QByteArray &packet
void QLowEnergyControllerPrivateBluez::sendNotification(QLowEnergyHandle handle)
{
- sendNotificationOrIndication(ATT_OP_HANDLE_VAL_NOTIFICATION, handle);
+ sendNotificationOrIndication(QBluezConst::AttCommand::ATT_OP_HANDLE_VAL_NOTIFICATION, handle);
}
void QLowEnergyControllerPrivateBluez::sendIndication(QLowEnergyHandle handle)
{
Q_ASSERT(!indicationInFlight);
indicationInFlight = true;
- sendNotificationOrIndication(ATT_OP_HANDLE_VAL_INDICATION, handle);
+ sendNotificationOrIndication(QBluezConst::AttCommand::ATT_OP_HANDLE_VAL_INDICATION, handle);
}
-void QLowEnergyControllerPrivateBluez::sendNotificationOrIndication(
- quint8 opCode,
- QLowEnergyHandle handle)
+void QLowEnergyControllerPrivateBluez::sendNotificationOrIndication(QBluezConst::AttCommand opCode,
+ QLowEnergyHandle handle)
{
Q_ASSERT(handle <= lastLocalHandle);
const Attribute &attribute = localAttributes.at(handle);
- const int maxValueLength = qMin(attribute.value.count(), mtuSize - 3);
+ const qsizetype maxValueLength = (std::min)(attribute.value.size(), qsizetype(mtuSize) - 3);
QByteArray packet(3 + maxValueLength, Qt::Uninitialized);
- packet[0] = opCode;
+ packet[0] = static_cast<quint8>(opCode);
putBtData(handle, packet.data() + 1);
using namespace std;
memcpy(packet.data() + 3, attribute.value.constData(), maxValueLength);
@@ -3026,67 +2962,33 @@ void QLowEnergyControllerPrivateBluez::sendNextIndication()
sendIndication(scheduledIndications.takeFirst());
}
-static QString nameOfRemoteCentral(const QBluetoothAddress &peerAddress, const QBluetoothAddress &localAdapter)
+static QString nameOfRemoteCentral(const QBluetoothAddress &peerAddress)
{
const QString peerAddressString = peerAddress.toString();
- if (isBluez5()) {
- OrgFreedesktopDBusObjectManagerInterface manager(QStringLiteral("org.bluez"),
- QStringLiteral("/"),
- QDBusConnection::systemBus());
- QDBusPendingReply<ManagedObjectList> reply = manager.GetManagedObjects();
- reply.waitForFinished();
- if (reply.isError())
- return QString();
-
- ManagedObjectList managedObjectList = reply.value();
- for (ManagedObjectList::const_iterator it = managedObjectList.constBegin(); it != managedObjectList.constEnd(); ++it) {
- const InterfaceList &ifaceList = it.value();
-
- for (InterfaceList::const_iterator jt = ifaceList.constBegin(); jt != ifaceList.constEnd(); ++jt) {
- const QString &iface = jt.key();
- const QVariantMap &ifaceValues = jt.value();
-
- if (iface == QStringLiteral("org.bluez.Device1")) {
- if (ifaceValues.value(QStringLiteral("Address")).toString() == peerAddressString)
- return ifaceValues.value(QStringLiteral("Alias")).toString();
- }
- }
- }
+ initializeBluez5();
+ OrgFreedesktopDBusObjectManagerInterface manager(QStringLiteral("org.bluez"),
+ QStringLiteral("/"),
+ QDBusConnection::systemBus());
+ QDBusPendingReply<ManagedObjectList> reply = manager.GetManagedObjects();
+ reply.waitForFinished();
+ if (reply.isError())
return QString();
- } else {
- OrgBluezManagerInterface manager(QStringLiteral("org.bluez"), QStringLiteral("/"),
- QDBusConnection::systemBus());
-
- QDBusPendingReply<QDBusObjectPath> reply = manager.FindAdapter(localAdapter.toString());
- reply.waitForFinished();
- if (reply.isError())
- return QString();
-
- OrgBluezAdapterInterface adapter(QStringLiteral("org.bluez"), reply.value().path(),
- QDBusConnection::systemBus());
-
- QDBusPendingReply<QDBusObjectPath> deviceObjectPath = adapter.FindDevice(peerAddressString);
- deviceObjectPath.waitForFinished();
- if (deviceObjectPath.isError()) {
- if (deviceObjectPath.error().name() != QStringLiteral("org.bluez.Error.DoesNotExist"))
- return QString();
-
- deviceObjectPath = adapter.CreateDevice(peerAddressString);
- deviceObjectPath.waitForFinished();
- if (deviceObjectPath.isError())
- return QString();
- }
- OrgBluezDeviceInterface device(QStringLiteral("org.bluez"), deviceObjectPath.value().path(),
- QDBusConnection::systemBus());
+ ManagedObjectList managedObjectList = reply.value();
+ for (ManagedObjectList::const_iterator it = managedObjectList.constBegin(); it != managedObjectList.constEnd(); ++it) {
+ const InterfaceList &ifaceList = it.value();
- QDBusPendingReply<QVariantMap> properties = device.GetProperties();
- properties.waitForFinished();
- if (properties.isError())
- return QString();
+ for (InterfaceList::const_iterator jt = ifaceList.constBegin(); jt != ifaceList.constEnd(); ++jt) {
+ const QString &iface = jt.key();
+ const QVariantMap &ifaceValues = jt.value();
- return properties.value().value(QStringLiteral("Alias")).toString();
+ if (iface == QStringLiteral("org.bluez.Device1")) {
+ if (ifaceValues.value(QStringLiteral("Address")).toString() == peerAddressString)
+ return ifaceValues.value(QStringLiteral("Alias")).toString();
+ }
+ }
}
+ return QString();
}
void QLowEnergyControllerPrivateBluez::handleConnectionRequest()
@@ -3109,7 +3011,7 @@ void QLowEnergyControllerPrivateBluez::handleConnectionRequest()
}
remoteDevice = QBluetoothAddress(convertAddress(clientAddr.l2_bdaddr.b));
- remoteName = nameOfRemoteCentral(remoteDevice, localAdapter);
+ remoteName = nameOfRemoteCentral(remoteDevice);
qCDebug(QT_BT_BLUEZ) << "GATT connection from device" << remoteDevice << remoteName;
if (connectionHandle == 0)
@@ -3130,13 +3032,13 @@ void QLowEnergyControllerPrivateBluez::handleConnectionRequest()
rawSocketPrivate, QBluetoothServiceInfo::L2capProtocol, this);
connect(l2cpSocket, &QBluetoothSocket::disconnected,
this, &QLowEnergyControllerPrivateBluez::l2cpDisconnected);
- connect(l2cpSocket, static_cast<void (QBluetoothSocket::*)(QBluetoothSocket::SocketError)>
- (&QBluetoothSocket::error), this, &QLowEnergyControllerPrivateBluez::l2cpErrorChanged);
+ connect(l2cpSocket, &QBluetoothSocket::errorOccurred, this,
+ &QLowEnergyControllerPrivateBluez::l2cpErrorChanged);
connect(l2cpSocket, &QIODevice::readyRead, this, &QLowEnergyControllerPrivateBluez::l2cpReadyRead);
l2cpSocket->d_ptr->lowEnergySocketType = addressType == QLowEnergyController::PublicAddress
? BDADDR_LE_PUBLIC : BDADDR_LE_RANDOM;
l2cpSocket->setSocketDescriptor(clientSocket, QBluetoothServiceInfo::L2capProtocol,
- QBluetoothSocket::ConnectedState, QIODevice::ReadWrite | QIODevice::Unbuffered);
+ QBluetoothSocket::SocketState::ConnectedState, QIODevice::ReadWrite | QIODevice::Unbuffered);
restoreClientConfigurations();
loadSigningDataIfNecessary(RemoteSigningKey);
@@ -3163,17 +3065,18 @@ bool QLowEnergyControllerPrivateBluez::isBonded() const
!= QBluetoothLocalDevice::Unpaired;
}
-QVector<QLowEnergyControllerPrivateBluez::TempClientConfigurationData> QLowEnergyControllerPrivateBluez::gatherClientConfigData()
+QList<QLowEnergyControllerPrivateBluez::TempClientConfigurationData>
+QLowEnergyControllerPrivateBluez::gatherClientConfigData()
{
- QVector<TempClientConfigurationData> data;
- for (const auto &service : qAsConst(localServices)) {
+ QList<TempClientConfigurationData> data;
+ for (const auto &service : std::as_const(localServices)) {
for (auto charIt = service->characteristicList.begin();
charIt != service->characteristicList.end(); ++charIt) {
QLowEnergyServicePrivate::CharData &charData = charIt.value();
for (auto descIt = charData.descriptorList.begin();
descIt != charData.descriptorList.end(); ++descIt) {
QLowEnergyServicePrivate::DescData &descData = descIt.value();
- if (descData.uuid == QBluetoothUuid::ClientCharacteristicConfiguration) {
+ if (descData.uuid == QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration) {
data << TempClientConfigurationData(&descData, charData.valueHandle,
descIt.key());
break;
@@ -3190,10 +3093,10 @@ void QLowEnergyControllerPrivateBluez::storeClientConfigurations()
clientConfigData.remove(remoteDevice.toUInt64());
return;
}
- QVector<ClientConfigurationData> clientConfigs;
- const QVector<TempClientConfigurationData> &tempConfigList = gatherClientConfigData();
+ QList<ClientConfigurationData> clientConfigs;
+ const QList<TempClientConfigurationData> &tempConfigList = gatherClientConfigData();
for (const auto &tempConfigData : tempConfigList) {
- Q_ASSERT(tempConfigData.descData->value.count() == 2);
+ Q_ASSERT(tempConfigData.descData->value.size() == 2);
const quint16 value = bt_get_le16(tempConfigData.descData->value.constData());
if (value != 0) {
clientConfigs << ClientConfigurationData(tempConfigData.charValueHandle,
@@ -3205,15 +3108,16 @@ void QLowEnergyControllerPrivateBluez::storeClientConfigurations()
void QLowEnergyControllerPrivateBluez::restoreClientConfigurations()
{
- const QVector<TempClientConfigurationData> &tempConfigList = gatherClientConfigData();
- const QVector<ClientConfigurationData> &restoredClientConfigs = isBonded()
- ? clientConfigData.value(remoteDevice.toUInt64()) : QVector<ClientConfigurationData>();
- QVector<QLowEnergyHandle> notifications;
+ const QList<TempClientConfigurationData> &tempConfigList = gatherClientConfigData();
+ const QList<ClientConfigurationData> &restoredClientConfigs = isBonded()
+ ? clientConfigData.value(remoteDevice.toUInt64())
+ : QList<ClientConfigurationData>();
+ QList<QLowEnergyHandle> notifications;
for (const auto &tempConfigData : tempConfigList) {
bool wasRestored = false;
for (const auto &restoredData : restoredClientConfigs) {
if (restoredData.charValueHandle == tempConfigData.charValueHandle) {
- Q_ASSERT(tempConfigData.descData->value.count() == 2);
+ Q_ASSERT(tempConfigData.descData->value.size() == 2);
putBtData(restoredData.configValue, tempConfigData.descData->value.data());
wasRestored = true;
if (restoredData.charValueWasUpdated) {
@@ -3232,7 +3136,7 @@ void QLowEnergyControllerPrivateBluez::restoreClientConfigurations()
localAttributes[tempConfigData.configHandle].value = tempConfigData.descData->value;
}
- for (const QLowEnergyHandle handle : qAsConst(notifications))
+ for (const QLowEnergyHandle handle : std::as_const(notifications))
sendNotification(handle);
sendNextIndication();
}
@@ -3256,16 +3160,16 @@ void QLowEnergyControllerPrivateBluez::loadSigningDataIfNecessary(SigningKeyType
return;
}
const QByteArray keyData = QByteArray::fromHex(keyString);
- if (keyData.count() != int(sizeof(quint128))) {
+ if (keyData.size() != qsizetype(sizeof(BluezUint128))) {
qCWarning(QT_BT_BLUEZ) << "Signing key in settings file has invalid size"
- << keyString.count();
+ << keyString.size();
return;
}
qCDebug(QT_BT_BLUEZ) << "CSRK of peer device is" << keyString;
const quint32 counter = settings.value(QLatin1String("Counter"), 0).toUInt();
- quint128 csrk;
using namespace std;
- memcpy(csrk.data, keyData.constData(), keyData.count());
+ BluezUint128 csrk;
+ memcpy(csrk.data, keyData.constData(), keyData.size());
signingData.insert(remoteDevice.toUInt64(), SigningData(csrk, counter - 1));
}
@@ -3303,17 +3207,10 @@ QString QLowEnergyControllerPrivateBluez::keySettingsFilePath() const
static QByteArray uuidToByteArray(const QBluetoothUuid &uuid)
{
- QByteArray ba;
- if (uuid.minimumSize() == 2) {
- ba.resize(2);
- putBtData(uuid.toUInt16(), ba.data());
- } else {
- ba.resize(16);
- quint128 hostOrder;
- quint128 qtUuidOrder = uuid.toUInt128();
- ntoh128(&qtUuidOrder, &hostOrder);
- putBtData(hostOrder, ba.data());
- }
+ QByteArray ba(sizeof(uuid), Qt::Uninitialized);
+ char *ptr = ba.data();
+ putDataAndIncrement(uuid, ptr);
+ ba.resize(ptr - ba.constData());
return ba;
}
@@ -3352,7 +3249,7 @@ void QLowEnergyControllerPrivateBluez::addToGenericAttributeList(const QLowEnerg
// Characteristic declaration;
attribute.handle = ++currentHandle;
- attribute.groupEndHandle = attribute.handle + 1 + cd.descriptors().count();
+ attribute.groupEndHandle = attribute.handle + 1 + cd.descriptors().size();
attribute.type = QBluetoothUuid(GATT_CHARACTERISTIC);
attribute.properties = QLowEnergyCharacteristic::Read;
attribute.value.resize(1 + sizeof(QLowEnergyHandle) + cd.uuid().minimumSize());
@@ -3386,17 +3283,17 @@ void QLowEnergyControllerPrivateBluez::addToGenericAttributeList(const QLowEnerg
attribute.maxLength = INT_MAX;
// Spec v4.2, Vol. 3, Part G, 3.3.3.x
- if (attribute.type == QBluetoothUuid::CharacteristicExtendedProperties) {
+ if (attribute.type == QBluetoothUuid::DescriptorType::CharacteristicExtendedProperties) {
attribute.properties = QLowEnergyCharacteristic::Read;
attribute.minLength = attribute.maxLength = 2;
- } else if (attribute.type == QBluetoothUuid::CharacteristicPresentationFormat) {
+ } else if (attribute.type == QBluetoothUuid::DescriptorType::CharacteristicPresentationFormat) {
attribute.properties = QLowEnergyCharacteristic::Read;
attribute.minLength = attribute.maxLength = 7;
- } else if (attribute.type == QBluetoothUuid::CharacteristicAggregateFormat) {
+ } else if (attribute.type == QBluetoothUuid::DescriptorType::CharacteristicAggregateFormat) {
attribute.properties = QLowEnergyCharacteristic::Read;
attribute.minLength = 4;
- } else if (attribute.type == QBluetoothUuid::ClientCharacteristicConfiguration
- || attribute.type == QBluetoothUuid::ServerCharacteristicConfiguration) {
+ } else if (attribute.type == QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration
+ || attribute.type == QBluetoothUuid::DescriptorType::ServerCharacteristicConfiguration) {
attribute.properties = QLowEnergyCharacteristic::Read
| QLowEnergyCharacteristic::Write
| QLowEnergyCharacteristic::WriteNoResponse
@@ -3416,10 +3313,10 @@ void QLowEnergyControllerPrivateBluez::addToGenericAttributeList(const QLowEnerg
}
attribute.value = dd.value();
- if (attribute.value.count() < attribute.minLength
- || attribute.value.count() > attribute.maxLength) {
+ if (attribute.value.size() < attribute.minLength
+ || attribute.value.size() > attribute.maxLength) {
qCWarning(QT_BT_BLUEZ) << "attribute of type" << attribute.type
- << "has invalid length of" << attribute.value.count()
+ << "has invalid length of" << attribute.value.size()
<< "bytes";
attribute.value = QByteArray(attribute.minLength, 0);
}
@@ -3430,8 +3327,13 @@ void QLowEnergyControllerPrivateBluez::addToGenericAttributeList(const QLowEnerg
localAttributes[serviceAttribute.handle] = serviceAttribute;
}
-void QLowEnergyControllerPrivateBluez::ensureUniformAttributes(QVector<Attribute> &attributes,
- const std::function<int (const Attribute &)> &getSize)
+int QLowEnergyControllerPrivateBluez::mtu() const
+{
+ return mtuSize;
+}
+
+void QLowEnergyControllerPrivateBluez::ensureUniformAttributes(
+ QList<Attribute> &attributes, const std::function<int(const Attribute &)> &getSize)
{
if (attributes.isEmpty())
return;
@@ -3443,22 +3345,24 @@ void QLowEnergyControllerPrivateBluez::ensureUniformAttributes(QVector<Attribute
}
-void QLowEnergyControllerPrivateBluez::ensureUniformUuidSizes(QVector<Attribute> &attributes)
+void QLowEnergyControllerPrivateBluez::ensureUniformUuidSizes(QList<Attribute> &attributes)
{
ensureUniformAttributes(attributes,
[](const Attribute &attr) { return getUuidSize(attr.type); });
}
-void QLowEnergyControllerPrivateBluez::ensureUniformValueSizes(QVector<Attribute> &attributes)
+void QLowEnergyControllerPrivateBluez::ensureUniformValueSizes(QList<Attribute> &attributes)
{
ensureUniformAttributes(attributes,
- [](const Attribute &attr) { return attr.value.count(); });
+ [](const Attribute &attr) { return attr.value.size(); });
}
-QVector<QLowEnergyControllerPrivateBluez::Attribute> QLowEnergyControllerPrivateBluez::getAttributes(QLowEnergyHandle startHandle,
- QLowEnergyHandle endHandle, const AttributePredicate &attributePredicate)
+QList<QLowEnergyControllerPrivateBluez::Attribute>
+QLowEnergyControllerPrivateBluez::getAttributes(QLowEnergyHandle startHandle,
+ QLowEnergyHandle endHandle,
+ const AttributePredicate &attributePredicate)
{
- QVector<Attribute> results;
+ QList<Attribute> results;
if (startHandle > lastLocalHandle)
return results;
if (lastLocalHandle == 0) // We have no services at all.
@@ -3474,8 +3378,9 @@ QVector<QLowEnergyControllerPrivateBluez::Attribute> QLowEnergyControllerPrivate
return results;
}
-int QLowEnergyControllerPrivateBluez::checkPermissions(const Attribute &attr,
- QLowEnergyCharacteristic::PropertyType type)
+QBluezConst::AttError
+QLowEnergyControllerPrivateBluez::checkPermissions(const Attribute &attr,
+ QLowEnergyCharacteristic::PropertyType type)
{
const bool isReadAccess = type == QLowEnergyCharacteristic::Read;
const bool isWriteCommand = type == QLowEnergyCharacteristic::WriteNoResponse;
@@ -3485,7 +3390,7 @@ int QLowEnergyControllerPrivateBluez::checkPermissions(const Attribute &attr,
Q_ASSERT(isReadAccess || isWriteAccess);
if (!(attr.properties & type)) {
if (isReadAccess)
- return ATT_ERROR_READ_NOT_PERM;
+ return QBluezConst::AttError::ATT_ERROR_READ_NOT_PERM;
// The spec says: If an attribute requires a signed write, then a non-signed write command
// can also be used if the link is encrypted.
@@ -3493,47 +3398,53 @@ int QLowEnergyControllerPrivateBluez::checkPermissions(const Attribute &attr,
&& (attr.properties & QLowEnergyCharacteristic::WriteSigned)
&& securityLevel() >= BT_SECURITY_MEDIUM;
if (!unsignedWriteOk)
- return ATT_ERROR_WRITE_NOT_PERM;
+ return QBluezConst::AttError::ATT_ERROR_WRITE_NOT_PERM;
}
const AttAccessConstraints constraints = isReadAccess
? attr.readConstraints : attr.writeConstraints;
- if (constraints.testFlag(AttAuthorizationRequired))
- return ATT_ERROR_INSUF_AUTHORIZATION; // TODO: emit signal (and offer authorization function)?
- if (constraints.testFlag(AttEncryptionRequired) && securityLevel() < BT_SECURITY_MEDIUM)
- return ATT_ERROR_INSUF_ENCRYPTION;
- if (constraints.testFlag(AttAuthenticationRequired) && securityLevel() < BT_SECURITY_HIGH)
- return ATT_ERROR_INSUF_AUTHENTICATION;
+ if (constraints.testFlag(AttAccessConstraint::AttAuthorizationRequired))
+ return QBluezConst::AttError::ATT_ERROR_INSUF_AUTHORIZATION; // TODO: emit signal (and offer
+ // authorization function)?
+ if (constraints.testFlag(AttAccessConstraint::AttEncryptionRequired)
+ && securityLevel() < BT_SECURITY_MEDIUM)
+ return QBluezConst::AttError::ATT_ERROR_INSUF_ENCRYPTION;
+ if (constraints.testFlag(AttAccessConstraint::AttAuthenticationRequired)
+ && securityLevel() < BT_SECURITY_HIGH)
+ return QBluezConst::AttError::ATT_ERROR_INSUF_AUTHENTICATION;
if (false)
- return ATT_ERROR_INSUF_ENCR_KEY_SIZE;
- return 0;
+ return QBluezConst::AttError::ATT_ERROR_INSUF_ENCR_KEY_SIZE;
+ return QBluezConst::AttError::ATT_ERROR_NO_ERROR;
}
-int QLowEnergyControllerPrivateBluez::checkReadPermissions(const Attribute &attr)
+QBluezConst::AttError QLowEnergyControllerPrivateBluez::checkReadPermissions(const Attribute &attr)
{
return checkPermissions(attr, QLowEnergyCharacteristic::Read);
}
-int QLowEnergyControllerPrivateBluez::checkReadPermissions(QVector<Attribute> &attributes)
+QBluezConst::AttError
+QLowEnergyControllerPrivateBluez::checkReadPermissions(QList<Attribute> &attributes)
{
if (attributes.isEmpty())
- return 0;
+ return QBluezConst::AttError::ATT_ERROR_NO_ERROR;
// The logic prescribed in the spec is as follows:
// 1) If the first in a list of matching attributes has a permissions error,
// then that error is returned via an error response.
// 2) If any other element of that list would cause a permissions error, then all
// attributes from this one on are not part of the result set, but no error is returned.
- const int error = checkReadPermissions(attributes.first());
- if (error)
+ const QBluezConst::AttError error = checkReadPermissions(attributes.first());
+ if (error != QBluezConst::AttError::ATT_ERROR_NO_ERROR)
return error;
- const auto it = std::find_if(attributes.begin() + 1, attributes.end(),
- [this](const Attribute &attr) { return checkReadPermissions(attr) != 0; });
+ const auto it =
+ std::find_if(attributes.begin() + 1, attributes.end(), [this](const Attribute &attr) {
+ return checkReadPermissions(attr) != QBluezConst::AttError::ATT_ERROR_NO_ERROR;
+ });
if (it != attributes.end())
attributes.erase(it, attributes.end());
- return 0;
+ return QBluezConst::AttError::ATT_ERROR_NO_ERROR;
}
-bool QLowEnergyControllerPrivateBluez::verifyMac(const QByteArray &message, const quint128 &csrk,
+bool QLowEnergyControllerPrivateBluez::verifyMac(const QByteArray &message, BluezUint128 csrk,
quint32 signCounter, quint64 expectedMac)
{
if (!cmacCalculator)
@@ -3543,3 +3454,5 @@ bool QLowEnergyControllerPrivateBluez::verifyMac(const QByteArray &message, cons
}
QT_END_NAMESPACE
+
+#include "moc_qlowenergycontroller_bluez_p.cpp"
diff --git a/src/bluetooth/qlowenergycontroller_bluez_p.h b/src/bluetooth/qlowenergycontroller_bluez_p.h
index 65517cba..5c42ccd2 100644
--- a/src/bluetooth/qlowenergycontroller_bluez_p.h
+++ b/src/bluetooth/qlowenergycontroller_bluez_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QLOWENERGYCONTROLLERBLUEZ_P_H
#define QLOWENERGYCONTROLLERBLUEZ_P_H
@@ -52,12 +16,13 @@
//
#include <qglobal.h>
+#include <QtCore/QList>
#include <QtCore/QQueue>
-#include <QtCore/QVector>
#include <QtBluetooth/qbluetooth.h>
#include <QtBluetooth/qlowenergycharacteristic.h>
#include "qlowenergycontroller.h"
#include "qlowenergycontrollerbase_p.h"
+#include "bluez/bluez_data_p.h"
#include <QtBluetooth/QBluetoothSocket>
#include <functional>
@@ -89,7 +54,8 @@ public:
void disconnectFromDevice() override;
void discoverServices() override;
- void discoverServiceDetails(const QBluetoothUuid &service) override;
+ void discoverServiceDetails(const QBluetoothUuid &service,
+ QLowEnergyService::DiscoveryMode mode) override;
void startAdvertising(const QLowEnergyAdvertisingParameters &params,
const QLowEnergyAdvertisingData &advertisingData,
@@ -117,6 +83,8 @@ public:
void addToGenericAttributeList(const QLowEnergyServiceData &service,
QLowEnergyHandle startHandle) override;
+ int mtu() const override;
+
struct Attribute {
Attribute() : handle(0) {}
@@ -130,13 +98,13 @@ public:
int minLength;
int maxLength;
};
- QVector<Attribute> localAttributes;
+ QList<Attribute> localAttributes;
private:
quint16 connectionHandle = 0;
QBluetoothSocket *l2cpSocket = nullptr;
struct Request {
- quint8 command;
+ QBluezConst::AttCommand command;
QByteArray payload;
// TODO reference below is ugly but until we know all commands and their
// requirements this is WIP
@@ -153,10 +121,10 @@ private:
quint16 valueOffset;
QByteArray value;
};
- QVector<WriteRequest> openPrepareWriteRequests;
+ QList<WriteRequest> openPrepareWriteRequests;
// Invariant: !scheduledIndications.isEmpty => indicationInFlight == true
- QVector<QLowEnergyHandle> scheduledIndications;
+ QList<QLowEnergyHandle> scheduledIndications;
bool indicationInFlight = false;
struct TempClientConfigurationData {
@@ -179,14 +147,14 @@ private:
quint16 configValue;
bool charValueWasUpdated = false;
};
- QHash<quint64, QVector<ClientConfigurationData>> clientConfigData;
+ QHash<quint64, QList<ClientConfigurationData>> clientConfigData;
struct SigningData {
SigningData() = default;
- SigningData(const quint128 &csrk, quint32 signCounter = quint32(-1))
+ SigningData(BluezUint128 csrk, quint32 signCounter = quint32(-1))
: key(csrk), counter(signCounter) {}
- quint128 key;
+ BluezUint128 key;
quint32 counter = quint32(-1);
};
QHash<quint64, SigningData> signingData;
@@ -198,7 +166,7 @@ private:
bool encryptionChangePending;
bool receivedMtuExchangeRequest = false;
- HciManager *hciManager = nullptr;
+ std::shared_ptr<HciManager> hciManager;
QLeAdvertiser *advertiser = nullptr;
QSocketNotifier *serverSocketNotifier = nullptr;
QTimer *requestTimer = nullptr;
@@ -225,7 +193,7 @@ private:
void closeServerSocket();
bool isBonded() const;
- QVector<TempClientConfigurationData> gatherClientConfigData();
+ QList<TempClientConfigurationData> gatherClientConfigData();
void storeClientConfigurations();
void restoreClientConfigurations();
@@ -262,7 +230,7 @@ private:
bool isCancelation);
void sendNextPrepareWriteRequest(const QLowEnergyHandle handle,
const QByteArray &newValue, quint16 offset);
- bool increaseEncryptLevelfRequired(quint8 errorCode);
+ bool increaseEncryptLevelfRequired(QBluezConst::AttError errorCode);
void resetController();
@@ -270,7 +238,7 @@ private:
bool checkPacketSize(const QByteArray &packet, int minSize, int maxSize = -1);
bool checkHandle(const QByteArray &packet, QLowEnergyHandle handle);
- bool checkHandlePair(quint8 request, QLowEnergyHandle startingHandle,
+ bool checkHandlePair(QBluezConst::AttCommand request, QLowEnergyHandle startingHandle,
QLowEnergyHandle endingHandle);
void handleExchangeMtuRequest(const QByteArray &packet);
@@ -285,30 +253,34 @@ private:
void handlePrepareWriteRequest(const QByteArray &packet);
void handleExecuteWriteRequest(const QByteArray &packet);
- void sendErrorResponse(quint8 request, quint16 handle, quint8 code);
+ void sendErrorResponse(QBluezConst::AttCommand request, quint16 handle,
+ QBluezConst::AttError code);
using ElemWriter = std::function<void(const Attribute &, char *&)>;
- void sendListResponse(const QByteArray &packetStart, int elemSize,
- const QVector<Attribute> &attributes, const ElemWriter &elemWriter);
+ void sendListResponse(const QByteArray &packetStart, qsizetype elemSize,
+ const QList<Attribute> &attributes, const ElemWriter &elemWriter);
void sendNotification(QLowEnergyHandle handle);
void sendIndication(QLowEnergyHandle handle);
- void sendNotificationOrIndication(quint8 opCode, QLowEnergyHandle handle);
+ void sendNotificationOrIndication(QBluezConst::AttCommand opCode, QLowEnergyHandle handle);
void sendNextIndication();
- void ensureUniformAttributes(QVector<Attribute> &attributes, const std::function<int(const Attribute &)> &getSize);
- void ensureUniformUuidSizes(QVector<Attribute> &attributes);
- void ensureUniformValueSizes(QVector<Attribute> &attributes);
+ void ensureUniformAttributes(QList<Attribute> &attributes,
+ const std::function<int(const Attribute &)> &getSize);
+ void ensureUniformUuidSizes(QList<Attribute> &attributes);
+ void ensureUniformValueSizes(QList<Attribute> &attributes);
using AttributePredicate = std::function<bool(const Attribute &)>;
- QVector<Attribute> getAttributes(QLowEnergyHandle startHandle, QLowEnergyHandle endHandle,
+ QList<Attribute> getAttributes(
+ QLowEnergyHandle startHandle, QLowEnergyHandle endHandle,
const AttributePredicate &attributePredicate = [](const Attribute &) { return true; });
- int checkPermissions(const Attribute &attr, QLowEnergyCharacteristic::PropertyType type);
- int checkReadPermissions(const Attribute &attr);
- int checkReadPermissions(QVector<Attribute> &attributes);
+ QBluezConst::AttError checkPermissions(const Attribute &attr,
+ QLowEnergyCharacteristic::PropertyType type);
+ QBluezConst::AttError checkReadPermissions(const Attribute &attr);
+ QBluezConst::AttError checkReadPermissions(QList<Attribute> &attributes);
- bool verifyMac(const QByteArray &message, const quint128 &csrk, quint32 signCounter,
+ bool verifyMac(const QByteArray &message, BluezUint128 csrk, quint32 signCounter,
quint64 expectedMac);
void updateLocalAttributeValue(
@@ -350,7 +322,7 @@ private slots:
void activeConnectionTerminationDone();
};
-Q_DECLARE_TYPEINFO(QLowEnergyControllerPrivateBluez::Attribute, Q_MOVABLE_TYPE);
+Q_DECLARE_TYPEINFO(QLowEnergyControllerPrivateBluez::Attribute, Q_RELOCATABLE_TYPE);
QT_END_NAMESPACE
diff --git a/src/bluetooth/qlowenergycontroller_bluezdbus.cpp b/src/bluetooth/qlowenergycontroller_bluezdbus.cpp
index 2a0fafdf..a00e4383 100644
--- a/src/bluetooth/qlowenergycontroller_bluezdbus.cpp
+++ b/src/bluetooth/qlowenergycontroller_bluezdbus.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qlowenergycontroller_bluezdbus_p.h"
#include "bluez/adapter1_bluez5_p.h"
@@ -47,23 +11,66 @@
#include "bluez/battery1_p.h"
#include "bluez/objectmanager_p.h"
#include "bluez/properties_p.h"
-
+#include "bluez/bluezperipheralapplication_p.h"
+#include "bluez/bluezperipheralconnectionmanager_p.h"
QT_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(QT_BT_BLUEZ)
-QLowEnergyControllerPrivateBluezDBus::QLowEnergyControllerPrivateBluezDBus()
- : QLowEnergyControllerPrivate()
+QLowEnergyControllerPrivateBluezDBus::QLowEnergyControllerPrivateBluezDBus(
+ const QString &adapterPathWithPeripheralSupport)
+ : QLowEnergyControllerPrivate(),
+ adapterPathWithPeripheralSupport(adapterPathWithPeripheralSupport)
{
}
QLowEnergyControllerPrivateBluezDBus::~QLowEnergyControllerPrivateBluezDBus()
{
+ if (state != QLowEnergyController::UnconnectedState) {
+ qCWarning(QT_BT_BLUEZ) << "Low Energy Controller is not Unconnected when deleted."
+ << "Deleted in state:" << state;
+ }
}
void QLowEnergyControllerPrivateBluezDBus::init()
{
+ if (role == QLowEnergyController::PeripheralRole) {
+ Q_ASSERT(!adapterPathWithPeripheralSupport.isEmpty());
+
+ peripheralApplication = new QtBluezPeripheralApplication(adapterPathWithPeripheralSupport,
+ this);
+
+ QObject::connect(peripheralApplication, &QtBluezPeripheralApplication::errorOccurred, this,
+ &QLowEnergyControllerPrivateBluezDBus::handlePeripheralApplicationError);
+
+ QObject::connect(peripheralApplication, &QtBluezPeripheralApplication::registered, this,
+ &QLowEnergyControllerPrivateBluezDBus::handlePeripheralApplicationRegistered);
+
+ QObject::connect(peripheralApplication,
+ &QtBluezPeripheralApplication::characteristicValueUpdatedByRemote, this,
+ &QLowEnergyControllerPrivateBluezDBus::handlePeripheralCharacteristicValueUpdate);
+
+ QObject::connect(peripheralApplication,
+ &QtBluezPeripheralApplication::descriptorValueUpdatedByRemote, this,
+ &QLowEnergyControllerPrivateBluezDBus::handlePeripheralDescriptorValueUpdate);
+
+ peripheralConnectionManager =
+ new QtBluezPeripheralConnectionManager(localAdapter, this);
+
+ QObject::connect(peripheralApplication,
+ &QtBluezPeripheralApplication::remoteDeviceAccessEvent,
+ peripheralConnectionManager,
+ &QtBluezPeripheralConnectionManager::remoteDeviceAccessEvent);
+
+ QObject::connect(peripheralConnectionManager,
+ &QtBluezPeripheralConnectionManager::connectivityStateChanged, this,
+ &QLowEnergyControllerPrivateBluezDBus::handlePeripheralConnectivityChanged);
+
+ QObject::connect(peripheralConnectionManager,
+ &QtBluezPeripheralConnectionManager::remoteDeviceChanged, this,
+ &QLowEnergyControllerPrivateBluezDBus::handlePeripheralRemoteDeviceChanged);
+ }
}
void QLowEnergyControllerPrivateBluezDBus::devicePropertiesChanged(
@@ -112,32 +119,49 @@ void QLowEnergyControllerPrivateBluezDBus::devicePropertiesChanged(
}
}
}
+
+ if (changedProperties.contains(QStringLiteral("UUIDs"))) {
+ const QStringList newUuidStringList = changedProperties.value(QStringLiteral("UUIDs")).toStringList();
+ QList<QBluetoothUuid> newUuidList;
+ for (const QString &uuidString : newUuidStringList)
+ newUuidList.append(QBluetoothUuid(uuidString));
+
+ for (const QBluetoothUuid &uuid : serviceList.keys()) {
+ if (!newUuidList.contains(uuid)) {
+ qCDebug(QT_BT_BLUEZ) << __func__ << "Service" << uuid << "has been removed";
+ QSharedPointer<QLowEnergyServicePrivate> service = serviceList.take(uuid);
+ service->setController(nullptr);
+ dbusServices.remove(uuid);
+ }
+ }
+ }
+
} else if (interface == QStringLiteral("org.bluez.Battery1")) {
qCDebug(QT_BT_BLUEZ) << "######" << interface << changedProperties;
if (changedProperties.contains(QStringLiteral("Percentage"))) {
// if battery service is discovered and ClientCharConfig is enabled
// emit characteristicChanged() signal
- const QBluetoothUuid uuid(QBluetoothUuid::BatteryService);
+ const QBluetoothUuid uuid(QBluetoothUuid::ServiceClassUuid::BatteryService);
if (!serviceList.contains(uuid) || !dbusServices.contains(uuid)
|| !dbusServices[uuid].hasBatteryService
|| dbusServices[uuid].batteryInterface.isNull())
return;
QSharedPointer<QLowEnergyServicePrivate> serviceData = serviceList.value(uuid);
- if (serviceData->state != QLowEnergyService::ServiceDiscovered)
+ if (serviceData->state != QLowEnergyService::RemoteServiceDiscovered)
return;
QHash<QLowEnergyHandle, QLowEnergyServicePrivate::CharData>::iterator iter;
iter = serviceData->characteristicList.begin();
while (iter != serviceData->characteristicList.end()) {
auto &charData = iter.value();
- if (charData.uuid != QBluetoothUuid::BatteryLevel)
+ if (charData.uuid != QBluetoothUuid::CharacteristicType::BatteryLevel)
continue;
// Client Characteristic Notification enabled?
bool cccActive = false;
- for (const QLowEnergyServicePrivate::DescData &descData : qAsConst(charData.descriptorList)) {
- if (descData.uuid != QBluetoothUuid(QBluetoothUuid::ClientCharacteristicConfiguration))
+ for (const QLowEnergyServicePrivate::DescData &descData : std::as_const(charData.descriptorList)) {
+ if (descData.uuid != QBluetoothUuid(QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration))
continue;
if (descData.value == QByteArray::fromHex("0100")
|| descData.value == QByteArray::fromHex("0200")) {
@@ -177,7 +201,7 @@ void QLowEnergyControllerPrivateBluezDBus::characteristicPropertiesChanged(
const QLowEnergyCharacteristic changedChar = characteristicForHandle(charHandle);
const QLowEnergyDescriptor ccnDescriptor = changedChar.descriptor(
- QBluetoothUuid::ClientCharacteristicConfiguration);
+ QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration);
if (!ccnDescriptor.isValid())
return;
@@ -191,12 +215,17 @@ void QLowEnergyControllerPrivateBluezDBus::characteristicPropertiesChanged(
emit service->characteristicChanged(changedChar, newValue);
}
-void QLowEnergyControllerPrivateBluezDBus::interfacesRemoved(
- const QDBusObjectPath &objectPath, const QStringList &/*interfaces*/)
+void QLowEnergyControllerPrivateBluezDBus::interfacesRemoved(const QDBusObjectPath &objectPath,
+ const QStringList &interfaces)
{
if (objectPath.path() == device->path()) {
- qCWarning(QT_BT_BLUEZ) << "DBus Device1 was removed";
- executeClose(QLowEnergyController::UnknownRemoteDeviceError);
+ if (interfaces.contains(QStringLiteral("org.bluez.Device1"))) {
+ qCWarning(QT_BT_BLUEZ) << "DBus Device1 was removed";
+ executeClose(QLowEnergyController::UnknownRemoteDeviceError);
+ } else {
+ qCDebug(QT_BT_BLUEZ) << "DBus interfaces" << interfaces << "were removed from"
+ << objectPath.path();
+ }
} else if (objectPath.path() == adapter->path()) {
qCWarning(QT_BT_BLUEZ) << "DBus Adapter was removed";
executeClose(QLowEnergyController::InvalidBluetoothAdapterError);
@@ -225,6 +254,20 @@ void QLowEnergyControllerPrivateBluezDBus::resetController()
deviceMonitor = nullptr;
}
+ if (advertiser) {
+ delete advertiser;
+ advertiser = nullptr;
+ }
+
+ if (peripheralApplication)
+ peripheralApplication->reset();
+
+ if (peripheralConnectionManager)
+ peripheralConnectionManager->reset();
+
+ remoteName.clear();
+ remoteMtu = -1;
+
dbusServices.clear();
jobs.clear();
invalidateServices();
@@ -245,10 +288,8 @@ void QLowEnergyControllerPrivateBluezDBus::connectToDeviceHelper()
return;
}
- QScopedPointer<OrgFreedesktopDBusObjectManagerInterface> manager(
- new OrgFreedesktopDBusObjectManagerInterface(
- QStringLiteral("org.bluez"), QStringLiteral("/"),
- QDBusConnection::systemBus()));
+ auto manager = std::make_unique<OrgFreedesktopDBusObjectManagerInterface>(
+ QStringLiteral("org.bluez"), QStringLiteral("/"), QDBusConnection::systemBus());
QDBusPendingReply<ManagedObjectList> reply = manager->GetManagedObjects();
reply.waitForFinished();
@@ -290,7 +331,7 @@ void QLowEnergyControllerPrivateBluezDBus::connectToDeviceHelper()
return;
}
- managerBluez = manager.take();
+ managerBluez = manager.release();
connect(managerBluez, &OrgFreedesktopDBusObjectManagerInterface::InterfacesRemoved,
this, &QLowEnergyControllerPrivateBluezDBus::interfacesRemoved);
adapter = new OrgBluezAdapter1Interface(
@@ -354,24 +395,37 @@ void QLowEnergyControllerPrivateBluezDBus::connectToDevice()
void QLowEnergyControllerPrivateBluezDBus::disconnectFromDevice()
{
- if (!device)
- return;
-
- setState(QLowEnergyController::ClosingState);
+ if (role == QLowEnergyController::CentralRole) {
+ if (!device)
+ return;
- QDBusPendingReply<> reply = device->Disconnect();
- QDBusPendingCallWatcher* watcher = new QDBusPendingCallWatcher(reply, this);
- connect(watcher, &QDBusPendingCallWatcher::finished, this,
- [this](QDBusPendingCallWatcher* call) {
- QDBusPendingReply<> reply = *call;
- if (reply.isError()) {
- qCDebug(QT_BT_BLUEZ) << "BTLE_DBUS::disconnect() failed"
- << reply.reply().errorName()
- << reply.reply().errorMessage();
- executeClose(QLowEnergyController::NoError);
- }
- call->deleteLater();
- });
+ setState(QLowEnergyController::ClosingState);
+
+ QDBusPendingReply<> reply = device->Disconnect();
+ QDBusPendingCallWatcher* watcher = new QDBusPendingCallWatcher(reply, this);
+ connect(watcher, &QDBusPendingCallWatcher::finished, this,
+ [this](QDBusPendingCallWatcher* call) {
+ QDBusPendingReply<> reply = *call;
+ if (reply.isError()) {
+ qCDebug(QT_BT_BLUEZ) << "BTLE_DBUS::disconnect() failed"
+ << reply.reply().errorName()
+ << reply.reply().errorMessage();
+ executeClose(QLowEnergyController::UnknownError);
+ } else {
+ executeClose(QLowEnergyController::NoError);
+ }
+ call->deleteLater();
+ });
+ } else {
+ Q_Q(QLowEnergyController);
+ peripheralConnectionManager->disconnectDevices();
+ resetController();
+ remoteDevice.clear();
+ const auto emitDisconnected = (state == QLowEnergyController::ConnectedState);
+ setState(QLowEnergyController::UnconnectedState);
+ if (emitDisconnected)
+ emit q->disconnected();
+ }
}
void QLowEnergyControllerPrivateBluezDBus::discoverServices()
@@ -388,7 +442,8 @@ void QLowEnergyControllerPrivateBluezDBus::discoverServices()
Q_Q(QLowEnergyController);
auto setupServicePrivate = [&, q](
- QLowEnergyService::ServiceType type, const QBluetoothUuid &uuid, const QString &path){
+ QLowEnergyService::ServiceType type, const QBluetoothUuid &uuid,
+ const QString &path, const bool battery1Interface = false){
QSharedPointer<QLowEnergyServicePrivate> priv = QSharedPointer<QLowEnergyServicePrivate>::create();
priv->uuid = uuid;
priv->type = type; // we make a guess we cannot validate
@@ -396,8 +451,11 @@ void QLowEnergyControllerPrivateBluezDBus::discoverServices()
GattService serviceContainer;
serviceContainer.servicePath = path;
- if (uuid == QBluetoothUuid::BatteryService)
+
+ if (battery1Interface) {
+ qCDebug(QT_BT_BLUEZ) << "Using Battery1 interface to emulate generic interface";
serviceContainer.hasBatteryService = true;
+ }
serviceList.insert(priv->uuid, priv);
dbusServices.insert(priv->uuid, serviceContainer);
@@ -407,25 +465,50 @@ void QLowEnergyControllerPrivateBluezDBus::discoverServices()
const ManagedObjectList managedObjectList = reply.value();
const QString servicePathPrefix = device->path().append(QStringLiteral("/service"));
+
+ // The Bluez battery service (0x180f) support has evolved over time and needs additional logic:
+ //
+ // * Until 5.47 Bluez exposes battery services via generic interface (GattService1) only
+ // * Between 5.48..5.54 Bluez exposes battery service as a dedicated 'Battery1' interface only
+ // * From 5.55 Bluez exposes both the generic service as well as the dedicated 'Battery1'
+ //
+ // To hide the difference from users the 'Battery1' interface will be used to emulate the
+ // generic interface. Importantly also the GattService1 interface, if available, is available
+ // early whereas the Battery1 interface may be available only later (generated too late for
+ // this service discovery's purposes)
+ //
+ // The precedence for battery service here is as follows:
+ // * If available via GattService1, use that and ignore possible Battery1 interface
+ // * If Battery1 interface is available or the 'org.bluez.Device1' lists battery service
+ // amongst list of available services, mark the service such that the code will later
+ // look up the Battery1 service details
+ bool gattBatteryService{false};
+ QString batteryServicePath;
+
for (ManagedObjectList::const_iterator it = managedObjectList.constBegin(); it != managedObjectList.constEnd(); ++it) {
const InterfaceList &ifaceList = it.value();
if (!it.key().path().startsWith(device->path()))
continue;
- // Since Bluez 5.48 battery services (0x180f) are no longer exposed
- // as generic services under servicePathPrefix.
- // A dedicated org.bluez.Battery1 interface is exposed. Here we are going to revert
- // Bettery1 to the generic pattern.
if (it.key().path() == device->path()) {
- // find Battery1 service
+ // See if the battery service is available or is assumed to be available later
for (InterfaceList::const_iterator battIter = ifaceList.constBegin(); battIter != ifaceList.constEnd(); ++battIter) {
const QString &iface = battIter.key();
if (iface == QStringLiteral("org.bluez.Battery1")) {
- qCDebug(QT_BT_BLUEZ) << "Found dedicated Battery service -> emulating generic btle access";
- setupServicePrivate(QLowEnergyService::PrimaryService,
- QBluetoothUuid::BatteryService,
- it.key().path());
+ qCDebug(QT_BT_BLUEZ) << "Dedicated Battery1 service available";
+ batteryServicePath = it.key().path();
+ break;
+ } else if (iface == QStringLiteral("org.bluez.Device1")) {
+ for (auto const& uuid :
+ battIter.value()[QStringLiteral("UUIDs")].toStringList()) {
+ if (QBluetoothUuid(uuid) ==
+ QBluetoothUuid::ServiceClassUuid::BatteryService) {
+ qCDebug(QT_BT_BLUEZ) << "Battery service listed as available service";
+ batteryServicePath = it.key().path();
+ break;
+ }
+ }
}
}
continue;
@@ -441,6 +524,11 @@ void QLowEnergyControllerPrivateBluezDBus::discoverServices()
QScopedPointer<OrgBluezGattService1Interface> service(new OrgBluezGattService1Interface(
QStringLiteral("org.bluez"),it.key().path(),
QDBusConnection::systemBus(), this));
+ if (QBluetoothUuid(service->uUID()) ==
+ QBluetoothUuid::ServiceClassUuid::BatteryService) {
+ qCDebug(QT_BT_BLUEZ) << "Using battery service via GattService1 interface";
+ gattBatteryService = true;
+ }
setupServicePrivate(service->primary()
? QLowEnergyService::PrimaryService
: QLowEnergyService::IncludedService,
@@ -449,6 +537,12 @@ void QLowEnergyControllerPrivateBluezDBus::discoverServices()
}
}
+ if (!gattBatteryService && !batteryServicePath.isEmpty()) {
+ setupServicePrivate(QLowEnergyService::PrimaryService,
+ QBluetoothUuid::ServiceClassUuid::BatteryService,
+ batteryServicePath, true);
+ }
+
setState(QLowEnergyController::DiscoveredState);
emit q->discoveryFinished();
}
@@ -474,19 +568,19 @@ void QLowEnergyControllerPrivateBluezDBus::discoverBatteryServiceDetails(
charData.valueHandle = runningHandle++;
charData.properties.setFlag(QLowEnergyCharacteristic::Read);
charData.properties.setFlag(QLowEnergyCharacteristic::Notify);
- charData.uuid = QBluetoothUuid::BatteryLevel;
+ charData.uuid = QBluetoothUuid::CharacteristicType::BatteryLevel;
charData.value = QByteArray(1, char(batteryService->percentage()));
// Create the descriptors for the BatteryLevel
// They are hardcoded although CCC may change
QLowEnergyServicePrivate::DescData descData;
QLowEnergyHandle descriptorHandle = runningHandle++;
- descData.uuid = QBluetoothUuid::ClientCharacteristicConfiguration;
+ descData.uuid = QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration;
descData.value = QByteArray::fromHex("0000"); // all configs off
charData.descriptorList.insert(descriptorHandle, descData);
descriptorHandle = runningHandle++;
- descData.uuid = QBluetoothUuid::CharacteristicPresentationFormat;
+ descData.uuid = QBluetoothUuid::DescriptorType::CharacteristicPresentationFormat;
//for details see Characteristic Presentation Format Vol3, Part G 3.3.3.5
// unsigend 8 bit, exp=1, org.bluetooth.unit.percentage, namespace & description
// bit order: little endian
@@ -494,14 +588,14 @@ void QLowEnergyControllerPrivateBluezDBus::discoverBatteryServiceDetails(
charData.descriptorList.insert(descriptorHandle, descData);
descriptorHandle = runningHandle++;
- descData.uuid = QBluetoothUuid::ReportReference;
+ descData.uuid = QBluetoothUuid::DescriptorType::ReportReference;
descData.value = QByteArray::fromHex("0401");
charData.descriptorList.insert(descriptorHandle, descData);
serviceData->characteristicList[indexHandle] = charData;
serviceData->endHandle = runningHandle++;
- serviceData->setState(QLowEnergyService::ServiceDiscovered);
+ serviceData->setState(QLowEnergyService::RemoteServiceDiscovered);
}
void QLowEnergyControllerPrivateBluezDBus::executeClose(QLowEnergyController::Error newError)
@@ -519,7 +613,8 @@ void QLowEnergyControllerPrivateBluezDBus::executeClose(QLowEnergyController::Er
}
}
-void QLowEnergyControllerPrivateBluezDBus::discoverServiceDetails(const QBluetoothUuid &service)
+void QLowEnergyControllerPrivateBluezDBus::discoverServiceDetails(
+ const QBluetoothUuid &service, QLowEnergyService::DiscoveryMode mode)
{
if (!serviceList.contains(service) || !dbusServices.contains(service)) {
qCWarning(QT_BT_BLUEZ) << "Discovery of unknown service" << service.toString()
@@ -622,7 +717,8 @@ void QLowEnergyControllerPrivateBluezDBus::discoverServiceDetails(const QBluetoo
charData.uuid = QBluetoothUuid(dbusChar.characteristic->uUID());
// schedule read for initial char value
- if (charData.properties.testFlag(QLowEnergyCharacteristic::Read)) {
+ if (mode == QLowEnergyService::FullDiscovery
+ && charData.properties.testFlag(QLowEnergyCharacteristic::Read)) {
GattJob job;
job.flags = GattJob::JobFlags({GattJob::CharRead, GattJob::ServiceDiscovery});
job.service = serviceData;
@@ -631,7 +727,7 @@ void QLowEnergyControllerPrivateBluezDBus::discoverServiceDetails(const QBluetoo
}
// descriptor data
- for (const auto &descEntry : qAsConst(dbusChar.descriptors)) {
+ for (const auto &descEntry : std::as_const(dbusChar.descriptors)) {
const QLowEnergyHandle descriptorHandle = runningHandle++;
QLowEnergyServicePrivate::DescData descData;
descData.uuid = QBluetoothUuid(descEntry->uUID());
@@ -640,7 +736,7 @@ void QLowEnergyControllerPrivateBluezDBus::discoverServiceDetails(const QBluetoo
// every ClientCharacteristicConfiguration needs to track property changes
if (descData.uuid
- == QBluetoothUuid(QBluetoothUuid::ClientCharacteristicConfiguration)) {
+ == QBluetoothUuid(QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration)) {
dbusChar.charMonitor = QSharedPointer<OrgFreedesktopDBusPropertiesInterface>::create(
QStringLiteral("org.bluez"),
dbusChar.characteristic->path(),
@@ -654,12 +750,14 @@ void QLowEnergyControllerPrivateBluezDBus::discoverServiceDetails(const QBluetoo
});
}
- // schedule read for initial descriptor value
- GattJob job;
- job.flags = GattJob::JobFlags({GattJob::DescRead, GattJob::ServiceDiscovery});
- job.service = serviceData;
- job.handle = descriptorHandle;
- jobs.append(job);
+ if (mode == QLowEnergyService::FullDiscovery) {
+ // schedule read for initial descriptor value
+ GattJob job;
+ job.flags = GattJob::JobFlags({ GattJob::DescRead, GattJob::ServiceDiscovery });
+ job.service = serviceData;
+ job.handle = descriptorHandle;
+ jobs.append(job);
+ }
}
serviceData->characteristicList[indexHandle] = charData;
@@ -672,7 +770,7 @@ void QLowEnergyControllerPrivateBluezDBus::discoverServiceDetails(const QBluetoo
GattJob &lastJob = jobs.last();
lastJob.flags.setFlag(GattJob::LastServiceDiscovery, true);
} else {
- serviceData->setState(QLowEnergyService::ServiceDiscovered);
+ serviceData->setState(QLowEnergyService::RemoteServiceDiscovered);
}
scheduleNextJob();
@@ -723,7 +821,7 @@ void QLowEnergyControllerPrivateBluezDBus::onCharReadFinished(QDBusPendingCallWa
if (isServiceDiscovery) {
if (nextJob.flags.testFlag(GattJob::LastServiceDiscovery))
- service->setState(QLowEnergyService::ServiceDiscovered);
+ service->setState(QLowEnergyService::RemoteServiceDiscovered);
} else {
QLowEnergyCharacteristic ch(service, nextJob.handle);
emit service->characteristicRead(ch, reply.value());
@@ -773,7 +871,6 @@ void QLowEnergyControllerPrivateBluezDBus::onDescReadFinished(QDBusPendingCallWa
}
bool isServiceDiscovery = nextJob.flags.testFlag(GattJob::ServiceDiscovery);
- const QBluetoothUuid descUuid = charData.descriptorList[nextJob.handle].uuid;
QDBusPendingReply<QByteArray> reply = *call;
if (reply.isError()) {
@@ -789,7 +886,7 @@ void QLowEnergyControllerPrivateBluezDBus::onDescReadFinished(QDBusPendingCallWa
if (isServiceDiscovery) {
if (nextJob.flags.testFlag(GattJob::LastServiceDiscovery))
- service->setState(QLowEnergyService::ServiceDiscovered);
+ service->setState(QLowEnergyService::RemoteServiceDiscovered);
} else {
QLowEnergyDescriptor desc(service, ch.attributeHandle(), nextJob.handle);
emit service->descriptorRead(desc, reply.value());
@@ -834,7 +931,7 @@ void QLowEnergyControllerPrivateBluezDBus::onCharWriteFinished(QDBusPendingCallW
updateValueOfCharacteristic(nextJob.handle, nextJob.value, false);
QLowEnergyCharacteristic ch(service, nextJob.handle);
- // write without respone implies zero feedback
+ // write without response implies zero feedback
if (nextJob.writeMode == QLowEnergyService::WriteWithResponse) {
qCDebug(QT_BT_BLUEZ) << "Written Char:" << charData.uuid << nextJob.value.toHex();
emit service->characteristicWritten(ch, nextJob.value);
@@ -921,7 +1018,7 @@ void QLowEnergyControllerPrivateBluezDBus::scheduleNextJob()
const QLowEnergyServicePrivate::CharData &charData =
service->characteristicList.value(nextJob.handle);
bool foundChar = false;
- for (const auto &gattChar : qAsConst(dbusServiceData.characteristics)) {
+ for (const auto &gattChar : std::as_const(dbusServiceData.characteristics)) {
if (charData.uuid != QBluetoothUuid(gattChar.characteristic->uUID()))
continue;
@@ -950,11 +1047,16 @@ void QLowEnergyControllerPrivateBluezDBus::scheduleNextJob()
const QLowEnergyServicePrivate::CharData &charData =
service->characteristicList.value(nextJob.handle);
bool foundChar = false;
- for (const auto &gattChar : qAsConst(dbusServiceData.characteristics)) {
+ for (const auto &gattChar : std::as_const(dbusServiceData.characteristics)) {
if (charData.uuid != QBluetoothUuid(gattChar.characteristic->uUID()))
continue;
- QDBusPendingReply<> reply = gattChar.characteristic->WriteValue(nextJob.value, QVariantMap());
+ QVariantMap options;
+ // The "type" option only works with BlueZ >= 5.50, older versions always write with response
+ options[QStringLiteral("type")] = nextJob.writeMode == QLowEnergyService::WriteWithoutResponse ?
+ QStringLiteral("command") : QStringLiteral("request");
+ QDBusPendingReply<> reply = gattChar.characteristic->WriteValue(nextJob.value, options);
+
QDBusPendingCallWatcher* watcher = new QDBusPendingCallWatcher(reply, this);
connect(watcher, &QDBusPendingCallWatcher::finished,
this, &QLowEnergyControllerPrivateBluezDBus::onCharWriteFinished);
@@ -987,11 +1089,11 @@ void QLowEnergyControllerPrivateBluezDBus::scheduleNextJob()
const QBluetoothUuid descUuid = charData.descriptorList[nextJob.handle].uuid;
bool foundDesc = false;
- for (const auto &gattChar : qAsConst(dbusServiceData.characteristics)) {
+ for (const auto &gattChar : std::as_const(dbusServiceData.characteristics)) {
if (charData.uuid != QBluetoothUuid(gattChar.characteristic->uUID()))
continue;
- for (const auto &gattDesc : qAsConst(gattChar.descriptors)) {
+ for (const auto &gattDesc : std::as_const(gattChar.descriptors)) {
if (descUuid != QBluetoothUuid(gattDesc->uUID()))
continue;
@@ -1031,17 +1133,17 @@ void QLowEnergyControllerPrivateBluezDBus::scheduleNextJob()
const QBluetoothUuid descUuid = charData.descriptorList[nextJob.handle].uuid;
bool foundDesc = false;
- for (const auto &gattChar : qAsConst(dbusServiceData.characteristics)) {
+ for (const auto &gattChar : std::as_const(dbusServiceData.characteristics)) {
if (charData.uuid != QBluetoothUuid(gattChar.characteristic->uUID()))
continue;
- for (const auto &gattDesc : qAsConst(gattChar.descriptors)) {
+ for (const auto &gattDesc : std::as_const(gattChar.descriptors)) {
if (descUuid != QBluetoothUuid(gattDesc->uUID()))
continue;
//notifications enabled via characteristics Start/StopNotify() functions
//otherwise regular WriteValue() calls on descriptor interface
- if (descUuid == QBluetoothUuid(QBluetoothUuid::ClientCharacteristicConfiguration)) {
+ if (descUuid == QBluetoothUuid(QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration)) {
const QByteArray value = nextJob.value;
QDBusPendingReply<> reply;
@@ -1190,8 +1292,16 @@ void QLowEnergyControllerPrivateBluezDBus::writeCharacteristic(
scheduleNextJob();
} else {
- qWarning(QT_BT_BLUEZ) << "writeCharacteristic() not implemented for DBus Bluez GATT";
- service->setError(QLowEnergyService::CharacteristicWriteError);
+ // Peripheral role
+ Q_ASSERT(peripheralApplication);
+ if (!peripheralApplication->localCharacteristicWrite(charHandle, newValue)) {
+ qCWarning(QT_BT_BLUEZ) << "Characteristic write failed"
+ << characteristicForHandle(charHandle).uuid();
+ service->setError(QLowEnergyService::CharacteristicWriteError);
+ return;
+ }
+ QLowEnergyServicePrivate::CharData &charData = service->characteristicList[charHandle];
+ charData.value = newValue;
}
}
@@ -1212,7 +1322,7 @@ void QLowEnergyControllerPrivateBluezDBus::writeDescriptor(
if (!descriptor.isValid())
return;
- if (descriptor.uuid() == QBluetoothUuid::ClientCharacteristicConfiguration) {
+ if (descriptor.uuid() == QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration) {
if (newValue == QByteArray::fromHex("0000")
|| newValue == QByteArray::fromHex("0100")
|| newValue == QByteArray::fromHex("0200")) {
@@ -1239,37 +1349,168 @@ void QLowEnergyControllerPrivateBluezDBus::writeDescriptor(
scheduleNextJob();
} else {
- qWarning(QT_BT_BLUEZ) << "writeDescriptor() peripheral not implemented for DBus Bluez GATT";
- service->setError(QLowEnergyService::CharacteristicWriteError);
+ // Peripheral role
+ Q_ASSERT(peripheralApplication);
+
+ auto desc = descriptorForHandle(descriptorHandle);
+ if (desc.uuid() == QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration) {
+ qCWarning(QT_BT_BLUEZ) << "CCCD write not supported in peripheral role";
+ service->setError(QLowEnergyService::DescriptorWriteError);
+ return;
+ } else if (!peripheralApplication->localDescriptorWrite(descriptorHandle, newValue)) {
+ qCWarning(QT_BT_BLUEZ) << "Descriptor write failed" << desc.uuid();
+ service->setError(QLowEnergyService::DescriptorWriteError);
+ return;
+ }
+ service->characteristicList[charHandle].descriptorList[descriptorHandle].value = newValue;
}
}
void QLowEnergyControllerPrivateBluezDBus::startAdvertising(
- const QLowEnergyAdvertisingParameters &/* params */,
- const QLowEnergyAdvertisingData &/* advertisingData */,
- const QLowEnergyAdvertisingData &/* scanResponseData */)
+ const QLowEnergyAdvertisingParameters &params,
+ const QLowEnergyAdvertisingData &advertisingData,
+ const QLowEnergyAdvertisingData &scanResponseData)
{
+ error = QLowEnergyController::NoError;
+ errorString.clear();
+
+ Q_ASSERT(peripheralApplication);
+ Q_ASSERT(!adapterPathWithPeripheralSupport.isEmpty());
+
+ if (advertiser) {
+ // Clear any previous advertiser in case advertising data has changed.
+ // For clarity: this function is called only in 'Unconnected' state
+ delete advertiser;
+ advertiser = nullptr;
+ }
+ advertiser = new QLeDBusAdvertiser(params, advertisingData, scanResponseData,
+ adapterPathWithPeripheralSupport, this);
+ connect(advertiser, &QLeDBusAdvertiser::errorOccurred,
+ this, &QLowEnergyControllerPrivateBluezDBus::handleAdvertisingError);
+
+ setState(QLowEnergyController::AdvertisingState);
+
+ // First register the application to bluez if needed, and then start the advertisement.
+ // The application registration may fail and is asynchronous => serialize the steps.
+ // For clarity: advertisements can be used without any services, but registering such
+ // application to Bluez would fail
+ if (peripheralApplication->registrationNeeded())
+ peripheralApplication->registerApplication();
+ else
+ advertiser->startAdvertising();
}
void QLowEnergyControllerPrivateBluezDBus::stopAdvertising()
{
+ // This function is called only in Advertising state
+ setState(QLowEnergyController::UnconnectedState);
+ if (advertiser) {
+ advertiser->stopAdvertising();
+ delete advertiser;
+ advertiser = nullptr;
+ }
+}
+
+void QLowEnergyControllerPrivateBluezDBus::handlePeripheralApplicationRegistered()
+{
+ // Start the actual advertising now that the application is registered.
+ // Check the state first in case user has called stopAdvertising() during
+ // application registration
+ if (advertiser && state == QLowEnergyController::AdvertisingState)
+ advertiser->startAdvertising();
+ else
+ peripheralApplication->unregisterApplication();
+}
+
+void QLowEnergyControllerPrivateBluezDBus::handlePeripheralCharacteristicValueUpdate(
+ QLowEnergyHandle handle, const QByteArray& value)
+{
+ const auto characteristic = characteristicForHandle(handle);
+ if (characteristic.d_ptr
+ && updateValueOfCharacteristic(handle, value, false) == value.size()) {
+ emit characteristic.d_ptr->characteristicChanged(characteristic, value);
+ } else {
+ qCWarning(QT_BT_BLUEZ) << "Remote characteristic write failed";
+ }
+}
+
+void QLowEnergyControllerPrivateBluezDBus::handlePeripheralDescriptorValueUpdate(
+ QLowEnergyHandle characteristicHandle,
+ QLowEnergyHandle descriptorHandle,
+ const QByteArray& value)
+{
+ const auto descriptor = descriptorForHandle(descriptorHandle);
+ if (descriptor.d_ptr && updateValueOfDescriptor(
+ characteristicHandle, descriptorHandle, value, false) == value.size()) {
+ emit descriptor.d_ptr->descriptorWritten(descriptor, value);
+ } else {
+ qCWarning(QT_BT_BLUEZ) << "Remote descriptor write failed";
+ }
+}
+
+void QLowEnergyControllerPrivateBluezDBus::handlePeripheralRemoteDeviceChanged(
+ const QBluetoothAddress& address,
+ const QString& name,
+ quint16 mtu)
+{
+ remoteDevice = address;
+ remoteName = name;
+ remoteMtu = mtu;
+}
+
+void QLowEnergyControllerPrivateBluezDBus::handleAdvertisingError()
+{
+ Q_ASSERT(peripheralApplication);
+ qCWarning(QT_BT_BLUEZ) << "An advertising error occurred";
+ setError(QLowEnergyController::AdvertisingError);
+ setState(QLowEnergyController::UnconnectedState);
+ peripheralApplication->unregisterApplication();
+}
+
+void QLowEnergyControllerPrivateBluezDBus::handlePeripheralApplicationError()
+{
+ qCWarning(QT_BT_BLUEZ) << "A Bluez peripheral application error occurred";
+ setError(QLowEnergyController::UnknownError);
+ setState(QLowEnergyController::UnconnectedState);
+}
+
+void QLowEnergyControllerPrivateBluezDBus::handlePeripheralConnectivityChanged(bool connected)
+{
+ Q_Q(QLowEnergyController);
+ qCDebug(QT_BT_BLUEZ) << "Peripheral application connected change to:" << connected;
+ if (connected) {
+ setState(QLowEnergyController::ConnectedState);
+ } else {
+ resetController();
+ remoteDevice.clear();
+ setState(QLowEnergyController::UnconnectedState);
+ emit q->disconnected();
+ }
}
void QLowEnergyControllerPrivateBluezDBus::requestConnectionUpdate(
const QLowEnergyConnectionParameters & /* params */)
{
+ qCWarning(QT_BT_BLUEZ) << "Connection udpate requests not supported on Bluez DBus";
}
void QLowEnergyControllerPrivateBluezDBus::addToGenericAttributeList(
- const QLowEnergyServiceData &/* service */,
- QLowEnergyHandle /* startHandle */)
+ const QLowEnergyServiceData &serviceData,
+ QLowEnergyHandle startHandle)
{
+ Q_ASSERT(peripheralApplication);
+ QSharedPointer<QLowEnergyServicePrivate> servicePrivate = serviceForHandle(startHandle);
+ if (servicePrivate.isNull())
+ return;
+ peripheralApplication->addService(serviceData, servicePrivate, startHandle);
}
-QLowEnergyService *QLowEnergyControllerPrivateBluezDBus::addServiceHelper(
- const QLowEnergyServiceData &/*service*/)
+int QLowEnergyControllerPrivateBluezDBus::mtu() const
{
- return nullptr;
+ // currently only supported on peripheral role
+ return remoteMtu;
}
QT_END_NAMESPACE
+
+#include "moc_qlowenergycontroller_bluezdbus_p.cpp"
diff --git a/src/bluetooth/qlowenergycontroller_bluezdbus_p.h b/src/bluetooth/qlowenergycontroller_bluezdbus_p.h
index 3215b08d..afa2e8f3 100644
--- a/src/bluetooth/qlowenergycontroller_bluezdbus_p.h
+++ b/src/bluetooth/qlowenergycontroller_bluezdbus_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QLOWENERGYCONTROLLERPRIVATEDBUS_P_H
#define QLOWENERGYCONTROLLERPRIVATEDBUS_P_H
@@ -54,6 +18,7 @@
#include "qlowenergycontroller.h"
#include "qlowenergycontrollerbase_p.h"
+#include "qleadvertiser_bluezdbus_p.h"
#include <QtDBus/QDBusObjectPath>
@@ -68,13 +33,15 @@ class OrgFreedesktopDBusPropertiesInterface;
QT_BEGIN_NAMESPACE
+class QtBluezPeripheralApplication;
+class QtBluezPeripheralConnectionManager;
class QDBusPendingCallWatcher;
class QLowEnergyControllerPrivateBluezDBus final : public QLowEnergyControllerPrivate
{
Q_OBJECT
public:
- QLowEnergyControllerPrivateBluezDBus();
+ QLowEnergyControllerPrivateBluezDBus(const QString& adapterPathWithPeripheralSupport = {});
~QLowEnergyControllerPrivateBluezDBus() override;
void init() override;
@@ -82,41 +49,41 @@ public:
void disconnectFromDevice() override;
void discoverServices() override;
- void discoverServiceDetails(const QBluetoothUuid &/*service*/) override;
+ void discoverServiceDetails(const QBluetoothUuid &service,
+ QLowEnergyService::DiscoveryMode mode) override;
void readCharacteristic(
- const QSharedPointer<QLowEnergyServicePrivate> /*service*/,
- const QLowEnergyHandle /*charHandle*/) override;
+ const QSharedPointer<QLowEnergyServicePrivate> service,
+ const QLowEnergyHandle charHandle) override;
void readDescriptor(
- const QSharedPointer<QLowEnergyServicePrivate> /*service*/,
- const QLowEnergyHandle /*charHandle*/,
- const QLowEnergyHandle /*descriptorHandle*/) override;
+ const QSharedPointer<QLowEnergyServicePrivate> service,
+ const QLowEnergyHandle charHandle,
+ const QLowEnergyHandle descriptorHandle) override;
void writeCharacteristic(
- const QSharedPointer<QLowEnergyServicePrivate> /*service*/,
- const QLowEnergyHandle /*charHandle*/,
- const QByteArray &/*newValue*/,
- QLowEnergyService::WriteMode /*writeMode*/) override;
+ const QSharedPointer<QLowEnergyServicePrivate> service,
+ const QLowEnergyHandle charHandle,
+ const QByteArray &newValue,
+ QLowEnergyService::WriteMode writeMode) override;
void writeDescriptor(
- const QSharedPointer<QLowEnergyServicePrivate> /*service*/,
- const QLowEnergyHandle /*charHandle*/,
- const QLowEnergyHandle /*descriptorHandle*/,
- const QByteArray &/*newValue*/) override;
+ const QSharedPointer<QLowEnergyServicePrivate> service,
+ const QLowEnergyHandle charHandle,
+ const QLowEnergyHandle descriptorHandle,
+ const QByteArray &newValue) override;
void startAdvertising(
- const QLowEnergyAdvertisingParameters &/* params */,
- const QLowEnergyAdvertisingData &/* advertisingData */,
- const QLowEnergyAdvertisingData &/* scanResponseData */) override;
+ const QLowEnergyAdvertisingParameters &params,
+ const QLowEnergyAdvertisingData &advertisingData,
+ const QLowEnergyAdvertisingData &scanResponseData) override;
void stopAdvertising() override;
void requestConnectionUpdate(
- const QLowEnergyConnectionParameters & /* params */) override;
+ const QLowEnergyConnectionParameters & params) override;
void addToGenericAttributeList(
- const QLowEnergyServiceData &/* service */,
- QLowEnergyHandle /* startHandle */) override;
-
- QLowEnergyService *addServiceHelper(const QLowEnergyServiceData &service) override;
+ const QLowEnergyServiceData &service,
+ QLowEnergyHandle startHandle) override;
+ int mtu() const override;
private:
void connectToDeviceHelper();
@@ -126,7 +93,7 @@ private:
private slots:
void devicePropertiesChanged(const QString &interface, const QVariantMap &changedProperties,
- const QStringList &/*invalidatedProperties*/);
+ const QStringList &invalidatedProperties);
void characteristicPropertiesChanged(QLowEnergyHandle charHandle, const QString &interface,
const QVariantMap &changedProperties,
const QStringList &invalidatedProperties);
@@ -137,11 +104,29 @@ private slots:
void onCharWriteFinished(QDBusPendingCallWatcher *call);
void onDescWriteFinished(QDBusPendingCallWatcher *call);
private:
+
OrgBluezAdapter1Interface* adapter{};
OrgBluezDevice1Interface* device{};
OrgFreedesktopDBusObjectManagerInterface* managerBluez{};
OrgFreedesktopDBusPropertiesInterface* deviceMonitor{};
-
+ QString adapterPathWithPeripheralSupport;
+
+ int remoteMtu{-1};
+ QtBluezPeripheralApplication* peripheralApplication{};
+ QtBluezPeripheralConnectionManager* peripheralConnectionManager{};
+ QLeDBusAdvertiser *advertiser{};
+ void handleAdvertisingError();
+ void handlePeripheralApplicationError();
+ void handlePeripheralApplicationRegistered();
+ void handlePeripheralConnectivityChanged(bool connected);
+ void handlePeripheralCharacteristicValueUpdate(QLowEnergyHandle handle,
+ const QByteArray& value);
+ void handlePeripheralDescriptorValueUpdate(QLowEnergyHandle characteristicHandle,
+ QLowEnergyHandle descriptorHandle,
+ const QByteArray& value);
+ void handlePeripheralRemoteDeviceChanged(const QBluetoothAddress& address,
+ const QString& name,
+ quint16 mtu);
bool pendingConnect = false;
bool disconnectSignalRequired = false;
@@ -149,13 +134,13 @@ private:
{
QSharedPointer<OrgBluezGattCharacteristic1Interface> characteristic;
QSharedPointer<OrgFreedesktopDBusPropertiesInterface> charMonitor;
- QVector<QSharedPointer<OrgBluezGattDescriptor1Interface>> descriptors;
+ QList<QSharedPointer<OrgBluezGattDescriptor1Interface>> descriptors;
};
struct GattService
{
QString servicePath;
- QVector<GattCharacteristic> characteristics;
+ QList<GattCharacteristic> characteristics;
bool hasBatteryService = false;
QSharedPointer<OrgBluezBattery1Interface> batteryInterface;
@@ -183,7 +168,7 @@ private:
QSharedPointer<QLowEnergyServicePrivate> service;
};
- QVector<GattJob> jobs;
+ QList<GattJob> jobs;
bool jobPending = false;
void prepareNextJob();
diff --git a/src/bluetooth/qlowenergycontroller_darwin.mm b/src/bluetooth/qlowenergycontroller_darwin.mm
index bbe7a4a6..40c95182 100644
--- a/src/bluetooth/qlowenergycontroller_darwin.mm
+++ b/src/bluetooth/qlowenergycontroller_darwin.mm
@@ -1,53 +1,13 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2016 Javier S. Pedro <maemo@javispedro.com>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "darwin/btutility_p.h"
-#include "darwin/uistrings_p.h"
-
-#ifndef Q_OS_TVOS
-#include "darwin/btperipheralmanager_p.h"
-#endif // Q_OS_TVOS
+// Copyright (C) 2022 The Qt Company Ltd.
+// Copyright (C) 2016 Javier S. Pedro <maemo@javispedro.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qlowenergycontroller_darwin_p.h"
+#include "darwin/btperipheralmanager_p.h"
#include "qlowenergyserviceprivate_p.h"
#include "darwin/btcentralmanager_p.h"
+#include "darwin/btutility_p.h"
+#include "darwin/uistrings_p.h"
#include "qlowenergyservicedata.h"
#include "qbluetoothlocaldevice.h"
@@ -61,6 +21,8 @@
#include <QtCore/qglobal.h>
#include <QtCore/qstring.h>
#include <QtCore/qlist.h>
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qpermissions.h>
QT_BEGIN_NAMESPACE
@@ -121,12 +83,6 @@ UUIDList qt_servicesUuids(NSArray *services)
} // unnamed namespace
-#ifndef Q_OS_TVOS
-using ObjCPeripheralManager = QT_MANGLE_NAMESPACE(DarwinBTPeripheralManager);
-#endif // Q_OS_TVOS
-
-using ObjCCentralManager = QT_MANGLE_NAMESPACE(DarwinBTCentralManager);
-
QLowEnergyControllerPrivateDarwin::QLowEnergyControllerPrivateDarwin()
{
void registerQLowEnergyControllerMetaType();
@@ -139,61 +95,64 @@ QLowEnergyControllerPrivateDarwin::~QLowEnergyControllerPrivateDarwin()
{
if (const auto leQueue = DarwinBluetooth::qt_LE_queue()) {
if (role == QLowEnergyController::CentralRole) {
- const auto manager = centralManager.getAs<ObjCCentralManager>();
+ const auto manager = centralManager.getAs<DarwinBTCentralManager>();
dispatch_sync(leQueue, ^{
[manager detach];
});
} else {
-#ifndef Q_OS_TVOS
- const auto manager = peripheralManager.getAs<ObjCPeripheralManager>();
+ const auto manager = peripheralManager.getAs<DarwinBTPeripheralManager>();
dispatch_sync(leQueue, ^{
[manager detach];
});
-#endif
}
}
}
bool QLowEnergyControllerPrivateDarwin::isValid() const
{
-#ifdef Q_OS_TVOS
- return centralManager;
-#else
return centralManager || peripheralManager;
-#endif
}
void QLowEnergyControllerPrivateDarwin::init()
{
- using DarwinBluetooth::LECBManagerNotifier;
+ // We have to override the 'init', it's pure virtual in the base.
+ // Just creating a central or peripheral should not trigger any
+ // error yet.
+}
- QScopedPointer<LECBManagerNotifier> notifier(new LECBManagerNotifier);
+bool QLowEnergyControllerPrivateDarwin::lazyInit()
+{
+ using namespace DarwinBluetooth;
+
+ if (peripheralManager || centralManager)
+ return true;
+
+ if (qApp->checkPermission(QBluetoothPermission{}) != Qt::PermissionStatus::Granted) {
+ qCWarning(QT_BT_DARWIN,
+ "Use of Bluetooth LE must be explicitly requested by the application.");
+ setError(QLowEnergyController::MissingPermissionsError);
+ return false;
+ }
+
+ std::unique_ptr<LECBManagerNotifier> notifier = std::make_unique<LECBManagerNotifier>();
if (role == QLowEnergyController::PeripheralRole) {
-#ifndef Q_OS_TVOS
- peripheralManager.reset([[ObjCPeripheralManager alloc] initWith:notifier.data()],
+ peripheralManager.reset([[DarwinBTPeripheralManager alloc] initWith:notifier.get()],
DarwinBluetooth::RetainPolicy::noInitialRetain);
- if (!peripheralManager) {
- qCWarning(QT_BT_DARWIN) << "failed to create a peripheral manager";
- return;
- }
-#else
- qCWarning(QT_BT_DARWIN) << "the peripheral role is not supported on your platform";
- return;
-#endif // Q_OS_TVOS
+ Q_ASSERT(peripheralManager);
} else {
- centralManager.reset([[ObjCCentralManager alloc] initWith:notifier.data()],
+ centralManager.reset([[DarwinBTCentralManager alloc] initWith:notifier.get()],
DarwinBluetooth::RetainPolicy::noInitialRetain);
- if (!centralManager) {
- qCWarning(QT_BT_DARWIN) << "failed to initialize a central manager";
- return;
- }
+ Q_ASSERT(centralManager);
}
- if (!connectSlots(notifier.data()))
+ // FIXME: Q_UNLIKELY
+ if (!connectSlots(notifier.get()))
qCWarning(QT_BT_DARWIN) << "failed to connect to notifier's signal(s)";
// Ownership was taken by central manager.
- notifier.take();
+ notifier.release();
+
+ return true;
}
void QLowEnergyControllerPrivateDarwin::connectToDevice()
@@ -201,32 +160,26 @@ void QLowEnergyControllerPrivateDarwin::connectToDevice()
Q_ASSERT_X(state == QLowEnergyController::UnconnectedState,
Q_FUNC_INFO, "invalid state");
- if (!isValid()) {
- // init() had failed for was never called.
- return _q_CBManagerError(QLowEnergyController::UnknownError);
- }
-
if (deviceUuid.isNull()) {
// Wrong constructor was used or invalid UUID was provided.
return _q_CBManagerError(QLowEnergyController::UnknownRemoteDeviceError);
}
+ if (!lazyInit()) // MissingPermissionsError was emit.
+ return;
+
// The logic enforcing the role is in the public class.
Q_ASSERT_X(role != QLowEnergyController::PeripheralRole,
Q_FUNC_INFO, "invalid role (peripheral)");
dispatch_queue_t leQueue(DarwinBluetooth::qt_LE_queue());
- if (!leQueue) {
- qCWarning(QT_BT_DARWIN) << "no LE queue found";
- setErrorDescription(QLowEnergyController::UnknownError);
- return;
- }
+ Q_ASSERT_X(leQueue, Q_FUNC_INFO, "invalid LE queue (nullptr)");
- setErrorDescription(QLowEnergyController::NoError);
+ setError(QLowEnergyController::NoError);
setState(QLowEnergyController::ConnectingState);
const QBluetoothUuid deviceUuidCopy(deviceUuid);
- ObjCCentralManager *manager = centralManager.getAs<ObjCCentralManager>();
+ DarwinBTCentralManager *manager = centralManager.getAs<DarwinBTCentralManager>();
dispatch_async(leQueue, ^{
[manager connectToDevice:deviceUuidCopy];
});
@@ -234,36 +187,35 @@ void QLowEnergyControllerPrivateDarwin::connectToDevice()
void QLowEnergyControllerPrivateDarwin::disconnectFromDevice()
{
+ Q_ASSERT(isValid()); // Check for proper state is in Qt's code.
+
if (role == QLowEnergyController::PeripheralRole) {
// CoreBluetooth API intentionally does not provide any way of closing
// a connection. All we can do here is to stop the advertisement.
- stopAdvertising();
- return;
+ return stopAdvertising();
}
- if (isValid()) {
- const auto oldState = state;
+ const auto oldState = state;
- if (dispatch_queue_t leQueue = DarwinBluetooth::qt_LE_queue()) {
- setState(QLowEnergyController::ClosingState);
- invalidateServices();
-
- auto manager = centralManager.getAs<ObjCCentralManager>();
- dispatch_async(leQueue, ^{
- [manager disconnectFromDevice];
- });
+ if (dispatch_queue_t leQueue = DarwinBluetooth::qt_LE_queue()) {
+ setState(QLowEnergyController::ClosingState);
+ invalidateServices();
- if (oldState == QLowEnergyController::ConnectingState) {
- // With a pending connect attempt there is no
- // guarantee we'll ever have didDisconnect callback,
- // set the state here and now to make sure we still
- // can connect.
- setState(QLowEnergyController::UnconnectedState);
- }
- } else {
- qCCritical(QT_BT_DARWIN) << "qt LE queue is nil, "
- "can not dispatch 'disconnect'";
+ auto manager = centralManager.getAs<DarwinBTCentralManager>();
+ dispatch_async(leQueue, ^{
+ [manager disconnectFromDevice];
+ });
+
+ if (oldState == QLowEnergyController::ConnectingState) {
+ // With a pending connect attempt there is no
+ // guarantee we'll ever have didDisconnect callback,
+ // set the state here and now to make sure we still
+ // can connect.
+ setState(QLowEnergyController::UnconnectedState);
}
+ } else {
+ qCCritical(QT_BT_DARWIN) << "qt LE queue is nil, "
+ "can not dispatch 'disconnect'";
}
}
@@ -274,19 +226,23 @@ void QLowEnergyControllerPrivateDarwin::discoverServices()
Q_ASSERT_X(role != QLowEnergyController::PeripheralRole,
Q_FUNC_INFO, "invalid role (peripheral)");
+ Q_ASSERT(isValid()); // Check we're in a proper state is in q's code.
+
dispatch_queue_t leQueue(DarwinBluetooth::qt_LE_queue());
Q_ASSERT_X(leQueue, Q_FUNC_INFO, "LE queue not found");
setState(QLowEnergyController::DiscoveringState);
- ObjCCentralManager *manager = centralManager.getAs<ObjCCentralManager>();
+ DarwinBTCentralManager *manager = centralManager.getAs<DarwinBTCentralManager>();
dispatch_async(leQueue, ^{
[manager discoverServices];
});
}
-void QLowEnergyControllerPrivateDarwin::discoverServiceDetails(const QBluetoothUuid &serviceUuid)
+void QLowEnergyControllerPrivateDarwin::discoverServiceDetails(
+ const QBluetoothUuid &serviceUuid, QLowEnergyService::DiscoveryMode mode)
{
+ Q_UNUSED(mode);
if (state != QLowEnergyController::DiscoveredState) {
qCWarning(QT_BT_DARWIN) << "can not discover service details in the current state, "
"QLowEnergyController::DiscoveredState is expected";
@@ -302,12 +258,12 @@ void QLowEnergyControllerPrivateDarwin::discoverServiceDetails(const QBluetoothU
Q_ASSERT(leQueue);
ServicePrivate qtService(serviceList.value(serviceUuid));
- qtService->setState(QLowEnergyService::DiscoveringServices);
+ qtService->setState(QLowEnergyService::RemoteServiceDiscovering);
// Copy objects ...
- ObjCCentralManager *manager = centralManager.getAs<ObjCCentralManager>();
+ DarwinBTCentralManager *manager = centralManager.getAs<DarwinBTCentralManager>();
const QBluetoothUuid serviceUuidCopy(serviceUuid);
dispatch_async(leQueue, ^{
- [manager discoverServiceDetails:serviceUuidCopy];
+ [manager discoverServiceDetails:serviceUuidCopy readValues:mode == QLowEnergyService::FullDiscovery];
});
}
@@ -321,38 +277,57 @@ void QLowEnergyControllerPrivateDarwin::requestConnectionUpdate(const QLowEnergy
void QLowEnergyControllerPrivateDarwin::addToGenericAttributeList(const QLowEnergyServiceData &service,
QLowEnergyHandle startHandle)
{
+ // Darwin LE controller implements the addServiceHelper() for adding services, and thus
+ // the base class' addServiceHelper(), which calls this function, is not used
Q_UNUSED(service);
Q_UNUSED(startHandle);
- // TODO: check why I don't need this (apparently it is used in addServiceHelper
- // of the base class).
}
-QLowEnergyService * QLowEnergyControllerPrivateDarwin::addServiceHelper(const QLowEnergyServiceData &service)
+int QLowEnergyControllerPrivateDarwin::mtu() const
{
- // Three checks below should be removed, they are done in the q_ptr's class.
-#ifdef Q_OS_TVOS
- Q_UNUSED(service);
- qCDebug(QT_BT_DARWIN, "peripheral role is not supported on tvOS");
-#else
- if (role != QLowEnergyController::PeripheralRole) {
- qCWarning(QT_BT_DARWIN) << "not in peripheral role";
- return nullptr;
+ // FIXME: check the state - neither public class does,
+ // nor us - not fun! E.g. readRssi correctly checked/asserted.
+
+ __block int mtu = DarwinBluetooth::defaultMtu;
+ if (!isValid()) // A minimal check.
+ return defaultMtu;
+
+ if (const auto leQueue = DarwinBluetooth::qt_LE_queue()) {
+ const auto *manager = centralManager.getAs<DarwinBTCentralManager>();
+ dispatch_sync(leQueue, ^{
+ mtu = [manager mtu];
+ });
}
- if (state != QLowEnergyController::UnconnectedState) {
- qCWarning(QT_BT_DARWIN) << "invalid state";
- return nullptr;
+ return mtu;
+}
+
+void QLowEnergyControllerPrivateDarwin::readRssi()
+{
+ Q_ASSERT(role == QLowEnergyController::CentralRole);
+ Q_ASSERT(state == QLowEnergyController::ConnectedState ||
+ state == QLowEnergyController::DiscoveringState ||
+ state == QLowEnergyController::DiscoveredState);
+
+ if (const auto leQueue = DarwinBluetooth::qt_LE_queue()) {
+ const auto *manager = centralManager.getAs<DarwinBTCentralManager>();
+ dispatch_async(leQueue, ^{
+ [manager readRssi];
+ });
}
+}
- if (!service.isValid()) {
- qCWarning(QT_BT_DARWIN) << "invalid service";
+QLowEnergyService * QLowEnergyControllerPrivateDarwin::addServiceHelper(const QLowEnergyServiceData &service)
+{
+ if (!lazyInit() || !isValid()) {
+ qCWarning(QT_BT_DARWIN) << "invalid peripheral";
return nullptr;
}
for (auto includedService : service.includedServices())
includedService->d_ptr->type |= QLowEnergyService::IncludedService;
- const auto manager = peripheralManager.getAs<ObjCPeripheralManager>();
+ const auto manager = peripheralManager.getAs<DarwinBTPeripheralManager>();
Q_ASSERT(manager);
if (const auto servicePrivate = [manager addService:service]) {
servicePrivate->setController(this);
@@ -360,7 +335,7 @@ QLowEnergyService * QLowEnergyControllerPrivateDarwin::addServiceHelper(const QL
localServices.insert(servicePrivate->uuid, servicePrivate);
return new QLowEnergyService(servicePrivate);
}
-#endif // Q_OS_TVOS
+
return nullptr;
}
@@ -379,6 +354,11 @@ void QLowEnergyControllerPrivateDarwin::_q_disconnected()
emit q_ptr->disconnected();
}
+void QLowEnergyControllerPrivateDarwin::_q_mtuChanged(int newValue)
+{
+ emit q_ptr->mtuChanged(newValue);
+}
+
void QLowEnergyControllerPrivateDarwin::_q_serviceDiscoveryFinished()
{
Q_ASSERT_X(state == QLowEnergyController::DiscoveringState,
@@ -388,7 +368,7 @@ void QLowEnergyControllerPrivateDarwin::_q_serviceDiscoveryFinished()
QT_BT_MAC_AUTORELEASEPOOL;
- NSArray *const services = [centralManager.getAs<ObjCCentralManager>() peripheral].services;
+ NSArray *const services = [centralManager.getAs<DarwinBTCentralManager>() peripheral].services;
// Now we have to traverse the discovered services tree.
// Essentially it's an iterative version of more complicated code from the
// DarwinBTCentralManager's code.
@@ -460,11 +440,16 @@ void QLowEnergyControllerPrivateDarwin::_q_serviceDiscoveryFinished()
qCDebug(QT_BT_DARWIN) << "no services found";
}
- for (ServiceMap::const_iterator it = serviceList.constBegin(); it != serviceList.constEnd(); ++it)
- emit q_ptr->serviceDiscovered(it.key());
- setState(QLowEnergyController::DiscoveredState);
- emit q_ptr->discoveryFinished();
+ state = QLowEnergyController::DiscoveredState;
+
+ for (auto it = serviceList.constBegin(); it != serviceList.constEnd(); ++it) {
+ QMetaObject::invokeMethod(q_ptr, "serviceDiscovered", Qt::QueuedConnection,
+ Q_ARG(QBluetoothUuid, it.key()));
+ }
+
+ QMetaObject::invokeMethod(q_ptr, "stateChanged", Qt::QueuedConnection, Q_ARG(QLowEnergyController::ControllerState, state));
+ QMetaObject::invokeMethod(q_ptr, "discoveryFinished", Qt::QueuedConnection);
}
void QLowEnergyControllerPrivateDarwin::_q_serviceDetailsDiscoveryFinished(QSharedPointer<QLowEnergyServicePrivate> service)
@@ -485,7 +470,7 @@ void QLowEnergyControllerPrivateDarwin::_q_serviceDetailsDiscoveryFinished(QShar
qtService->endHandle = service->endHandle;
qtService->characteristicList = service->characteristicList;
- qtService->setState(QLowEnergyService::ServiceDiscovered);
+ qtService->setState(QLowEnergyService::RemoteServiceDiscovered);
}
void QLowEnergyControllerPrivateDarwin::_q_servicesWereModified()
@@ -631,7 +616,7 @@ void QLowEnergyControllerPrivateDarwin::_q_notificationEnabled(QLowEnergyHandle
}
const QLowEnergyDescriptor qtDescriptor =
- qtChar.descriptor(QBluetoothUuid::ClientCharacteristicConfiguration);
+ qtChar.descriptor(QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration);
if (!qtDescriptor.isValid()) {
qCWarning(QT_BT_DARWIN) << "characteristic" << charHandle
<< "does not have a client characteristic "
@@ -663,14 +648,19 @@ void QLowEnergyControllerPrivateDarwin::_q_LEnotSupported()
void QLowEnergyControllerPrivateDarwin::_q_CBManagerError(QLowEnergyController::Error errorCode)
{
+ qCDebug(QT_BT_DARWIN) << "QLowEnergyController error:" << errorCode << "in state:" << state;
// This function handles errors reported while connecting to a remote device
// and also other errors in general.
setError(errorCode);
- if (state == QLowEnergyController::ConnectingState)
+ if (state == QLowEnergyController::ConnectingState
+ || state == QLowEnergyController::AdvertisingState) {
setState(QLowEnergyController::UnconnectedState);
- else if (state == QLowEnergyController::DiscoveringState)
+ } else if (state == QLowEnergyController::DiscoveringState) {
+ // An error occurred during service discovery, finish the discovery.
setState(QLowEnergyController::ConnectedState);
+ emit q_ptr->discoveryFinished();
+ }
// In any other case we stay in Discovered, it's
// a service/characteristic - related error.
@@ -680,7 +670,7 @@ void QLowEnergyControllerPrivateDarwin::_q_CBManagerError(const QBluetoothUuid &
QLowEnergyController::Error errorCode)
{
// Errors reported while discovering service details etc.
- Q_UNUSED(errorCode) // TODO: setError?
+ Q_UNUSED(errorCode); // TODO: setError?
// We failed to discover any characteristics/descriptors.
if (serviceList.contains(serviceUuid)) {
@@ -742,7 +732,7 @@ void QLowEnergyControllerPrivateDarwin::setNotifyValue(QSharedPointer<QLowEnergy
dispatch_queue_t leQueue(DarwinBluetooth::qt_LE_queue());
Q_ASSERT_X(leQueue, Q_FUNC_INFO, "no LE queue found");
- ObjCCentralManager *manager = centralManager.getAs<ObjCCentralManager>();
+ DarwinBTCentralManager *manager = centralManager.getAs<DarwinBTCentralManager>();
const QBluetoothUuid serviceUuid(service->uuid);
const QByteArray newValueCopy(newValue);
dispatch_async(leQueue, ^{
@@ -778,7 +768,7 @@ void QLowEnergyControllerPrivateDarwin::readCharacteristic(const QSharedPointer<
Q_ASSERT_X(leQueue, Q_FUNC_INFO, "no LE queue found");
// Attention! We have to copy UUID.
- ObjCCentralManager *manager = centralManager.getAs<ObjCCentralManager>();
+ DarwinBTCentralManager *manager = centralManager.getAs<DarwinBTCentralManager>();
const QBluetoothUuid serviceUuid(service->uuid);
dispatch_async(leQueue, ^{
[manager readCharacteristic:charHandle onService:serviceUuid];
@@ -812,7 +802,7 @@ void QLowEnergyControllerPrivateDarwin::writeCharacteristic(const QSharedPointer
const QByteArray newValueCopy(newValue);
if (role == QLowEnergyController::CentralRole) {
const QBluetoothUuid serviceUuid(service->uuid);
- const auto manager = centralManager.getAs<ObjCCentralManager>();
+ const auto manager = centralManager.getAs<DarwinBTCentralManager>();
dispatch_async(leQueue, ^{
[manager write:newValueCopy
charHandle:charHandle
@@ -820,14 +810,10 @@ void QLowEnergyControllerPrivateDarwin::writeCharacteristic(const QSharedPointer
withResponse:mode == QLowEnergyService::WriteWithResponse];
});
} else {
-#ifndef Q_OS_TVOS
- const auto manager = peripheralManager.getAs<ObjCPeripheralManager>();
+ const auto manager = peripheralManager.getAs<DarwinBTPeripheralManager>();
dispatch_async(leQueue, ^{
[manager write:newValueCopy charHandle:charHandle];
});
-#else
- qCWarning(QT_BT_DARWIN) << "peripheral role is not supported on your platform";
-#endif
}
}
@@ -856,7 +842,7 @@ void QLowEnergyControllerPrivateDarwin::readDescriptor(const QSharedPointer<QLow
const QLowEnergyHandle charHandle,
const QLowEnergyHandle descriptorHandle)
{
- Q_UNUSED(charHandle) // Hehe, yes!
+ Q_UNUSED(charHandle); // Hehe, yes!
Q_ASSERT_X(!service.isNull(), Q_FUNC_INFO, "invalid service (null)");
@@ -878,7 +864,7 @@ void QLowEnergyControllerPrivateDarwin::readDescriptor(const QSharedPointer<QLow
}
// Attention! Copy objects!
const QBluetoothUuid serviceUuid(service->uuid);
- ObjCCentralManager * const manager = centralManager.getAs<ObjCCentralManager>();
+ DarwinBTCentralManager * const manager = centralManager.getAs<DarwinBTCentralManager>();
dispatch_async(leQueue, ^{
[manager readDescriptor:descriptorHandle
onService:serviceUuid];
@@ -890,7 +876,7 @@ void QLowEnergyControllerPrivateDarwin::writeDescriptor(const QSharedPointer<QLo
const QLowEnergyHandle descriptorHandle,
const QByteArray &newValue)
{
- Q_UNUSED(charHandle)
+ Q_UNUSED(charHandle);
Q_ASSERT_X(!service.isNull(), Q_FUNC_INFO, "invalid service (null)");
@@ -912,7 +898,7 @@ void QLowEnergyControllerPrivateDarwin::writeDescriptor(const QSharedPointer<QLo
Q_ASSERT_X(leQueue, Q_FUNC_INFO, "no LE queue found");
// Attention! Copy objects!
const QBluetoothUuid serviceUuid(service->uuid);
- ObjCCentralManager * const manager = centralManager.getAs<ObjCCentralManager>();
+ DarwinBTCentralManager * const manager = centralManager.getAs<DarwinBTCentralManager>();
const QByteArray newValueCopy(newValue);
dispatch_async(leQueue, ^{
[manager write:newValueCopy
@@ -947,40 +933,6 @@ quint16 QLowEnergyControllerPrivateDarwin::updateValueOfDescriptor(QLowEnergyHan
return 0;
}
-void QLowEnergyControllerPrivateDarwin::setErrorDescription(QLowEnergyController::Error errorCode)
-{
- // This function does not emit!
- // TODO: well, it is not a reason to duplicate a significant part of
- // setError though!
-
- error = errorCode;
-
- switch (error) {
- case QLowEnergyController::NoError:
- errorString.clear();
- break;
- case QLowEnergyController::UnknownRemoteDeviceError:
- errorString = QLowEnergyController::tr("Remote device cannot be found");
- break;
- case QLowEnergyController::InvalidBluetoothAdapterError:
- errorString = QLowEnergyController::tr("Cannot find local adapter");
- break;
- case QLowEnergyController::NetworkError:
- errorString = QLowEnergyController::tr("Error occurred during connection I/O");
- break;
- case QLowEnergyController::ConnectionError:
- errorString = QLowEnergyController::tr("Error occurred trying to connect to remote device.");
- break;
- case QLowEnergyController::AdvertisingError:
- errorString = QLowEnergyController::tr("Error occurred trying to start advertising");
- break;
- case QLowEnergyController::UnknownError:
- default:
- errorString = QLowEnergyController::tr("Unknown Error");
- break;
- }
-}
-
bool QLowEnergyControllerPrivateDarwin::connectSlots(DarwinBluetooth::LECBManagerNotifier *notifier)
{
using DarwinBluetooth::LECBManagerNotifier;
@@ -1017,6 +969,10 @@ bool QLowEnergyControllerPrivateDarwin::connectSlots(DarwinBluetooth::LECBManage
this, SLOT(_q_CBManagerError(const QBluetoothUuid &, QLowEnergyController::Error)));
ok = ok && connect(notifier, SIGNAL(CBManagerError(const QBluetoothUuid &, QLowEnergyService::ServiceError)),
this, SLOT(_q_CBManagerError(const QBluetoothUuid &, QLowEnergyService::ServiceError)));
+ ok = ok && connect(notifier, &LECBManagerNotifier::mtuChanged, this,
+ &QLowEnergyControllerPrivateDarwin::_q_mtuChanged);
+ ok = ok && connect(notifier, &LECBManagerNotifier::rssiUpdated, q_ptr,
+ &QLowEnergyController::rssiRead, Qt::QueuedConnection);
if (!ok)
notifier->disconnect();
@@ -1028,34 +984,13 @@ void QLowEnergyControllerPrivateDarwin::startAdvertising(const QLowEnergyAdverti
const QLowEnergyAdvertisingData &advertisingData,
const QLowEnergyAdvertisingData &scanResponseData)
{
-#ifdef Q_OS_TVOS
- Q_UNUSED(params)
- Q_UNUSED(advertisingData)
- Q_UNUSED(scanResponseData)
- qCWarning(QT_BT_DARWIN) << "advertising is not supported on your platform";
-#else
-
- if (!isValid())
- return _q_CBManagerError(QLowEnergyController::UnknownError);
-
- if (role != QLowEnergyController::PeripheralRole) {
- qCWarning(QT_BT_DARWIN) << "controller is not a peripheral, cannot start advertising";
+ if (!lazyInit()) // Error was emit already.
return;
- }
-
- if (state != QLowEnergyController::UnconnectedState) {
- qCWarning(QT_BT_DARWIN) << "invalid state" << state;
- return;
- }
auto leQueue(DarwinBluetooth::qt_LE_queue());
- if (!leQueue) {
- qCWarning(QT_BT_DARWIN) << "no LE queue found";
- setErrorDescription(QLowEnergyController::UnknownError);
- return;
- }
+ Q_ASSERT_X(leQueue, Q_FUNC_INFO, "invalid LE queue (nullptr)");
- const auto manager = peripheralManager.getAs<ObjCPeripheralManager>();
+ const auto manager = peripheralManager.getAs<DarwinBTPeripheralManager>();
[manager setParameters:params data:advertisingData scanResponse:scanResponseData];
setState(QLowEnergyController::AdvertisingState);
@@ -1063,14 +998,10 @@ void QLowEnergyControllerPrivateDarwin::startAdvertising(const QLowEnergyAdverti
dispatch_async(leQueue, ^{
[manager startAdvertising];
});
-#endif
}
void QLowEnergyControllerPrivateDarwin::stopAdvertising()
{
-#ifdef Q_OS_TVOS
- qCWarning(QT_BT_DARWIN) << "advertising is not supported on your platform";
-#else
if (!isValid())
return _q_CBManagerError(QLowEnergyController::UnknownError);
@@ -1079,19 +1010,14 @@ void QLowEnergyControllerPrivateDarwin::stopAdvertising()
return;
}
- if (const auto leQueue = DarwinBluetooth::qt_LE_queue()) {
- const auto manager = peripheralManager.getAs<ObjCPeripheralManager>();
- dispatch_sync(leQueue, ^{
- [manager stopAdvertising];
- });
+ const auto leQueue = DarwinBluetooth::qt_LE_queue();
+ Q_ASSERT_X(leQueue, Q_FUNC_INFO, "invalid LE queue (nullptr)");
+ const auto manager = peripheralManager.getAs<DarwinBTPeripheralManager>();
+ dispatch_sync(leQueue, ^{
+ [manager stopAdvertising];
+ });
- setState(QLowEnergyController::UnconnectedState);
- } else {
- qCWarning(QT_BT_DARWIN) << "no LE queue found";
- setErrorDescription(QLowEnergyController::UnknownError);
- return;
- }
-#endif
+ setState(QLowEnergyController::UnconnectedState);
}
QT_END_NAMESPACE
diff --git a/src/bluetooth/qlowenergycontroller_darwin_p.h b/src/bluetooth/qlowenergycontroller_darwin_p.h
index b285830c..2782ff59 100644
--- a/src/bluetooth/qlowenergycontroller_darwin_p.h
+++ b/src/bluetooth/qlowenergycontroller_darwin_p.h
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2016 Javier S. Pedro <maemo@javispedro.com>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2022 The Qt Company Ltd.
+// Copyright (C) 2016 Javier S. Pedro <maemo@javispedro.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QLOWENERGYCONTROLLER_DARWIN_P_H
#define QLOWENERGYCONTROLLER_DARWIN_P_H
@@ -79,10 +43,12 @@ public:
~QLowEnergyControllerPrivateDarwin();
void init() override;
+ bool lazyInit();
void connectToDevice() override;
void disconnectFromDevice() override;
void discoverServices() override;
- void discoverServiceDetails(const QBluetoothUuid &serviceUuid) override;
+ void discoverServiceDetails(const QBluetoothUuid &serviceUuid,
+ QLowEnergyService::DiscoveryMode mode) override;
void readCharacteristic(const QSharedPointer<QLowEnergyServicePrivate> service,
const QLowEnergyHandle charHandle) override;
@@ -103,17 +69,24 @@ public:
void addToGenericAttributeList(const QLowEnergyServiceData &service,
QLowEnergyHandle startHandle) override;
+ int mtu() const override;
+ void readRssi() override;
+
void startAdvertising(const QLowEnergyAdvertisingParameters &params,
const QLowEnergyAdvertisingData &advertisingData,
const QLowEnergyAdvertisingData &scanResponseData) override;
void stopAdvertising()override;
QLowEnergyService *addServiceHelper(const QLowEnergyServiceData &service) override;
- bool isValid() const; // QT6 - delete this logic.
+
+ // Valid - a central or peripheral instance was allocated, and this may also
+ // mean a proper usage description was provided/found:
+ bool isValid() const;
private Q_SLOTS:
void _q_connected();
void _q_disconnected();
+ void _q_mtuChanged(int newValue);
void _q_serviceDiscoveryFinished();
void _q_serviceDetailsDiscoveryFinished(QSharedPointer<QLowEnergyServicePrivate> service);
void _q_servicesWereModified();
@@ -143,14 +116,10 @@ private:
const QByteArray &value,
bool appendValue);
- void setErrorDescription(QLowEnergyController::Error errorCode);
bool connectSlots(DarwinBluetooth::LECBManagerNotifier *notifier);
DarwinBluetooth::ScopedPointer centralManager;
-
-#ifndef Q_OS_TVOS
DarwinBluetooth::ScopedPointer peripheralManager;
-#endif
using ServiceMap = QMap<QBluetoothUuid, QSharedPointer<QLowEnergyServicePrivate>>;
};
diff --git a/src/bluetooth/qlowenergycontroller_dummy.cpp b/src/bluetooth/qlowenergycontroller_dummy.cpp
index 2542b355..e271a8a7 100644
--- a/src/bluetooth/qlowenergycontroller_dummy.cpp
+++ b/src/bluetooth/qlowenergycontroller_dummy.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qlowenergycontroller_dummy_p.h"
#include "dummy/dummy_helper_p.h"
@@ -80,7 +44,8 @@ void QLowEnergyControllerPrivateCommon::discoverServices()
}
-void QLowEnergyControllerPrivateCommon::discoverServiceDetails(const QBluetoothUuid &/*service*/)
+void QLowEnergyControllerPrivateCommon::discoverServiceDetails(
+ const QBluetoothUuid & /*service*/, QLowEnergyService::DiscoveryMode /*mode*/)
{
}
@@ -134,4 +99,10 @@ void QLowEnergyControllerPrivateCommon::addToGenericAttributeList(const QLowEner
{
}
+int QLowEnergyControllerPrivateCommon::mtu() const
+{
+ // not supported
+ return -1;
+}
+
QT_END_NAMESPACE
diff --git a/src/bluetooth/qlowenergycontroller_dummy_p.h b/src/bluetooth/qlowenergycontroller_dummy_p.h
index 54a49b53..16fbab3e 100644
--- a/src/bluetooth/qlowenergycontroller_dummy_p.h
+++ b/src/bluetooth/qlowenergycontroller_dummy_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QLOWENERGYCONTROLLERPRIVATE_P_H
#define QLOWENERGYCONTROLLERPRIVATE_P_H
@@ -53,7 +17,6 @@
#include <qglobal.h>
#include <QtCore/QQueue>
-#include <QtCore/QVector>
#include <QtBluetooth/qbluetooth.h>
#include <QtBluetooth/qlowenergycharacteristic.h>
#include "qlowenergycontroller.h"
@@ -78,7 +41,8 @@ public:
void disconnectFromDevice() override;
void discoverServices() override;
- void discoverServiceDetails(const QBluetoothUuid &service) override;
+ void discoverServiceDetails(const QBluetoothUuid &service,
+ QLowEnergyService::DiscoveryMode mode) override;
void startAdvertising(const QLowEnergyAdvertisingParameters &params,
const QLowEnergyAdvertisingData &advertisingData,
@@ -105,6 +69,8 @@ public:
void addToGenericAttributeList(const QLowEnergyServiceData &service,
QLowEnergyHandle startHandle) override;
+
+ int mtu() const override;
};
QT_END_NAMESPACE
diff --git a/src/bluetooth/qlowenergycontroller_win.cpp b/src/bluetooth/qlowenergycontroller_win.cpp
deleted file mode 100644
index ced69685..00000000
--- a/src/bluetooth/qlowenergycontroller_win.cpp
+++ /dev/null
@@ -1,1356 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Copyright (C) 2014 Denis Shienkov <denis.shienkov@gmail.com>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qlowenergycontroller_win_p.h"
-#include "qbluetoothdevicediscoveryagent_p.h"
-
-#include <QtCore/QLoggingCategory>
-#include <QtCore/QIODevice> // for open modes
-#include <QtCore/QEvent>
-#include <QtCore/QMutex>
-#include <QtCore/QThread>
-#include <QtCore/QDataStream>
-#include <QtCore/QCoreApplication>
-
-#include <algorithm> // for std::max
-
-#include <SetupAPI.h>
-
-QT_BEGIN_NAMESPACE
-
-Q_DECLARE_LOGGING_CATEGORY(QT_BT_WINDOWS)
-
-Q_GLOBAL_STATIC(QLibrary, bluetoothapis)
-
-Q_GLOBAL_STATIC(QVector<QLowEnergyControllerPrivateWin32 *>, qControllers)
-static QMutex controllersGuard(QMutex::NonRecursive);
-
-const QEvent::Type CharactericticValueEventType = static_cast<QEvent::Type>(QEvent::User + 1);
-
-class CharactericticValueEvent : public QEvent
-{
-public:
- explicit CharactericticValueEvent(const PBLUETOOTH_GATT_VALUE_CHANGED_EVENT gattValueChangedEvent)
- : QEvent(CharactericticValueEventType)
- , m_handle(0)
- {
- if (!gattValueChangedEvent || gattValueChangedEvent->CharacteristicValueDataSize == 0)
- return;
-
- m_handle = gattValueChangedEvent->ChangedAttributeHandle;
-
- const PBTH_LE_GATT_CHARACTERISTIC_VALUE gattValue = gattValueChangedEvent->CharacteristicValue;
- if (!gattValue)
- return;
-
- m_value = QByteArray(reinterpret_cast<const char *>(&gattValue->Data[0]),
- int(gattValue->DataSize));
- }
-
- QByteArray m_value;
- QLowEnergyHandle m_handle;
-};
-
-// Bit masks of ClientCharacteristicConfiguration value, see btle spec.
-namespace ClientCharacteristicConfigurationValue {
-enum { UseNotifications = 0x1, UseIndications = 0x2 };
-}
-
-static bool gattFunctionsResolved = false;
-
-static QBluetoothAddress getDeviceAddress(const QString &servicePath)
-{
- const int firstbound = servicePath.lastIndexOf(QStringLiteral("_"));
- const int lastbound = servicePath.indexOf(QLatin1Char('#'), firstbound);
- const QString hex = servicePath.mid(firstbound + 1, lastbound - firstbound - 1);
- bool ok = false;
- return QBluetoothAddress(hex.toULongLong(&ok, 16));
-}
-
-static QString getServiceSystemPath(const QBluetoothAddress &deviceAddress,
- const QBluetoothUuid &serviceUuid, int *systemErrorCode)
-{
- const HDEVINFO deviceInfoSet = ::SetupDiGetClassDevs(
- reinterpret_cast<const GUID *>(&serviceUuid),
- nullptr,
- nullptr,
- DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
-
- if (deviceInfoSet == INVALID_HANDLE_VALUE) {
- *systemErrorCode = int(::GetLastError());
- return QString();
- }
-
- QString foundSystemPath;
- DWORD index = 0;
-
- for (;;) {
- SP_DEVICE_INTERFACE_DATA deviceInterfaceData;
- ::ZeroMemory(&deviceInterfaceData, sizeof(deviceInterfaceData));
- deviceInterfaceData.cbSize = sizeof(deviceInterfaceData);
-
- if (!::SetupDiEnumDeviceInterfaces(
- deviceInfoSet,
- nullptr,
- reinterpret_cast<const GUID *>(&serviceUuid),
- index++,
- &deviceInterfaceData)) {
- *systemErrorCode = int(::GetLastError());
- break;
- }
-
- DWORD deviceInterfaceDetailDataSize = 0;
- if (!::SetupDiGetDeviceInterfaceDetail(
- deviceInfoSet,
- &deviceInterfaceData,
- nullptr,
- deviceInterfaceDetailDataSize,
- &deviceInterfaceDetailDataSize,
- nullptr)) {
- const int error = int(::GetLastError());
- if (error != ERROR_INSUFFICIENT_BUFFER) {
- *systemErrorCode = error;
- break;
- }
- }
-
- SP_DEVINFO_DATA deviceInfoData;
- ::ZeroMemory(&deviceInfoData, sizeof(deviceInfoData));
- deviceInfoData.cbSize = sizeof(deviceInfoData);
-
- QByteArray deviceInterfaceDetailDataBuffer(
- int(deviceInterfaceDetailDataSize), 0);
-
- PSP_INTERFACE_DEVICE_DETAIL_DATA deviceInterfaceDetailData =
- reinterpret_cast<PSP_INTERFACE_DEVICE_DETAIL_DATA>
- (deviceInterfaceDetailDataBuffer.data());
-
- deviceInterfaceDetailData->cbSize =
- sizeof(SP_INTERFACE_DEVICE_DETAIL_DATA);
-
- if (!::SetupDiGetDeviceInterfaceDetail(
- deviceInfoSet,
- &deviceInterfaceData,
- deviceInterfaceDetailData,
- DWORD(deviceInterfaceDetailDataBuffer.size()),
- &deviceInterfaceDetailDataSize,
- &deviceInfoData)) {
- *systemErrorCode = int(::GetLastError());
- break;
- }
-
- // We need to check on required device address which contains in a
- // system path. As it is not enough to use only service UUID for this.
- const auto candidateSystemPath = QString::fromWCharArray(deviceInterfaceDetailData->DevicePath);
- const auto candidateDeviceAddress = getDeviceAddress(candidateSystemPath);
- if (candidateDeviceAddress == deviceAddress) {
- foundSystemPath = candidateSystemPath;
- *systemErrorCode = NO_ERROR;
- break;
- }
- }
-
- ::SetupDiDestroyDeviceInfoList(deviceInfoSet);
- return foundSystemPath;
-}
-
-static HANDLE openSystemDevice(
- const QString &systemPath, QIODevice::OpenMode openMode, int *systemErrorCode)
-{
- DWORD desiredAccess = 0;
- DWORD shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
-
- if (openMode & QIODevice::ReadOnly) {
- desiredAccess |= GENERIC_READ;
- }
-
- if (openMode & QIODevice::WriteOnly) {
- desiredAccess |= GENERIC_WRITE;
- shareMode &= ~DWORD(FILE_SHARE_WRITE);
- }
-
- const HANDLE hDevice = ::CreateFile(
- reinterpret_cast<const wchar_t *>(systemPath.utf16()),
- desiredAccess,
- shareMode,
- nullptr,
- OPEN_EXISTING,
- 0,
- nullptr);
-
- *systemErrorCode = (INVALID_HANDLE_VALUE == hDevice)
- ? int(::GetLastError()) : NO_ERROR;
- return hDevice;
-}
-
-static HANDLE openSystemService(const QBluetoothAddress &deviceAddress,
- const QBluetoothUuid &service, QIODevice::OpenMode openMode, int *systemErrorCode)
-{
- const QString serviceSystemPath = getServiceSystemPath(
- deviceAddress, service, systemErrorCode);
-
- if (*systemErrorCode != NO_ERROR)
- return INVALID_HANDLE_VALUE;
-
- const HANDLE hService = openSystemDevice(
- serviceSystemPath, openMode, systemErrorCode);
-
- if (*systemErrorCode != NO_ERROR)
- return INVALID_HANDLE_VALUE;
-
- return hService;
-}
-
-static void closeSystemDevice(HANDLE hDevice)
-{
- if (hDevice && hDevice != INVALID_HANDLE_VALUE)
- ::CloseHandle(hDevice);
-}
-
-static QVector<BTH_LE_GATT_SERVICE> enumeratePrimaryGattServices(
- HANDLE hDevice, int *systemErrorCode)
-{
- if (!gattFunctionsResolved) {
- *systemErrorCode = ERROR_NOT_SUPPORTED;
- return QVector<BTH_LE_GATT_SERVICE>();
- }
-
- QVector<BTH_LE_GATT_SERVICE> foundServices;
- USHORT servicesCount = 0;
- for (;;) {
- const HRESULT hr = ::BluetoothGATTGetServices(
- hDevice,
- servicesCount,
- foundServices.isEmpty() ? nullptr : &foundServices[0],
- &servicesCount,
- BLUETOOTH_GATT_FLAG_NONE);
-
- if (SUCCEEDED(hr)) {
- *systemErrorCode = NO_ERROR;
- return foundServices;
- } else {
- const int error = WIN32_FROM_HRESULT(hr);
- if (error == ERROR_MORE_DATA) {
- foundServices.resize(servicesCount);
- } else {
- *systemErrorCode = error;
- return QVector<BTH_LE_GATT_SERVICE>();
- }
- }
- }
-}
-
-static QVector<BTH_LE_GATT_CHARACTERISTIC> enumerateGattCharacteristics(
- HANDLE hService, PBTH_LE_GATT_SERVICE gattService, int *systemErrorCode)
-{
- if (!gattFunctionsResolved) {
- *systemErrorCode = ERROR_NOT_SUPPORTED;
- return QVector<BTH_LE_GATT_CHARACTERISTIC>();
- }
-
- QVector<BTH_LE_GATT_CHARACTERISTIC> foundCharacteristics;
- USHORT characteristicsCount = 0;
- for (;;) {
- const HRESULT hr = ::BluetoothGATTGetCharacteristics(
- hService,
- gattService,
- characteristicsCount,
- foundCharacteristics.isEmpty() ? nullptr : &foundCharacteristics[0],
- &characteristicsCount,
- BLUETOOTH_GATT_FLAG_NONE);
-
- if (SUCCEEDED(hr)) {
- *systemErrorCode = NO_ERROR;
- return foundCharacteristics;
- } else {
- const int error = WIN32_FROM_HRESULT(hr);
- if (error == ERROR_MORE_DATA) {
- foundCharacteristics.resize(characteristicsCount);
- } else {
- *systemErrorCode = error;
- return QVector<BTH_LE_GATT_CHARACTERISTIC>();
- }
- }
- }
-}
-
-static QByteArray getGattCharacteristicValue(
- HANDLE hService, PBTH_LE_GATT_CHARACTERISTIC gattCharacteristic, int *systemErrorCode)
-{
- if (!gattFunctionsResolved) {
- *systemErrorCode = ERROR_NOT_SUPPORTED;
- return QByteArray();
- }
-
- QByteArray valueBuffer;
- USHORT valueBufferSize = 0;
- for (;;) {
- const auto valuePtr = valueBuffer.isEmpty()
- ? nullptr
- : reinterpret_cast<PBTH_LE_GATT_CHARACTERISTIC_VALUE>(valueBuffer.data());
-
- const HRESULT hr = ::BluetoothGATTGetCharacteristicValue(
- hService,
- gattCharacteristic,
- valueBufferSize,
- valuePtr,
- &valueBufferSize,
- BLUETOOTH_GATT_FLAG_NONE);
-
- if (SUCCEEDED(hr)) {
- *systemErrorCode = NO_ERROR;
- return QByteArray(reinterpret_cast<const char *>(&valuePtr->Data[0]),
- int(valuePtr->DataSize));
- } else {
- const int error = WIN32_FROM_HRESULT(hr);
- if (error == ERROR_MORE_DATA) {
- valueBuffer.resize(valueBufferSize);
- valueBuffer.fill(0);
- } else {
- *systemErrorCode = error;
- return QByteArray();
- }
- }
- }
-}
-
-static void setGattCharacteristicValue(
- HANDLE hService, PBTH_LE_GATT_CHARACTERISTIC gattCharacteristic,
- const QByteArray &value, DWORD flags, int *systemErrorCode)
-{
- if (!gattFunctionsResolved) {
- *systemErrorCode = ERROR_NOT_SUPPORTED;
- return;
- }
-
- QByteArray valueBuffer;
- QDataStream out(&valueBuffer, QIODevice::WriteOnly);
- ULONG dataSize = ULONG(value.size());
- out.writeRawData(reinterpret_cast<const char *>(&dataSize), sizeof(dataSize));
- out.writeRawData(value.constData(), value.size());
-
- BTH_LE_GATT_RELIABLE_WRITE_CONTEXT reliableWriteContext = 0;
-
- const HRESULT hr = ::BluetoothGATTSetCharacteristicValue(
- hService,
- gattCharacteristic,
- reinterpret_cast<PBTH_LE_GATT_CHARACTERISTIC_VALUE>(valueBuffer.data()),
- reliableWriteContext,
- flags);
-
- if (SUCCEEDED(hr))
- *systemErrorCode = NO_ERROR;
- else
- *systemErrorCode = WIN32_FROM_HRESULT(hr);
-}
-
-static QVector<BTH_LE_GATT_DESCRIPTOR> enumerateGattDescriptors(
- HANDLE hService, PBTH_LE_GATT_CHARACTERISTIC gattCharacteristic, int *systemErrorCode)
-{
- if (!gattFunctionsResolved) {
- *systemErrorCode = ERROR_NOT_SUPPORTED;
- return QVector<BTH_LE_GATT_DESCRIPTOR>();
- }
-
- QVector<BTH_LE_GATT_DESCRIPTOR> foundDescriptors;
- USHORT descriptorsCount = 0;
- for (;;) {
- const HRESULT hr = ::BluetoothGATTGetDescriptors(
- hService,
- gattCharacteristic,
- descriptorsCount,
- foundDescriptors.isEmpty() ? nullptr : &foundDescriptors[0],
- &descriptorsCount,
- BLUETOOTH_GATT_FLAG_NONE);
-
- if (SUCCEEDED(hr)) {
- *systemErrorCode = NO_ERROR;
- return foundDescriptors;
- } else {
- const int error = WIN32_FROM_HRESULT(hr);
- if (error == ERROR_MORE_DATA) {
- foundDescriptors.resize(descriptorsCount);
- } else {
- *systemErrorCode = error;
- return QVector<BTH_LE_GATT_DESCRIPTOR>();
- }
- }
- }
-}
-
-static QByteArray getGattDescriptorValue(
- HANDLE hService, PBTH_LE_GATT_DESCRIPTOR gattDescriptor, int *systemErrorCode)
-{
- if (!gattFunctionsResolved) {
- *systemErrorCode = ERROR_NOT_SUPPORTED;
- return QByteArray();
- }
-
- QByteArray valueBuffer;
- USHORT valueBufferSize = 0;
- for (;;) {
- const auto valuePtr = valueBuffer.isEmpty()
- ? nullptr
- : reinterpret_cast<PBTH_LE_GATT_DESCRIPTOR_VALUE>(valueBuffer.data());
-
- const HRESULT hr = ::BluetoothGATTGetDescriptorValue(
- hService,
- gattDescriptor,
- valueBufferSize,
- valuePtr,
- &valueBufferSize,
- BLUETOOTH_GATT_FLAG_NONE);
-
- if (SUCCEEDED(hr)) {
- *systemErrorCode = NO_ERROR;
- if (gattDescriptor->DescriptorType == CharacteristicUserDescription) {
- QString valueString = QString::fromUtf16(reinterpret_cast<const ushort *>(&valuePtr->Data[0]),
- valuePtr->DataSize/2);
- return valueString.toUtf8();
- }
- return QByteArray(reinterpret_cast<const char *>(&valuePtr->Data[0]),
- int(valuePtr->DataSize));
- } else {
- const int error = WIN32_FROM_HRESULT(hr);
- if (error == ERROR_MORE_DATA) {
- valueBuffer.resize(valueBufferSize);
- valueBuffer.fill(0);
- } else {
- *systemErrorCode = error;
- return QByteArray();
- }
- }
- }
-}
-
-static void setGattDescriptorValue(
- HANDLE hService, PBTH_LE_GATT_DESCRIPTOR gattDescriptor,
- QByteArray value, int *systemErrorCode)
-{
- if (!gattFunctionsResolved) {
- *systemErrorCode = ERROR_NOT_SUPPORTED;
- return;
- }
-
- const int requiredValueBufferSize = int(sizeof(BTH_LE_GATT_DESCRIPTOR_VALUE))
- + value.size();
-
- QByteArray valueBuffer(requiredValueBufferSize, 0);
-
- PBTH_LE_GATT_DESCRIPTOR_VALUE gattValue = reinterpret_cast<
- PBTH_LE_GATT_DESCRIPTOR_VALUE>(valueBuffer.data());
-
- gattValue->DescriptorType = gattDescriptor->DescriptorType;
-
- if (gattValue->DescriptorType == ClientCharacteristicConfiguration) {
- QDataStream in(value);
- quint8 u;
- in >> u;
-
- // We need to setup appropriate fields that allow to subscribe for events.
- gattValue->ClientCharacteristicConfiguration.IsSubscribeToNotification =
- bool(u & ClientCharacteristicConfigurationValue::UseNotifications);
- gattValue->ClientCharacteristicConfiguration.IsSubscribeToIndication =
- bool(u & ClientCharacteristicConfigurationValue::UseIndications);
- }
-
- gattValue->DataSize = ULONG(value.size());
- ::memcpy(gattValue->Data, value.constData(), size_t(value.size()));
-
- const HRESULT hr = ::BluetoothGATTSetDescriptorValue(
- hService,
- gattDescriptor,
- gattValue,
- BLUETOOTH_GATT_FLAG_NONE);
-
- if (SUCCEEDED(hr))
- *systemErrorCode = NO_ERROR;
- else
- *systemErrorCode = WIN32_FROM_HRESULT(hr);
-}
-
-static void WINAPI eventChangedCallbackEntry(
- BTH_LE_GATT_EVENT_TYPE eventType, PVOID eventOutParameter, PVOID context)
-{
- if ((eventType != CharacteristicValueChangedEvent) || !eventOutParameter || !context)
- return;
-
- QMutexLocker locker(&controllersGuard);
- const auto target = static_cast<QLowEnergyControllerPrivateWin32 *>(context);
- if (!qControllers->contains(target))
- return;
-
- CharactericticValueEvent *e = new CharactericticValueEvent(
- reinterpret_cast<const PBLUETOOTH_GATT_VALUE_CHANGED_EVENT>(eventOutParameter));
-
- QCoreApplication::postEvent(target, e);
-}
-
-static HANDLE registerEvent(
- HANDLE hService, BTH_LE_GATT_CHARACTERISTIC gattCharacteristic,
- PVOID context, int *systemErrorCode)
-{
- if (!gattFunctionsResolved) {
- *systemErrorCode = ERROR_NOT_SUPPORTED;
- return INVALID_HANDLE_VALUE;
- }
-
- HANDLE hEvent = INVALID_HANDLE_VALUE;
-
- BLUETOOTH_GATT_VALUE_CHANGED_EVENT_REGISTRATION registration;
- ::ZeroMemory(&registration, sizeof(registration));
- registration.NumCharacteristics = 1;
- registration.Characteristics[0] = gattCharacteristic;
-
- const HRESULT hr = ::BluetoothGATTRegisterEvent(
- hService,
- CharacteristicValueChangedEvent,
- &registration,
- eventChangedCallbackEntry,
- context,
- &hEvent,
- BLUETOOTH_GATT_FLAG_NONE);
-
- if (SUCCEEDED(hr))
- *systemErrorCode = NO_ERROR;
- else
- *systemErrorCode = WIN32_FROM_HRESULT(hr);
-
- return hEvent;
-}
-
-static void unregisterEvent(HANDLE hEvent, int *systemErrorCode)
-{
- if (!gattFunctionsResolved) {
- *systemErrorCode = ERROR_NOT_SUPPORTED;
- return;
- }
-
- const HRESULT hr = ::BluetoothGATTUnregisterEvent(
- hEvent,
- BLUETOOTH_GATT_FLAG_NONE);
-
- if (SUCCEEDED(hr))
- *systemErrorCode = NO_ERROR;
- else
- *systemErrorCode = WIN32_FROM_HRESULT(hr);
-}
-
-static QBluetoothUuid qtBluetoothUuidFromNativeLeUuid(const BTH_LE_UUID &uuid)
-{
- return uuid.IsShortUuid ? QBluetoothUuid(uuid.Value.ShortUuid)
- : QBluetoothUuid(uuid.Value.LongUuid);
-}
-
-static BTH_LE_UUID nativeLeUuidFromQtBluetoothUuid(const QBluetoothUuid &uuid)
-{
- BTH_LE_UUID gattUuid;
- ::ZeroMemory(&gattUuid, sizeof(gattUuid));
- if (uuid.minimumSize() == 2) {
- gattUuid.IsShortUuid = TRUE;
- gattUuid.Value.ShortUuid = USHORT(uuid.data1); // other fields should be empty!
- } else {
- gattUuid.Value.LongUuid = uuid;
- }
- return gattUuid;
-}
-
-static BTH_LE_GATT_CHARACTERISTIC recoverNativeLeGattCharacteristic(
- QLowEnergyHandle serviceHandle, QLowEnergyHandle characteristicHandle,
- const QLowEnergyServicePrivate::CharData &characteristicData)
-{
- BTH_LE_GATT_CHARACTERISTIC gattCharacteristic;
-
- gattCharacteristic.ServiceHandle = serviceHandle;
- gattCharacteristic.AttributeHandle = characteristicHandle;
- gattCharacteristic.CharacteristicValueHandle = characteristicData.valueHandle;
-
- gattCharacteristic.CharacteristicUuid = nativeLeUuidFromQtBluetoothUuid(
- characteristicData.uuid);
-
- gattCharacteristic.HasExtendedProperties = bool(characteristicData.properties
- & QLowEnergyCharacteristic::ExtendedProperty);
- gattCharacteristic.IsBroadcastable = bool(characteristicData.properties
- & QLowEnergyCharacteristic::Broadcasting);
- gattCharacteristic.IsIndicatable = bool(characteristicData.properties
- & QLowEnergyCharacteristic::Indicate);
- gattCharacteristic.IsNotifiable = bool(characteristicData.properties
- & QLowEnergyCharacteristic::Notify);
- gattCharacteristic.IsReadable = bool(characteristicData.properties
- & QLowEnergyCharacteristic::Read);
- gattCharacteristic.IsSignedWritable = bool(characteristicData.properties
- & QLowEnergyCharacteristic::WriteSigned);
- gattCharacteristic.IsWritable = bool(characteristicData.properties
- & QLowEnergyCharacteristic::Write);
- gattCharacteristic.IsWritableWithoutResponse = bool(characteristicData.properties
- & QLowEnergyCharacteristic::WriteNoResponse);
-
- return gattCharacteristic;
-}
-
-static BTH_LE_GATT_DESCRIPTOR_TYPE nativeLeGattDescriptorTypeFromUuid(
- const QBluetoothUuid &uuid)
-{
- switch (uuid.toUInt16()) {
- case QBluetoothUuid::CharacteristicExtendedProperties:
- return CharacteristicExtendedProperties;
- case QBluetoothUuid::CharacteristicUserDescription:
- return CharacteristicUserDescription;
- case QBluetoothUuid::ClientCharacteristicConfiguration:
- return ClientCharacteristicConfiguration;
- case QBluetoothUuid::ServerCharacteristicConfiguration:
- return ServerCharacteristicConfiguration;
- case QBluetoothUuid::CharacteristicPresentationFormat:
- return CharacteristicFormat;
- case QBluetoothUuid::CharacteristicAggregateFormat:
- return CharacteristicAggregateFormat;
- default:
- return CustomDescriptor;
- }
-}
-
-static BTH_LE_GATT_DESCRIPTOR recoverNativeLeGattDescriptor(
- QLowEnergyHandle serviceHandle, QLowEnergyHandle characteristicHandle,
- QLowEnergyHandle descriptorHandle,
- const QLowEnergyServicePrivate::DescData &descriptorData)
-{
- BTH_LE_GATT_DESCRIPTOR gattDescriptor;
-
- gattDescriptor.ServiceHandle = serviceHandle;
- gattDescriptor.CharacteristicHandle = characteristicHandle;
- gattDescriptor.AttributeHandle = descriptorHandle;
-
- gattDescriptor.DescriptorUuid = nativeLeUuidFromQtBluetoothUuid(
- descriptorData.uuid);
-
- gattDescriptor.DescriptorType = nativeLeGattDescriptorTypeFromUuid
- (descriptorData.uuid);
-
- return gattDescriptor;
-}
-
-void QLowEnergyControllerPrivateWin32::customEvent(QEvent *e)
-{
- if (e->type() != CharactericticValueEventType)
- return;
-
- const CharactericticValueEvent *characteristicEvent
- = static_cast<CharactericticValueEvent *>(e);
-
- updateValueOfCharacteristic(characteristicEvent->m_handle,
- characteristicEvent->m_value, false);
-
- const QSharedPointer<QLowEnergyServicePrivate> service = serviceForHandle(
- characteristicEvent->m_handle);
- if (service.isNull())
- return;
-
- const QLowEnergyCharacteristic ch(service, characteristicEvent->m_handle);
- emit service->characteristicChanged(ch, characteristicEvent->m_value);
-}
-
-QLowEnergyControllerPrivateWin32::QLowEnergyControllerPrivateWin32()
- : QLowEnergyControllerPrivate()
-{
- QMutexLocker locker(&controllersGuard);
- qControllers()->append(this);
-
- gattFunctionsResolved = resolveFunctions(bluetoothapis());
- if (!gattFunctionsResolved) {
- qCWarning(QT_BT_WINDOWS) << "LE is not supported on this OS";
- return;
- }
-}
-
-QLowEnergyControllerPrivateWin32::~QLowEnergyControllerPrivateWin32()
-{
- QMutexLocker locker(&controllersGuard);
- qControllers()->removeAll(this);
-}
-
-void QLowEnergyControllerPrivateWin32::init()
-{
-}
-
-void QLowEnergyControllerPrivateWin32::connectToDevice()
-{
- // required to pass unit test on default backend
- if (remoteDevice.isNull()) {
- qWarning() << "Invalid/null remote device address";
- setError(QLowEnergyController::UnknownRemoteDeviceError);
- return;
- }
-
- if (!deviceSystemPath.isEmpty()) {
- qCDebug(QT_BT_WINDOWS) << "Already is connected";
- return;
- }
-
- setState(QLowEnergyController::ConnectingState);
-
- deviceSystemPath =
- QBluetoothDeviceDiscoveryAgentPrivate::discoveredLeDeviceSystemPath(
- remoteDevice);
-
- if (deviceSystemPath.isEmpty()) {
- qCWarning(QT_BT_WINDOWS) << qt_error_string(ERROR_PATH_NOT_FOUND);
- setError(QLowEnergyController::UnknownRemoteDeviceError);
- setState(QLowEnergyController::UnconnectedState);
- return;
- }
-
- setState(QLowEnergyController::ConnectedState);
-
- thread = new QThread;
- threadWorker = new ThreadWorker;
- threadWorker->moveToThread(thread);
- connect(threadWorker, &ThreadWorker::jobFinished, this, &QLowEnergyControllerPrivateWin32::jobFinished);
- connect(thread, &QThread::finished, threadWorker, &ThreadWorker::deleteLater);
- connect(thread, &QThread::finished, thread, &QThread::deleteLater);
- thread->start();
-
- Q_Q(QLowEnergyController);
- emit q->connected();
-}
-
-void QLowEnergyControllerPrivateWin32::disconnectFromDevice()
-{
- if (deviceSystemPath.isEmpty()) {
- qCDebug(QT_BT_WINDOWS) << "Already is disconnected";
- return;
- }
-
- setState(QLowEnergyController::ClosingState);
- deviceSystemPath.clear();
- setState(QLowEnergyController::UnconnectedState);
-
- if (thread) {
- disconnect(threadWorker, &ThreadWorker::jobFinished, this, &QLowEnergyControllerPrivateWin32::jobFinished);
- thread->quit();
- thread = nullptr;
- }
-
- for (const auto &servicePrivate: serviceList)
- closeSystemDevice(servicePrivate->hService);
-
- Q_Q(QLowEnergyController);
- emit q->disconnected();
-}
-
-void QLowEnergyControllerPrivateWin32::discoverServices()
-{
- int systemErrorCode = NO_ERROR;
-
- const HANDLE hDevice = openSystemDevice(
- deviceSystemPath, QIODevice::ReadOnly, &systemErrorCode);
-
- if (systemErrorCode != NO_ERROR) {
- qCWarning(QT_BT_WINDOWS) << qt_error_string(systemErrorCode);
- setError(QLowEnergyController::NetworkError);
- setState(QLowEnergyController::ConnectedState);
- return;
- }
-
- const QVector<BTH_LE_GATT_SERVICE> foundServices =
- enumeratePrimaryGattServices(hDevice, &systemErrorCode);
-
- closeSystemDevice(hDevice);
-
- if (systemErrorCode != NO_ERROR) {
- qCWarning(QT_BT_WINDOWS) << qt_error_string(systemErrorCode);
- setError(QLowEnergyController::NetworkError);
- setState(QLowEnergyController::ConnectedState);
- return;
- }
-
- setState(QLowEnergyController::DiscoveringState);
-
- Q_Q(QLowEnergyController);
-
- for (const BTH_LE_GATT_SERVICE &service : foundServices) {
- const QBluetoothUuid uuid = qtBluetoothUuidFromNativeLeUuid(
- service.ServiceUuid);
- qCDebug(QT_BT_WINDOWS) << "Found uuid:" << uuid;
-
- QLowEnergyServicePrivate *priv = new QLowEnergyServicePrivate();
- priv->uuid = uuid;
- priv->type = QLowEnergyService::PrimaryService;
- priv->startHandle = service.AttributeHandle;
- priv->setController(this);
-
- QSharedPointer<QLowEnergyServicePrivate> pointer(priv);
- serviceList.insert(uuid, pointer);
-
- emit q->serviceDiscovered(uuid);
- }
-
- setState(QLowEnergyController::DiscoveredState);
- emit q->discoveryFinished();
-}
-
-void QLowEnergyControllerPrivateWin32::discoverServiceDetails(
- const QBluetoothUuid &service)
-{
- if (!serviceList.contains(service)) {
- qCWarning(QT_BT_WINDOWS) << "Discovery of unknown service" << service.toString()
- << "not possible";
- return;
- }
-
- const QSharedPointer<QLowEnergyServicePrivate> servicePrivate =
- serviceList.value(service);
-
- int systemErrorCode = NO_ERROR;
-
- // Only open a service once and close it in the QLowEnergyServicePrivate destructor
- if (!servicePrivate->hService || servicePrivate->hService == INVALID_HANDLE_VALUE) {
- servicePrivate->hService = openSystemService(remoteDevice, service,
- QIODevice::ReadOnly | QIODevice::WriteOnly,
- &systemErrorCode);
- if (systemErrorCode != NO_ERROR) {
- servicePrivate->hService = openSystemService(remoteDevice, service,
- QIODevice::ReadOnly,
- &systemErrorCode);
- }
- }
-
- if (systemErrorCode != NO_ERROR) {
- qCWarning(QT_BT_WINDOWS) << "Unable to open service" << service.toString()
- << ":" << qt_error_string(systemErrorCode);
- servicePrivate->setError(QLowEnergyService::UnknownError);
- servicePrivate->setState(QLowEnergyService::DiscoveryRequired);
- return;
- }
-
- // We assume that the service does not have any characteristics with descriptors.
- servicePrivate->endHandle = servicePrivate->startHandle;
-
- const QVector<BTH_LE_GATT_CHARACTERISTIC> foundCharacteristics =
- enumerateGattCharacteristics(servicePrivate->hService, nullptr, &systemErrorCode);
-
- if (systemErrorCode != NO_ERROR) {
- qCWarning(QT_BT_WINDOWS) << "Unable to get characteristics for service" << service.toString()
- << ":" << qt_error_string(systemErrorCode);
- servicePrivate->setError(QLowEnergyService::CharacteristicReadError);
- servicePrivate->setState(QLowEnergyService::DiscoveryRequired);
- return;
- }
-
- for (const BTH_LE_GATT_CHARACTERISTIC &gattCharacteristic : foundCharacteristics) {
- const QLowEnergyHandle characteristicHandle = gattCharacteristic.AttributeHandle;
-
- QLowEnergyServicePrivate::CharData detailsData;
-
- detailsData.hValueChangeEvent = nullptr;
-
- detailsData.uuid = qtBluetoothUuidFromNativeLeUuid(
- gattCharacteristic.CharacteristicUuid);
- detailsData.valueHandle = gattCharacteristic.CharacteristicValueHandle;
-
- QLowEnergyCharacteristic::PropertyTypes properties = QLowEnergyCharacteristic::Unknown;
- if (gattCharacteristic.HasExtendedProperties)
- properties |= QLowEnergyCharacteristic::ExtendedProperty;
- if (gattCharacteristic.IsBroadcastable)
- properties |= QLowEnergyCharacteristic::Broadcasting;
- if (gattCharacteristic.IsIndicatable)
- properties |= QLowEnergyCharacteristic::Indicate;
- if (gattCharacteristic.IsNotifiable)
- properties |= QLowEnergyCharacteristic::Notify;
- if (gattCharacteristic.IsReadable)
- properties |= QLowEnergyCharacteristic::Read;
- if (gattCharacteristic.IsSignedWritable)
- properties |= QLowEnergyCharacteristic::WriteSigned;
- if (gattCharacteristic.IsWritable)
- properties |= QLowEnergyCharacteristic::Write;
- if (gattCharacteristic.IsWritableWithoutResponse)
- properties |= QLowEnergyCharacteristic::WriteNoResponse;
-
- detailsData.properties = properties;
- detailsData.value = getGattCharacteristicValue(
- servicePrivate->hService, const_cast<PBTH_LE_GATT_CHARACTERISTIC>(
- &gattCharacteristic), &systemErrorCode);
-
- if (systemErrorCode != NO_ERROR) {
- // We do not interrupt enumerating of characteristics
- // if value can not be read
- qCWarning(QT_BT_WINDOWS) << "Unable to get value for characteristic"
- << detailsData.uuid.toString()
- << "of the service" << service.toString()
- << ":" << qt_error_string(systemErrorCode);
- }
-
- // We assume that the characteristic has no any descriptors. So, the
- // biggest characteristic + 1 will indicate an end handle of service.
- servicePrivate->endHandle = std::max(
- servicePrivate->endHandle,
- QLowEnergyHandle(gattCharacteristic.AttributeHandle + 1));
-
- const QVector<BTH_LE_GATT_DESCRIPTOR> foundDescriptors = enumerateGattDescriptors(
- servicePrivate->hService, const_cast<PBTH_LE_GATT_CHARACTERISTIC>(
- &gattCharacteristic), &systemErrorCode);
-
- if (systemErrorCode != NO_ERROR) {
- if (systemErrorCode != ERROR_NOT_FOUND) {
- qCWarning(QT_BT_WINDOWS) << "Unable to get descriptor for characteristic"
- << detailsData.uuid.toString()
- << "of the service" << service.toString()
- << ":" << qt_error_string(systemErrorCode);
- servicePrivate->setError(QLowEnergyService::DescriptorReadError);
- servicePrivate->setState(QLowEnergyService::DiscoveryRequired);
- return;
- }
- }
-
- for (const BTH_LE_GATT_DESCRIPTOR &gattDescriptor : foundDescriptors) {
- const QLowEnergyHandle descriptorHandle = gattDescriptor.AttributeHandle;
-
- QLowEnergyServicePrivate::DescData data;
- data.uuid = qtBluetoothUuidFromNativeLeUuid(
- gattDescriptor.DescriptorUuid);
-
- data.value = getGattDescriptorValue(servicePrivate->hService, const_cast<PBTH_LE_GATT_DESCRIPTOR>(
- &gattDescriptor), &systemErrorCode);
-
- if (systemErrorCode != NO_ERROR) {
- qCWarning(QT_BT_WINDOWS) << "Unable to get value for descriptor"
- << data.uuid.toString()
- << "for characteristic"
- << detailsData.uuid.toString()
- << "of the service" << service.toString()
- << ":" << qt_error_string(systemErrorCode);
- servicePrivate->setError(QLowEnergyService::DescriptorReadError);
- servicePrivate->setState(QLowEnergyService::DiscoveryRequired);
- return;
- }
-
- // Biggest descriptor will contain an end handle of service.
- servicePrivate->endHandle = std::max(
- servicePrivate->endHandle,
- QLowEnergyHandle(gattDescriptor.AttributeHandle));
-
- detailsData.descriptorList.insert(descriptorHandle, data);
- }
-
- servicePrivate->characteristicList.insert(characteristicHandle, detailsData);
- }
-
- servicePrivate->setState(QLowEnergyService::ServiceDiscovered);
-}
-
-void QLowEnergyControllerPrivateWin32::startAdvertising(const QLowEnergyAdvertisingParameters &, const QLowEnergyAdvertisingData &, const QLowEnergyAdvertisingData &)
-{
- Q_UNIMPLEMENTED();
-}
-
-void QLowEnergyControllerPrivateWin32::stopAdvertising()
-{
- Q_UNIMPLEMENTED();
-}
-
-void QLowEnergyControllerPrivateWin32::requestConnectionUpdate(const QLowEnergyConnectionParameters &)
-{
- Q_UNIMPLEMENTED();
-}
-
-void QLowEnergyControllerPrivateWin32::readCharacteristic(
- const QSharedPointer<QLowEnergyServicePrivate> service,
- const QLowEnergyHandle charHandle)
-{
- Q_ASSERT(!service.isNull());
- if (!service->characteristicList.contains(charHandle))
- return;
-
- const QLowEnergyServicePrivate::CharData &charDetails
- = service->characteristicList[charHandle];
- if (!(charDetails.properties & QLowEnergyCharacteristic::Read)) {
- // if this succeeds the device has a bug, char is advertised as
- // non-readable. We try to be permissive and let the remote
- // device answer to the read attempt
- qCWarning(QT_BT_WINDOWS) << "Reading non-readable char" << charHandle;
- }
-
- ReadCharData data;
- data.systemErrorCode = NO_ERROR;
- data.hService = service->hService;
-
- if (data.systemErrorCode != NO_ERROR) {
- qCWarning(QT_BT_WINDOWS) << "Unable to open service" << service->uuid.toString()
- << ":" << qt_error_string(data.systemErrorCode);
- service->setError(QLowEnergyService::CharacteristicReadError);
- return;
- }
-
- data.gattCharacteristic = recoverNativeLeGattCharacteristic(
- service->startHandle, charHandle, charDetails);
-
- ThreadWorkerJob job;
- job.operation = ThreadWorkerJob::ReadChar;
- job.data = QVariant::fromValue(data);
-
- QMetaObject::invokeMethod(threadWorker, "putJob", Qt::QueuedConnection,
- Q_ARG(ThreadWorkerJob, job));
-}
-
-void QLowEnergyControllerPrivateWin32::writeCharacteristic(
- const QSharedPointer<QLowEnergyServicePrivate> service,
- const QLowEnergyHandle charHandle,
- const QByteArray &newValue,
- QLowEnergyService::WriteMode mode)
-{
- Q_ASSERT(!service.isNull());
-
- if (!service->characteristicList.contains(charHandle)) {
- service->setError(QLowEnergyService::CharacteristicWriteError);
- return;
- }
-
- WriteCharData data;
- data.systemErrorCode = NO_ERROR;
- data.hService = service->hService;
-
- if (data.systemErrorCode != NO_ERROR) {
- qCWarning(QT_BT_WINDOWS) << "Unable to open service" << service->uuid.toString()
- << ":" << qt_error_string(data.systemErrorCode);
- service->setError(QLowEnergyService::CharacteristicWriteError);
- return;
- }
-
- const QLowEnergyServicePrivate::CharData &charDetails
- = service->characteristicList[charHandle];
-
- data.gattCharacteristic = recoverNativeLeGattCharacteristic(
- service->startHandle, charHandle, charDetails);
-
- data.flags = (mode == QLowEnergyService::WriteWithResponse)
- ? BLUETOOTH_GATT_FLAG_NONE
- : BLUETOOTH_GATT_FLAG_WRITE_WITHOUT_RESPONSE;
-
- ThreadWorkerJob job;
- job.operation = ThreadWorkerJob::WriteChar;
- data.newValue = newValue;
- data.mode = mode;
- job.data = QVariant::fromValue(data);
-
- QMetaObject::invokeMethod(threadWorker, "putJob", Qt::QueuedConnection,
- Q_ARG(ThreadWorkerJob, job));
-}
-
-void QLowEnergyControllerPrivateWin32::jobFinished(const ThreadWorkerJob &job)
-{
- switch (job.operation) {
- case ThreadWorkerJob::WriteChar:
- {
- const WriteCharData data = job.data.value<WriteCharData>();
- const QLowEnergyHandle charHandle = static_cast<QLowEnergyHandle>(data.gattCharacteristic.AttributeHandle);
- const QSharedPointer<QLowEnergyServicePrivate> service = serviceForHandle(charHandle);
-
- if (data.systemErrorCode != NO_ERROR) {
- const QLowEnergyServicePrivate::CharData &charDetails = service->characteristicList[charHandle];
- qCWarning(QT_BT_WINDOWS) << "Unable to set value for characteristic"
- << charDetails.uuid.toString()
- << "of the service" << service->uuid.toString()
- << ":" << qt_error_string(data.systemErrorCode);
- service->setError(QLowEnergyService::CharacteristicWriteError);
- return;
- }
-
- updateValueOfCharacteristic(charHandle, data.newValue, false);
-
- if (data.mode == QLowEnergyService::WriteWithResponse) {
- const QLowEnergyCharacteristic ch = characteristicForHandle(charHandle);
- emit service->characteristicWritten(ch, data.newValue);
- }
- }
- break;
- case ThreadWorkerJob::ReadChar:
- {
- const ReadCharData data = job.data.value<ReadCharData>();
- const QLowEnergyHandle charHandle = static_cast<QLowEnergyHandle>(data.gattCharacteristic.AttributeHandle);
- const QSharedPointer<QLowEnergyServicePrivate> service = serviceForHandle(charHandle);
-
- if (data.systemErrorCode != NO_ERROR) {
- const QLowEnergyServicePrivate::CharData &charDetails = service->characteristicList[charHandle];
- qCWarning(QT_BT_WINDOWS) << "Unable to get value for characteristic"
- << charDetails.uuid.toString()
- << "of the service" << service->uuid.toString()
- << ":" << qt_error_string(data.systemErrorCode);
- service->setError(QLowEnergyService::CharacteristicReadError);
- return;
- }
-
- updateValueOfCharacteristic(charHandle, data.value, false);
-
- const QLowEnergyCharacteristic ch(service, charHandle);
- emit service->characteristicRead(ch, data.value);
- }
- break;
- case ThreadWorkerJob::WriteDescr:
- {
- WriteDescData data = job.data.value<WriteDescData>();
- const QLowEnergyHandle descriptorHandle = static_cast<QLowEnergyHandle>(data.gattDescriptor.AttributeHandle);
- const QLowEnergyHandle charHandle = static_cast<QLowEnergyHandle>(data.gattDescriptor.CharacteristicHandle);
- const QSharedPointer<QLowEnergyServicePrivate> service = serviceForHandle(charHandle);
- QLowEnergyServicePrivate::CharData &charDetails = service->characteristicList[charHandle];
- const QLowEnergyServicePrivate::DescData &dscrDetails = charDetails.descriptorList[descriptorHandle];
-
- if (data.systemErrorCode != NO_ERROR) {
- qCWarning(QT_BT_WINDOWS) << "Unable to set value for descriptor"
- << dscrDetails.uuid.toString()
- << "for characteristic"
- << charDetails.uuid.toString()
- << "of the service" << service->uuid.toString()
- << ":" << qt_error_string(data.systemErrorCode);
- service->setError(QLowEnergyService::DescriptorWriteError);
- return;
- }
-
- if (data.gattDescriptor.DescriptorType == ClientCharacteristicConfiguration) {
-
- QDataStream in(data.newValue);
- quint8 u;
- in >> u;
-
- if (u & ClientCharacteristicConfigurationValue::UseNotifications
- || u & ClientCharacteristicConfigurationValue::UseIndications) {
- if (!charDetails.hValueChangeEvent) {
- BTH_LE_GATT_CHARACTERISTIC gattCharacteristic = recoverNativeLeGattCharacteristic(
- service->startHandle, charHandle, charDetails);
-
- // note: if the service handle is closed the event registration is no longer valid.
- charDetails.hValueChangeEvent = registerEvent(
- data.hService, gattCharacteristic, this, &data.systemErrorCode);
- }
- } else {
- if (charDetails.hValueChangeEvent) {
- unregisterEvent(charDetails.hValueChangeEvent, &data.systemErrorCode);
- charDetails.hValueChangeEvent = nullptr;
- }
- }
-
- if (data.systemErrorCode != NO_ERROR) {
- qCWarning(QT_BT_WINDOWS) << "Unable to subscribe events for descriptor"
- << dscrDetails.uuid.toString()
- << "for characteristic"
- << charDetails.uuid.toString()
- << "of the service" << service->uuid.toString()
- << ":" << qt_error_string(data.systemErrorCode);
- service->setError(QLowEnergyService::DescriptorWriteError);
- return;
- }
- }
-
- updateValueOfDescriptor(charHandle, descriptorHandle, data.newValue, false);
-
- const QLowEnergyDescriptor dscr(service, charHandle, descriptorHandle);
- emit service->descriptorWritten(dscr, data.newValue);
- }
- break;
- case ThreadWorkerJob::ReadDescr:
- {
- ReadDescData data = job.data.value<ReadDescData>();
- const QLowEnergyHandle descriptorHandle = static_cast<QLowEnergyHandle>(data.gattDescriptor.AttributeHandle);
- const QLowEnergyHandle charHandle = static_cast<QLowEnergyHandle>(data.gattDescriptor.CharacteristicHandle);
- const QSharedPointer<QLowEnergyServicePrivate> service = serviceForHandle(charHandle);
- QLowEnergyServicePrivate::CharData &charDetails = service->characteristicList[charHandle];
- const QLowEnergyServicePrivate::DescData &dscrDetails = charDetails.descriptorList[descriptorHandle];
-
- if (data.systemErrorCode != NO_ERROR) {
- qCWarning(QT_BT_WINDOWS) << "Unable to get value for descriptor"
- << dscrDetails.uuid.toString()
- << "for characteristic"
- << charDetails.uuid.toString()
- << "of the service" << service->uuid.toString()
- << ":" << qt_error_string(data.systemErrorCode);
- service->setError(QLowEnergyService::DescriptorReadError);
- return;
- }
-
- updateValueOfDescriptor(charHandle, descriptorHandle, data.value, false);
-
- QLowEnergyDescriptor dscr(service, charHandle, descriptorHandle);
- emit service->descriptorRead(dscr, data.value);
- }
- break;
- }
-
- QMetaObject::invokeMethod(threadWorker, "runPendingJob", Qt::QueuedConnection);
-}
-
-void QLowEnergyControllerPrivateWin32::readDescriptor(
- const QSharedPointer<QLowEnergyServicePrivate> service,
- const QLowEnergyHandle charHandle,
- const QLowEnergyHandle descriptorHandle)
-{
- Q_ASSERT(!service.isNull());
- if (!service->characteristicList.contains(charHandle))
- return;
-
- const QLowEnergyServicePrivate::CharData &charDetails
- = service->characteristicList[charHandle];
- if (!charDetails.descriptorList.contains(descriptorHandle))
- return;
-
- ReadDescData data;
- data.systemErrorCode = NO_ERROR;
- data.hService = service->hService;
-
- if (data.systemErrorCode != NO_ERROR) {
- qCWarning(QT_BT_WINDOWS) << "Unable to open service" << service->uuid.toString()
- << ":" << qt_error_string(data.systemErrorCode);
- service->setError(QLowEnergyService::DescriptorReadError);
- return;
- }
-
- const QLowEnergyServicePrivate::DescData &dscrDetails
- = charDetails.descriptorList[descriptorHandle];
-
- data.gattDescriptor = recoverNativeLeGattDescriptor(
- service->startHandle, charHandle, descriptorHandle, dscrDetails);
-
- ThreadWorkerJob job;
- job.operation = ThreadWorkerJob::ReadDescr;
- job.data = QVariant::fromValue(data);
-
- QMetaObject::invokeMethod(threadWorker, "putJob", Qt::QueuedConnection,
- Q_ARG(ThreadWorkerJob, job));
-}
-
-void QLowEnergyControllerPrivateWin32::writeDescriptor(
- const QSharedPointer<QLowEnergyServicePrivate> service,
- const QLowEnergyHandle charHandle,
- const QLowEnergyHandle descriptorHandle,
- const QByteArray &newValue)
-{
- Q_ASSERT(!service.isNull());
- if (!service->characteristicList.contains(charHandle))
- return;
-
- QLowEnergyServicePrivate::CharData &charDetails
- = service->characteristicList[charHandle];
- if (!charDetails.descriptorList.contains(descriptorHandle))
- return;
-
- WriteDescData data;
- data.systemErrorCode = NO_ERROR;
- data.newValue = newValue;
- data.hService = service->hService;
-
- if (data.systemErrorCode != NO_ERROR) {
- qCWarning(QT_BT_WINDOWS) << "Unable to open service" << service->uuid.toString()
- << ":" << qt_error_string(data.systemErrorCode);
- service->setError(QLowEnergyService::DescriptorWriteError);
- return;
- }
-
- const QLowEnergyServicePrivate::DescData &dscrDetails
- = charDetails.descriptorList[descriptorHandle];
-
- data.gattDescriptor = recoverNativeLeGattDescriptor(
- service->startHandle, charHandle, descriptorHandle, dscrDetails);
-
- ThreadWorkerJob job;
- job.operation = ThreadWorkerJob::WriteDescr;
- job.data = QVariant::fromValue(data);
-
- QMetaObject::invokeMethod(threadWorker, "putJob", Qt::QueuedConnection,
- Q_ARG(ThreadWorkerJob, job));
-}
-
-void QLowEnergyControllerPrivateWin32::addToGenericAttributeList(const QLowEnergyServiceData &, QLowEnergyHandle)
-{
- Q_UNIMPLEMENTED();
-}
-
-void ThreadWorker::putJob(const ThreadWorkerJob &job)
-{
- m_jobs.append(job);
- if (m_jobs.count() == 1)
- runPendingJob();
-}
-
-void ThreadWorker::runPendingJob()
-{
- if (!m_jobs.count())
- return;
-
- ThreadWorkerJob job = m_jobs.first();
-
- switch (job.operation) {
- case ThreadWorkerJob::WriteChar:
- {
- WriteCharData data = job.data.value<WriteCharData>();
- setGattCharacteristicValue(data.hService, &data.gattCharacteristic,
- data.newValue, data.flags, &data.systemErrorCode);
- job.data = QVariant::fromValue(data);
- }
- break;
- case ThreadWorkerJob::ReadChar:
- {
- ReadCharData data = job.data.value<ReadCharData>();
- data.value = getGattCharacteristicValue(
- data.hService, &data.gattCharacteristic, &data.systemErrorCode);
- job.data = QVariant::fromValue(data);
- }
- break;
- case ThreadWorkerJob::WriteDescr:
- {
- WriteDescData data = job.data.value<WriteDescData>();
- setGattDescriptorValue(data.hService, &data.gattDescriptor,
- data.newValue, &data.systemErrorCode);
- job.data = QVariant::fromValue(data);
- }
- break;
- case ThreadWorkerJob::ReadDescr:
- {
- ReadDescData data = job.data.value<ReadDescData>();
- data.value = getGattDescriptorValue(
- data.hService,
- const_cast<PBTH_LE_GATT_DESCRIPTOR>(&data.gattDescriptor),
- &data.systemErrorCode);
- job.data = QVariant::fromValue(data);
- }
- break;
- }
-
- m_jobs.removeFirst();
- emit jobFinished(job);
-}
-
-QT_END_NAMESPACE
diff --git a/src/bluetooth/qlowenergycontroller_win_p.h b/src/bluetooth/qlowenergycontroller_win_p.h
deleted file mode 100644
index f8e3b10a..00000000
--- a/src/bluetooth/qlowenergycontroller_win_p.h
+++ /dev/null
@@ -1,185 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QLOWENERGYCONTROLLERPRIVATE_WIN32_P_H
-#define QLOWENERGYCONTROLLERPRIVATE_WIN32_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <qglobal.h>
-#include <QtCore/QQueue>
-#include <QtCore/QVector>
-#include <QtBluetooth/qbluetooth.h>
-#include <QtBluetooth/qlowenergycharacteristic.h>
-#include "qlowenergycontroller.h"
-#include "qlowenergycontrollerbase_p.h"
-
-#include <windows/qwinlowenergybluetooth_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class QThread;
-class QLowEnergyControllerPrivateWin32;
-
-class ThreadWorkerJob
-{
-public:
- enum Operation { WriteChar, ReadChar, WriteDescr, ReadDescr };
- Operation operation;
- QVariant data;
-};
-
-struct WriteCharData
-{
- QByteArray newValue;
- QLowEnergyService::WriteMode mode;
- HANDLE hService;
- DWORD flags;
- BTH_LE_GATT_CHARACTERISTIC gattCharacteristic;
- int systemErrorCode;
-};
-
-struct ReadCharData
-{
- QByteArray value;
- HANDLE hService;
- BTH_LE_GATT_CHARACTERISTIC gattCharacteristic;
- int systemErrorCode;
-};
-
-struct WriteDescData
-{
- QByteArray newValue;
- HANDLE hService;
- BTH_LE_GATT_DESCRIPTOR gattDescriptor;
- int systemErrorCode;
-};
-
-struct ReadDescData
-{
- QByteArray value;
- HANDLE hService;
- BTH_LE_GATT_DESCRIPTOR gattDescriptor;
- int systemErrorCode;
-};
-
-class ThreadWorker : public QObject
-{
- Q_OBJECT
-public:
- Q_INVOKABLE void putJob(const ThreadWorkerJob &job);
- Q_INVOKABLE void runPendingJob();
-signals:
- void jobFinished(const ThreadWorkerJob &job);
-private:
- QVector<ThreadWorkerJob> m_jobs;
-};
-
-class QLowEnergyServiceData;
-
-extern void registerQLowEnergyControllerMetaType();
-
-class QLowEnergyControllerPrivateWin32 : public QLowEnergyControllerPrivate
-{
- Q_OBJECT
-public:
- QLowEnergyControllerPrivateWin32();
- ~QLowEnergyControllerPrivateWin32();
-
- void init() override;
-
- void connectToDevice() override;
- void disconnectFromDevice() override;
-
- void discoverServices() override;
- void discoverServiceDetails(const QBluetoothUuid &service) override;
-
- void startAdvertising(const QLowEnergyAdvertisingParameters &params,
- const QLowEnergyAdvertisingData &advertisingData,
- const QLowEnergyAdvertisingData &scanResponseData) override;
- void stopAdvertising() override;
-
- void requestConnectionUpdate(const QLowEnergyConnectionParameters &params) override;
-
- // read data
- void readCharacteristic(const QSharedPointer<QLowEnergyServicePrivate> service,
- const QLowEnergyHandle charHandle) override;
- void readDescriptor(const QSharedPointer<QLowEnergyServicePrivate> service,
- const QLowEnergyHandle charHandle,
- const QLowEnergyHandle descriptorHandle) override;
-
- // write data
- void writeCharacteristic(const QSharedPointer<QLowEnergyServicePrivate> service,
- const QLowEnergyHandle charHandle,
- const QByteArray &newValue, QLowEnergyService::WriteMode mode) override;
- void writeDescriptor(const QSharedPointer<QLowEnergyServicePrivate> service,
- const QLowEnergyHandle charHandle,
- const QLowEnergyHandle descriptorHandle,
- const QByteArray &newValue) override;
-
- void addToGenericAttributeList(const QLowEnergyServiceData &service,
- QLowEnergyHandle startHandle) override;
-public slots:
- void jobFinished(const ThreadWorkerJob &job);
-protected:
- void customEvent(QEvent *e);
-private:
- QThread *thread = nullptr;
- ThreadWorker *threadWorker = nullptr;
- QString deviceSystemPath;
-};
-
-QT_END_NAMESPACE
-
-Q_DECLARE_METATYPE(ThreadWorkerJob)
-Q_DECLARE_METATYPE(WriteCharData)
-Q_DECLARE_METATYPE(ReadCharData)
-Q_DECLARE_METATYPE(WriteDescData)
-Q_DECLARE_METATYPE(ReadDescData)
-
-#endif // QLOWENERGYCONTROLLERPRIVATE_WIN32__P_H
diff --git a/src/bluetooth/qlowenergycontroller_winrt.cpp b/src/bluetooth/qlowenergycontroller_winrt.cpp
index ab566bd9..6914ed42 100644
--- a/src/bluetooth/qlowenergycontroller_winrt.cpp
+++ b/src/bluetooth/qlowenergycontroller_winrt.cpp
@@ -1,67 +1,36 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qlowenergycontroller_winrt_p.h"
#include "qbluetoothutils_winrt_p.h"
+#include <QtBluetooth/qbluetoothlocaldevice.h>
#include <QtBluetooth/QLowEnergyCharacteristicData>
#include <QtBluetooth/QLowEnergyDescriptorData>
+#include <QtBluetooth/private/qbluetoothutils_winrt_p.h>
+#include <QtBluetooth/QLowEnergyService>
-#ifdef CLASSIC_APP_BUILD
-#define Q_OS_WINRT
-#endif
-#include <QtCore/qfunctions_winrt.h>
#include <QtCore/QtEndian>
#include <QtCore/QLoggingCategory>
-#include <private/qeventdispatcher_winrt_p.h>
+#include <QtCore/private/qfunctions_winrt_p.h>
+#include <QtCore/QDeadlineTimer>
+#include <QtCore/qpointer.h>
#include <functional>
+
#include <robuffer.h>
#include <windows.devices.enumeration.h>
#include <windows.devices.bluetooth.h>
+#include <windows.devices.bluetooth.genericattributeprofile.h>
#include <windows.foundation.collections.h>
+#include <windows.foundation.metadata.h>
#include <windows.storage.streams.h>
using namespace Microsoft::WRL;
using namespace Microsoft::WRL::Wrappers;
using namespace ABI::Windows::Foundation;
using namespace ABI::Windows::Foundation::Collections;
+using namespace ABI::Windows::Foundation::Metadata;
using namespace ABI::Windows::Devices;
using namespace ABI::Windows::Devices::Bluetooth;
using namespace ABI::Windows::Devices::Bluetooth::GenericAttributeProfile;
@@ -71,438 +40,1021 @@ using namespace ABI::Windows::Storage::Streams;
QT_BEGIN_NAMESPACE
typedef ITypedEventHandler<BluetoothLEDevice *, IInspectable *> StatusHandler;
+typedef ITypedEventHandler<GattSession *, IInspectable *> MtuHandler;
typedef ITypedEventHandler<GattCharacteristic *, GattValueChangedEventArgs *> ValueChangedHandler;
typedef GattReadClientCharacteristicConfigurationDescriptorResult ClientCharConfigDescriptorResult;
typedef IGattReadClientCharacteristicConfigurationDescriptorResult IClientCharConfigDescriptorResult;
-Q_DECLARE_LOGGING_CATEGORY(QT_BT_WINRT)
-Q_DECLARE_LOGGING_CATEGORY(QT_BT_WINRT_SERVICE_THREAD)
+#define EMIT_WORKER_ERROR_AND_QUIT_IF_FAILED(hr) \
+ if (FAILED(hr)) { \
+ emitErrorAndQuitThread(hr); \
+ return; \
+ }
-static QByteArray byteArrayFromGattResult(const ComPtr<IGattReadResult> &gattResult, bool isWCharString = false)
+#define EMIT_WORKER_ERROR_AND_QUIT_IF_FAILED_2(hr, message) \
+ if (FAILED(hr)) { \
+ emitErrorAndQuitThread(message); \
+ return; \
+ }
+
+#define WARN_AND_CONTINUE_IF_FAILED(hr, msg) \
+ if (FAILED(hr)) { \
+ qCWarning(QT_BT_WINDOWS) << msg; \
+ continue; \
+ }
+
+#define DEC_CHAR_COUNT_AND_CONTINUE_IF_FAILED(hr, msg) \
+ if (FAILED(hr)) { \
+ qCWarning(QT_BT_WINDOWS) << msg; \
+ --mCharacteristicsCountToBeDiscovered; \
+ continue; \
+ }
+
+#define CHECK_FOR_DEVICE_CONNECTION_ERROR_IMPL(this, hr, msg, ret) \
+ if (FAILED(hr)) { \
+ this->handleConnectionError(msg); \
+ ret; \
+ }
+
+#define CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, msg, ret) \
+ CHECK_FOR_DEVICE_CONNECTION_ERROR_IMPL(this, hr, msg, ret)
+
+#define CHECK_HR_AND_SET_SERVICE_ERROR(hr, msg, service, error, ret) \
+ if (FAILED(hr)) { \
+ qCDebug(QT_BT_WINDOWS) << msg; \
+ service->setError(error); \
+ ret; \
+ }
+
+Q_DECLARE_LOGGING_CATEGORY(QT_BT_WINDOWS)
+Q_DECLARE_LOGGING_CATEGORY(QT_BT_WINDOWS_SERVICE_THREAD)
+
+static constexpr qint64 kMaxConnectTimeout = 20000; // 20 sec
+
+static QByteArray byteArrayFromGattResult(const ComPtr<IGattReadResult> &gattResult,
+ bool isWCharString = false)
{
ComPtr<ABI::Windows::Storage::Streams::IBuffer> buffer;
HRESULT hr;
hr = gattResult->get_Value(&buffer);
- Q_ASSERT_SUCCEEDED(hr);
+ if (FAILED(hr) || !buffer) {
+ qCWarning(QT_BT_WINDOWS) << "Could not obtain buffer from GattReadResult";
+ return QByteArray();
+ }
return byteArrayFromBuffer(buffer, isWCharString);
}
+template <typename T>
+static void closeDeviceService(ComPtr<T> service)
+{
+ ComPtr<IClosable> closableService;
+ HRESULT hr = service.As(&closableService);
+ RETURN_IF_FAILED("Could not cast type to closable", return);
+ hr = closableService->Close();
+ RETURN_IF_FAILED("Close() call failed", return);
+}
+
class QWinRTLowEnergyServiceHandler : public QObject
{
Q_OBJECT
public:
- QWinRTLowEnergyServiceHandler(const QBluetoothUuid &service, const ComPtr<IGattDeviceService2> &deviceService)
- : mService(service)
- , mDeviceService(deviceService)
+ QWinRTLowEnergyServiceHandler(const QBluetoothUuid &service,
+ const ComPtr<IGattDeviceService3> &deviceService,
+ QLowEnergyService::DiscoveryMode mode)
+ : mService(service), mMode(mode), mDeviceService(deviceService)
{
- qCDebug(QT_BT_WINRT) << __FUNCTION__;
+ qCDebug(QT_BT_WINDOWS) << __FUNCTION__;
}
~QWinRTLowEnergyServiceHandler()
{
+ if (mAbortRequested)
+ closeDeviceService(mDeviceService);
+ qCDebug(QT_BT_WINDOWS) << __FUNCTION__;
}
public slots:
void obtainCharList()
{
- QVector<QBluetoothUuid> indicateChars;
- quint16 startHandle = 0;
- quint16 endHandle = 0;
- qCDebug(QT_BT_WINRT) << __FUNCTION__;
- ComPtr<IVectorView<GattCharacteristic *>> characteristics;
- HRESULT hr = mDeviceService->GetAllCharacteristics(&characteristics);
- Q_ASSERT_SUCCEEDED(hr);
- if (!characteristics) {
- emit charListObtained(mService, mCharacteristicList, indicateChars, startHandle, endHandle);
- QThread::currentThread()->quit();
+ auto exitCondition = [this]() { return mAbortRequested; };
+
+ mIndicateChars.clear();
+ qCDebug(QT_BT_WINDOWS) << __FUNCTION__;
+ ComPtr<IAsyncOperation<GattCharacteristicsResult *>> characteristicsOp;
+ ComPtr<IGattCharacteristicsResult> characteristicsResult;
+ HRESULT hr = mDeviceService->GetCharacteristicsAsync(&characteristicsOp);
+ EMIT_WORKER_ERROR_AND_QUIT_IF_FAILED(hr);
+ hr = QWinRTFunctions::await(characteristicsOp, characteristicsResult.GetAddressOf(),
+ QWinRTFunctions::ProcessMainThreadEvents, 5000,
+ exitCondition);
+ EMIT_WORKER_ERROR_AND_QUIT_IF_FAILED(hr);
+ GattCommunicationStatus status;
+ hr = characteristicsResult->get_Status(&status);
+ EMIT_WORKER_ERROR_AND_QUIT_IF_FAILED(hr);
+ if (status != GattCommunicationStatus_Success) {
+ emitErrorAndQuitThread(QLatin1String("Could not obtain char list"));
return;
}
+ ComPtr<IVectorView<GattCharacteristic *>> characteristics;
+ hr = characteristicsResult->get_Characteristics(&characteristics);
+ EMIT_WORKER_ERROR_AND_QUIT_IF_FAILED(hr);
uint characteristicsCount;
hr = characteristics->get_Size(&characteristicsCount);
- Q_ASSERT_SUCCEEDED(hr);
- for (uint i = 0; i < characteristicsCount; ++i) {
+ EMIT_WORKER_ERROR_AND_QUIT_IF_FAILED(hr);
+
+ mCharacteristicsCountToBeDiscovered = characteristicsCount;
+ for (uint i = 0; !mAbortRequested && (i < characteristicsCount); ++i) {
ComPtr<IGattCharacteristic> characteristic;
hr = characteristics->GetAt(i, &characteristic);
- Q_ASSERT_SUCCEEDED(hr);
+ if (FAILED(hr)) {
+ qCWarning(QT_BT_WINDOWS) << "Could not obtain characteristic at" << i;
+ --mCharacteristicsCountToBeDiscovered;
+ continue;
+ }
+
+ ComPtr<IGattCharacteristic3> characteristic3;
+ hr = characteristic.As(&characteristic3);
+ if (FAILED(hr)) {
+ qCWarning(QT_BT_WINDOWS) << "Could not cast characteristic";
+ --mCharacteristicsCountToBeDiscovered;
+ continue;
+ }
+
+ // For some strange reason, Windows doesn't discover descriptors of characteristics (if not paired).
+ // Qt API assumes that all characteristics and their descriptors are discovered in one go.
+ // So we start 'GetDescriptorsAsync' for each discovered characteristic and finish only
+ // when GetDescriptorsAsync for all characteristics return.
+ ComPtr<IAsyncOperation<GattDescriptorsResult *>> descAsyncOp;
+ hr = characteristic3->GetDescriptorsAsync(&descAsyncOp);
+ DEC_CHAR_COUNT_AND_CONTINUE_IF_FAILED(hr, "Could not obtain list of descriptors")
+
+ ComPtr<IGattDescriptorsResult> descResult;
+ hr = QWinRTFunctions::await(descAsyncOp, descResult.GetAddressOf(),
+ QWinRTFunctions::ProcessMainThreadEvents, 5000,
+ exitCondition);
+ DEC_CHAR_COUNT_AND_CONTINUE_IF_FAILED(hr, "Could not obtain descriptor read result")
+
quint16 handle;
hr = characteristic->get_AttributeHandle(&handle);
- Q_ASSERT_SUCCEEDED(hr);
+ DEC_CHAR_COUNT_AND_CONTINUE_IF_FAILED(
+ hr, "Could not obtain characteristic's attribute handle")
QLowEnergyServicePrivate::CharData charData;
charData.valueHandle = handle + 1;
- if (startHandle == 0 || startHandle > handle)
- startHandle = handle;
- if (endHandle == 0 || endHandle < handle)
- endHandle = handle;
+ if (mStartHandle == 0 || mStartHandle > handle)
+ mStartHandle = handle;
+ if (mEndHandle == 0 || mEndHandle < handle)
+ mEndHandle = handle;
GUID guuid;
hr = characteristic->get_Uuid(&guuid);
- Q_ASSERT_SUCCEEDED(hr);
+ DEC_CHAR_COUNT_AND_CONTINUE_IF_FAILED(hr, "Could not obtain characteristic's Uuid")
charData.uuid = QBluetoothUuid(guuid);
GattCharacteristicProperties properties;
hr = characteristic->get_CharacteristicProperties(&properties);
- Q_ASSERT_SUCCEEDED(hr);
+ DEC_CHAR_COUNT_AND_CONTINUE_IF_FAILED(hr,
+ "Could not obtain characteristic's properties")
charData.properties = QLowEnergyCharacteristic::PropertyTypes(properties & 0xff);
- if (charData.properties & QLowEnergyCharacteristic::Read) {
+ if (charData.properties & QLowEnergyCharacteristic::Read
+ && mMode == QLowEnergyService::FullDiscovery) {
ComPtr<IAsyncOperation<GattReadResult *>> readOp;
- hr = characteristic->ReadValueWithCacheModeAsync(BluetoothCacheMode_Uncached, &readOp);
- Q_ASSERT_SUCCEEDED(hr);
+ hr = characteristic->ReadValueWithCacheModeAsync(BluetoothCacheMode_Uncached,
+ &readOp);
+ DEC_CHAR_COUNT_AND_CONTINUE_IF_FAILED(hr, "Could not read characteristic")
ComPtr<IGattReadResult> readResult;
- hr = QWinRTFunctions::await(readOp, readResult.GetAddressOf());
- Q_ASSERT_SUCCEEDED(hr);
- if (readResult)
+ hr = QWinRTFunctions::await(readOp, readResult.GetAddressOf(),
+ QWinRTFunctions::ProcessMainThreadEvents, 5000,
+ exitCondition);
+ DEC_CHAR_COUNT_AND_CONTINUE_IF_FAILED(hr,
+ "Could not obtain characteristic read result")
+ if (!readResult)
+ qCWarning(QT_BT_WINDOWS) << "Characteristic read result is null";
+ else
charData.value = byteArrayFromGattResult(readResult);
}
- ComPtr<IGattCharacteristic2> characteristic2;
- hr = characteristic.As(&characteristic2);
- Q_ASSERT_SUCCEEDED(hr);
+ mCharacteristicList.insert(handle, charData);
+
ComPtr<IVectorView<GattDescriptor *>> descriptors;
- hr = characteristic2->GetAllDescriptors(&descriptors);
- Q_ASSERT_SUCCEEDED(hr);
+
+ GattCommunicationStatus commStatus;
+ hr = descResult->get_Status(&commStatus);
+ if (FAILED(hr) || commStatus != GattCommunicationStatus_Success) {
+ qCWarning(QT_BT_WINDOWS) << "Descriptor operation failed";
+ --mCharacteristicsCountToBeDiscovered;
+ continue;
+ }
+
+ hr = descResult->get_Descriptors(&descriptors);
+ DEC_CHAR_COUNT_AND_CONTINUE_IF_FAILED(hr, "Could not obtain list of descriptors")
+
uint descriptorCount;
hr = descriptors->get_Size(&descriptorCount);
- Q_ASSERT_SUCCEEDED(hr);
- for (uint j = 0; j < descriptorCount; ++j) {
+ DEC_CHAR_COUNT_AND_CONTINUE_IF_FAILED(hr, "Could not obtain list of descriptors' size")
+ for (uint j = 0; !mAbortRequested && (j < descriptorCount); ++j) {
QLowEnergyServicePrivate::DescData descData;
ComPtr<IGattDescriptor> descriptor;
hr = descriptors->GetAt(j, &descriptor);
- Q_ASSERT_SUCCEEDED(hr);
+ WARN_AND_CONTINUE_IF_FAILED(hr, "Could not obtain descriptor")
quint16 descHandle;
hr = descriptor->get_AttributeHandle(&descHandle);
- Q_ASSERT_SUCCEEDED(hr);
+ WARN_AND_CONTINUE_IF_FAILED(hr, "Could not obtain descriptor's attribute handle")
GUID descriptorUuid;
hr = descriptor->get_Uuid(&descriptorUuid);
- Q_ASSERT_SUCCEEDED(hr);
+ WARN_AND_CONTINUE_IF_FAILED(hr, "Could not obtain descriptor's Uuid")
descData.uuid = QBluetoothUuid(descriptorUuid);
- if (descData.uuid == QBluetoothUuid(QBluetoothUuid::ClientCharacteristicConfiguration)) {
- ComPtr<IAsyncOperation<ClientCharConfigDescriptorResult *>> readOp;
- hr = characteristic->ReadClientCharacteristicConfigurationDescriptorAsync(&readOp);
- Q_ASSERT_SUCCEEDED(hr);
- ComPtr<IClientCharConfigDescriptorResult> readResult;
- hr = QWinRTFunctions::await(readOp, readResult.GetAddressOf());
- Q_ASSERT_SUCCEEDED(hr);
- GattClientCharacteristicConfigurationDescriptorValue value;
- hr = readResult->get_ClientCharacteristicConfigurationDescriptor(&value);
- Q_ASSERT_SUCCEEDED(hr);
- quint16 result = 0;
- bool correct = false;
- if (value & GattClientCharacteristicConfigurationDescriptorValue_Indicate) {
- result |= GattClientCharacteristicConfigurationDescriptorValue_Indicate;
- correct = true;
- }
- if (value & GattClientCharacteristicConfigurationDescriptorValue_Notify) {
- result |= GattClientCharacteristicConfigurationDescriptorValue_Notify;
- correct = true;
- }
- if (value == GattClientCharacteristicConfigurationDescriptorValue_None) {
- correct = true;
+ charData.descriptorList.insert(descHandle, descData);
+ if (descData.uuid == QBluetoothUuid(QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration)) {
+ if (mMode == QLowEnergyService::FullDiscovery) {
+ ComPtr<IAsyncOperation<ClientCharConfigDescriptorResult *>> readOp;
+ hr = characteristic->ReadClientCharacteristicConfigurationDescriptorAsync(
+ &readOp);
+ WARN_AND_CONTINUE_IF_FAILED(hr, "Could not read descriptor value")
+ ComPtr<IClientCharConfigDescriptorResult> readResult;
+ hr = QWinRTFunctions::await(readOp, readResult.GetAddressOf(),
+ QWinRTFunctions::ProcessMainThreadEvents, 5000,
+ exitCondition);
+ WARN_AND_CONTINUE_IF_FAILED(hr, "Could not await descriptor read result")
+ GattClientCharacteristicConfigurationDescriptorValue value;
+ hr = readResult->get_ClientCharacteristicConfigurationDescriptor(&value);
+ WARN_AND_CONTINUE_IF_FAILED(hr,
+ "Could not get descriptor value from result")
+ quint16 result = 0;
+ bool correct = false;
+ if (value & GattClientCharacteristicConfigurationDescriptorValue_Indicate) {
+ result |= GattClientCharacteristicConfigurationDescriptorValue_Indicate;
+ correct = true;
+ }
+ if (value & GattClientCharacteristicConfigurationDescriptorValue_Notify) {
+ result |= GattClientCharacteristicConfigurationDescriptorValue_Notify;
+ correct = true;
+ }
+ if (value == GattClientCharacteristicConfigurationDescriptorValue_None)
+ correct = true;
+ if (!correct)
+ continue;
+
+ descData.value = QByteArray(2, Qt::Uninitialized);
+ qToLittleEndian(result, descData.value.data());
}
- if (!correct)
- continue;
-
- descData.value = QByteArray(2, Qt::Uninitialized);
- qToLittleEndian(result, descData.value.data());
- indicateChars << charData.uuid;
+ mIndicateChars << charData.uuid;
} else {
- ComPtr<IAsyncOperation<GattReadResult *>> readOp;
- hr = descriptor->ReadValueWithCacheModeAsync(BluetoothCacheMode_Uncached, &readOp);
- Q_ASSERT_SUCCEEDED(hr);
- ComPtr<IGattReadResult> readResult;
- hr = QWinRTFunctions::await(readOp, readResult.GetAddressOf());
- Q_ASSERT_SUCCEEDED(hr);
- if (descData.uuid == QBluetoothUuid::CharacteristicUserDescription)
- descData.value = byteArrayFromGattResult(readResult, true);
- else
- descData.value = byteArrayFromGattResult(readResult);
+ if (mMode == QLowEnergyService::FullDiscovery) {
+ ComPtr<IAsyncOperation<GattReadResult *>> readOp;
+ hr = descriptor->ReadValueWithCacheModeAsync(BluetoothCacheMode_Uncached,
+ &readOp);
+ WARN_AND_CONTINUE_IF_FAILED(hr, "Could not read descriptor value")
+ ComPtr<IGattReadResult> readResult;
+ hr = QWinRTFunctions::await(readOp, readResult.GetAddressOf(),
+ QWinRTFunctions::ProcessMainThreadEvents, 5000,
+ exitCondition);
+ WARN_AND_CONTINUE_IF_FAILED(hr, "Could not await descriptor read result")
+ if (descData.uuid == QBluetoothUuid::DescriptorType::CharacteristicUserDescription)
+ descData.value = byteArrayFromGattResult(readResult, true);
+ else
+ descData.value = byteArrayFromGattResult(readResult);
+ }
}
charData.descriptorList.insert(descHandle, descData);
}
+
mCharacteristicList.insert(handle, charData);
+ --mCharacteristicsCountToBeDiscovered;
}
- emit charListObtained(mService, mCharacteristicList, indicateChars, startHandle, endHandle);
- QThread::currentThread()->quit();
+ checkAllCharacteristicsDiscovered();
+ }
+
+ void setAbortRequested()
+ {
+ mAbortRequested = true;
}
+private:
+ void checkAllCharacteristicsDiscovered();
+ void emitErrorAndQuitThread(HRESULT hr);
+ void emitErrorAndQuitThread(const QString &error);
+
public:
QBluetoothUuid mService;
- ComPtr<IGattDeviceService2> mDeviceService;
+ QLowEnergyService::DiscoveryMode mMode;
+ ComPtr<IGattDeviceService3> mDeviceService;
QHash<QLowEnergyHandle, QLowEnergyServicePrivate::CharData> mCharacteristicList;
+ uint mCharacteristicsCountToBeDiscovered;
+ quint16 mStartHandle = 0;
+ quint16 mEndHandle = 0;
+ QList<QBluetoothUuid> mIndicateChars;
+ bool mAbortRequested = false;
signals:
- void charListObtained(const QBluetoothUuid &service, QHash<QLowEnergyHandle,
- QLowEnergyServicePrivate::CharData> charList,
- QVector<QBluetoothUuid> indicateChars,
- QLowEnergyHandle startHandle, QLowEnergyHandle endHandle);
+ void charListObtained(const QBluetoothUuid &service,
+ QHash<QLowEnergyHandle, QLowEnergyServicePrivate::CharData> charList,
+ QList<QBluetoothUuid> indicateChars, QLowEnergyHandle startHandle,
+ QLowEnergyHandle endHandle);
+ void errorOccured(const QString &error);
};
-QLowEnergyControllerPrivateWinRT::QLowEnergyControllerPrivateWinRT()
- : QLowEnergyControllerPrivate()
+void QWinRTLowEnergyServiceHandler::checkAllCharacteristicsDiscovered()
{
- qCDebug(QT_BT_WINRT) << __FUNCTION__;
-
- registerQLowEnergyControllerMetaType();
- connect(this, &QLowEnergyControllerPrivateWinRT::characteristicChanged,
- this, &QLowEnergyControllerPrivateWinRT::handleCharacteristicChanged,
- Qt::QueuedConnection);
+ if (!mAbortRequested && (mCharacteristicsCountToBeDiscovered == 0)) {
+ emit charListObtained(mService, mCharacteristicList, mIndicateChars,
+ mStartHandle, mEndHandle);
+ }
+ QThread::currentThread()->quit();
}
-QLowEnergyControllerPrivateWinRT::~QLowEnergyControllerPrivateWinRT()
+void QWinRTLowEnergyServiceHandler::emitErrorAndQuitThread(HRESULT hr)
{
- if (mDevice && mStatusChangedToken.value)
- mDevice->remove_ConnectionStatusChanged(mStatusChangedToken);
-
- unregisterFromValueChanges();
+ emitErrorAndQuitThread(qt_error_string(hr));
}
-void QLowEnergyControllerPrivateWinRT::init()
+void QWinRTLowEnergyServiceHandler::emitErrorAndQuitThread(const QString &error)
{
+ mAbortRequested = true; // so that the service is closed during cleanup
+ emit errorOccured(error);
+ QThread::currentThread()->quit();
}
-void QLowEnergyControllerPrivateWinRT::connectToDevice()
+class QWinRTLowEnergyConnectionHandler : public QObject
{
- qCDebug(QT_BT_WINRT) << __FUNCTION__;
- Q_Q(QLowEnergyController);
- if (remoteDevice.isNull()) {
- qWarning() << "Invalid/null remote device address";
- setError(QLowEnergyController::UnknownRemoteDeviceError);
- return;
+ Q_OBJECT
+public:
+ explicit QWinRTLowEnergyConnectionHandler(const QBluetoothAddress &address) : mAddress(address)
+ {
+ qCDebug(QT_BT_WINDOWS) << __FUNCTION__;
+ // This should be checked before the handler is created
+ Q_ASSERT(!mAddress.isNull());
+ }
+ ~QWinRTLowEnergyConnectionHandler()
+ {
+ qCDebug(QT_BT_WINDOWS) << __FUNCTION__;
+ mDevice.Reset();
+ mGattSession.Reset();
+ // To close the COM library gracefully, each successful call to
+ // CoInitialize, including those that return S_FALSE, must be balanced
+ // by a corresponding call to CoUninitialize.
+ if (mInitialized == S_OK || mInitialized == S_FALSE)
+ CoUninitialize();
}
- setState(QLowEnergyController::ConnectingState);
+public slots:
+ void connectToDevice();
+ void handleDeviceDisconnectRequest();
+
+signals:
+ void deviceConnected(ComPtr<IBluetoothLEDevice> device, ComPtr<IGattSession> session);
+ void errorOccurred(const QString &error);
+
+private:
+ void connectToPairedDevice();
+ void connectToUnpairedDevice();
+ void emitErrorAndQuitThread(const QString &error);
+ void emitErrorAndQuitThread(const char *error);
+ void emitConnectedAndQuitThread();
+
+ ComPtr<IBluetoothLEDevice> mDevice = nullptr;
+ ComPtr<IGattSession> mGattSession = nullptr;
+ const QBluetoothAddress mAddress;
+ bool mAbortConnection = false;
+ HRESULT mInitialized = E_UNEXPECTED; // some error code
+};
+
+void QWinRTLowEnergyConnectionHandler::connectToDevice()
+{
+ qCDebug(QT_BT_WINDOWS) << __FUNCTION__;
+ mInitialized = CoInitializeEx(NULL, COINIT_MULTITHREADED);
+ qCDebug(QT_BT_WINDOWS) << qt_error_string(mInitialized);
+ auto earlyExit = [this]() { return mAbortConnection; };
ComPtr<IBluetoothLEDeviceStatics> deviceStatics;
- HRESULT hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Devices_Bluetooth_BluetoothLEDevice).Get(), &deviceStatics);
- Q_ASSERT_SUCCEEDED(hr);
+ HRESULT hr = GetActivationFactory(
+ HString::MakeReference(RuntimeClass_Windows_Devices_Bluetooth_BluetoothLEDevice).Get(),
+ &deviceStatics);
+ EMIT_WORKER_ERROR_AND_QUIT_IF_FAILED_2(hr, "Could not obtain device factory");
ComPtr<IAsyncOperation<BluetoothLEDevice *>> deviceFromIdOperation;
- hr = deviceStatics->FromBluetoothAddressAsync(remoteDevice.toUInt64(), &deviceFromIdOperation);
- Q_ASSERT_SUCCEEDED(hr);
- hr = QWinRTFunctions::await(deviceFromIdOperation, mDevice.GetAddressOf());
- Q_ASSERT_SUCCEEDED(hr);
-
- if (!mDevice) {
- qCDebug(QT_BT_WINRT) << "Could not find LE device";
- setError(QLowEnergyController::InvalidBluetoothAdapterError);
- setState(QLowEnergyController::UnconnectedState);
+ hr = deviceStatics->FromBluetoothAddressAsync(mAddress.toUInt64(), &deviceFromIdOperation);
+ EMIT_WORKER_ERROR_AND_QUIT_IF_FAILED_2(hr, "Could not find LE device from address");
+ hr = QWinRTFunctions::await(deviceFromIdOperation, mDevice.GetAddressOf(),
+ QWinRTFunctions::ProcessMainThreadEvents, 5000, earlyExit);
+ if (FAILED(hr) || !mDevice) {
+ emitErrorAndQuitThread("Could not find LE device");
+ return;
}
+
+ // get GattSession: 1. get device id
+ ComPtr<IBluetoothLEDevice4> device4;
+ hr = mDevice.As(&device4);
+ EMIT_WORKER_ERROR_AND_QUIT_IF_FAILED_2(hr, "Could not cast device");
+
+ ComPtr<IBluetoothDeviceId> deviceId;
+ hr = device4->get_BluetoothDeviceId(&deviceId);
+ EMIT_WORKER_ERROR_AND_QUIT_IF_FAILED_2(hr, "Could not get bluetooth device id");
+
+ // get GattSession: 2. get session statics
+ ComPtr<IGattSessionStatics> sessionStatics;
+ hr = GetActivationFactory(
+ HString::MakeReference(
+ RuntimeClass_Windows_Devices_Bluetooth_GenericAttributeProfile_GattSession)
+ .Get(),
+ &sessionStatics);
+ EMIT_WORKER_ERROR_AND_QUIT_IF_FAILED_2(hr, "Could not obtain GattSession statics");
+
+ // get GattSession: 3. get session
+ ComPtr<IAsyncOperation<GattSession *>> gattSessionFromIdOperation;
+ hr = sessionStatics->FromDeviceIdAsync(deviceId.Get(), &gattSessionFromIdOperation);
+ EMIT_WORKER_ERROR_AND_QUIT_IF_FAILED_2(hr, "Could not get GattSession from id");
+ hr = QWinRTFunctions::await(gattSessionFromIdOperation, mGattSession.GetAddressOf(),
+ QWinRTFunctions::ProcessMainThreadEvents, 5000, earlyExit);
+ EMIT_WORKER_ERROR_AND_QUIT_IF_FAILED_2(hr, "Could not complete Gatt session acquire");
+
BluetoothConnectionStatus status;
hr = mDevice->get_ConnectionStatus(&status);
- Q_ASSERT_SUCCEEDED(hr);
- hr = QEventDispatcherWinRT::runOnXamlThread([this, q]() {
- HRESULT hr;
- hr = mDevice->add_ConnectionStatusChanged(Callback<StatusHandler>([this, q](IBluetoothLEDevice *dev, IInspectable *) {
- BluetoothConnectionStatus status;
- HRESULT hr;
- hr = dev->get_ConnectionStatus(&status);
- Q_ASSERT_SUCCEEDED(hr);
- if (state == QLowEnergyController::ConnectingState
- && status == BluetoothConnectionStatus::BluetoothConnectionStatus_Connected) {
- setState(QLowEnergyController::ConnectedState);
- emit q->connected();
- } else if (state != QLowEnergyController::UnconnectedState
- && status == BluetoothConnectionStatus::BluetoothConnectionStatus_Disconnected) {
- invalidateServices();
- unregisterFromValueChanges();
- setError(QLowEnergyController::RemoteHostClosedError);
- setState(QLowEnergyController::UnconnectedState);
- emit q->disconnected();
- }
- return S_OK;
- }).Get(), &mStatusChangedToken);
- Q_ASSERT_SUCCEEDED(hr);
- return S_OK;
- });
- Q_ASSERT_SUCCEEDED(hr);
-
+ EMIT_WORKER_ERROR_AND_QUIT_IF_FAILED_2(hr, "Could not obtain device's connection status");
if (status == BluetoothConnectionStatus::BluetoothConnectionStatus_Connected) {
- setState(QLowEnergyController::ConnectedState);
- emit q->connected();
+ emitConnectedAndQuitThread();
return;
}
- ComPtr<IVectorView <GattDeviceService *>> deviceServices;
- hr = mDevice->get_GattServices(&deviceServices);
- Q_ASSERT_SUCCEEDED(hr);
- uint serviceCount;
- hr = deviceServices->get_Size(&serviceCount);
- Q_ASSERT_SUCCEEDED(hr);
- // Windows Phone automatically connects to the device as soon as a service value is read/written.
- // Thus we read one value in order to establish the connection.
- for (uint i = 0; i < serviceCount; ++i) {
- ComPtr<IGattDeviceService> service;
- hr = deviceServices->GetAt(i, &service);
- Q_ASSERT_SUCCEEDED(hr);
- ComPtr<IGattDeviceService2> service2;
- hr = service.As(&service2);
- Q_ASSERT_SUCCEEDED(hr);
- ComPtr<IVectorView<GattCharacteristic *>> characteristics;
- hr = service2->GetAllCharacteristics(&characteristics);
- if (hr == E_ACCESSDENIED) {
- // Everything will work as expected up until this point if the manifest capabilties
- // for bluetooth LE are not set.
- qCWarning(QT_BT_WINRT) << "Could not obtain characteristic list. Please check your "
- "manifest capabilities";
- setState(QLowEnergyController::UnconnectedState);
- setError(QLowEnergyController::ConnectionError);
+ QBluetoothLocalDevice localDevice;
+ QBluetoothLocalDevice::Pairing pairing = localDevice.pairingStatus(mAddress);
+ if (pairing == QBluetoothLocalDevice::Unpaired)
+ connectToUnpairedDevice();
+ else
+ connectToPairedDevice();
+}
+
+void QWinRTLowEnergyConnectionHandler::handleDeviceDisconnectRequest()
+{
+ mAbortConnection = true;
+ // Disconnect from the QLowEnergyControllerPrivateWinRT, so that it does
+ // not get notifications. It's absolutely fine to keep doing smth in
+ // background, as multiple connections to the same device should be handled
+ // correctly by OS.
+ disconnect(this, &QWinRTLowEnergyConnectionHandler::deviceConnected, nullptr, nullptr);
+ disconnect(this, &QWinRTLowEnergyConnectionHandler::errorOccurred, nullptr, nullptr);
+}
+
+void QWinRTLowEnergyConnectionHandler::connectToPairedDevice()
+{
+ qCDebug(QT_BT_WINDOWS) << __FUNCTION__;
+ ComPtr<IBluetoothLEDevice3> device3;
+ HRESULT hr = mDevice.As(&device3);
+ EMIT_WORKER_ERROR_AND_QUIT_IF_FAILED_2(hr, "Could not cast device");
+ ComPtr<IAsyncOperation<GattDeviceServicesResult *>> deviceServicesOp;
+ auto earlyExit = [this]() { return mAbortConnection; };
+ QDeadlineTimer deadline(kMaxConnectTimeout);
+ while (!mAbortConnection && !deadline.hasExpired()) {
+ hr = device3->GetGattServicesAsync(&deviceServicesOp);
+ EMIT_WORKER_ERROR_AND_QUIT_IF_FAILED_2(hr, "Could not obtain services");
+ ComPtr<IGattDeviceServicesResult> deviceServicesResult;
+ hr = QWinRTFunctions::await(deviceServicesOp, deviceServicesResult.GetAddressOf(),
+ QWinRTFunctions::ProcessThreadEvents, 5000, earlyExit);
+ EMIT_WORKER_ERROR_AND_QUIT_IF_FAILED_2(hr, "Could not await services operation");
+
+ GattCommunicationStatus commStatus;
+ hr = deviceServicesResult->get_Status(&commStatus);
+ if (FAILED(hr) || commStatus != GattCommunicationStatus_Success) {
+ emitErrorAndQuitThread("Service operation failed");
return;
- } else {
- Q_ASSERT_SUCCEEDED(hr);
}
- uint characteristicsCount;
- hr = characteristics->get_Size(&characteristicsCount);
- Q_ASSERT_SUCCEEDED(hr);
- for (uint j = 0; j < characteristicsCount; ++j) {
- ComPtr<IGattCharacteristic> characteristic;
- hr = characteristics->GetAt(j, &characteristic);
- Q_ASSERT_SUCCEEDED(hr);
- ComPtr<IAsyncOperation<GattReadResult *>> op;
- GattCharacteristicProperties props;
- hr = characteristic->get_CharacteristicProperties(&props);
- Q_ASSERT_SUCCEEDED(hr);
- if (!(props & GattCharacteristicProperties_Read))
- continue;
- hr = characteristic->ReadValueWithCacheModeAsync(BluetoothCacheMode::BluetoothCacheMode_Uncached, &op);
- Q_ASSERT_SUCCEEDED(hr);
- ComPtr<IGattReadResult> result;
- hr = QWinRTFunctions::await(op, result.GetAddressOf());
- if (hr == E_INVALIDARG) {
- // E_INVALIDARG happens when user tries to connect to a device that was paired
- // before but is not available.
- qCDebug(QT_BT_WINRT) << "Could not obtain characteristic read result that triggers"
- "device connection. Is the device reachable?";
- setError(QLowEnergyController::ConnectionError);
- setState(QLowEnergyController::UnconnectedState);
- return;
- } else if (hr != S_OK) {
- qCWarning(QT_BT_WINRT) << "Connecting to device failed: "
- << qt_error_string(hr);
- setError(QLowEnergyController::ConnectionError);
- setState(QLowEnergyController::UnconnectedState);
+
+ ComPtr<IVectorView<GattDeviceService *>> deviceServices;
+ hr = deviceServicesResult->get_Services(&deviceServices);
+ EMIT_WORKER_ERROR_AND_QUIT_IF_FAILED_2(hr, "Could not obtain list of services");
+ uint serviceCount;
+ hr = deviceServices->get_Size(&serviceCount);
+ EMIT_WORKER_ERROR_AND_QUIT_IF_FAILED_2(hr, "Could not obtain service count");
+
+ if (serviceCount == 0) {
+ emitErrorAndQuitThread("Found devices without services");
+ return;
+ }
+
+ // Windows automatically connects to the device as soon as a service value is read/written.
+ // Thus we read one value in order to establish the connection.
+ for (uint i = 0; i < serviceCount; ++i) {
+ ComPtr<IGattDeviceService> service;
+ hr = deviceServices->GetAt(i, &service);
+ EMIT_WORKER_ERROR_AND_QUIT_IF_FAILED_2(hr, "Could not obtain service");
+ ComPtr<IGattDeviceService3> service3;
+ hr = service.As(&service3);
+ EMIT_WORKER_ERROR_AND_QUIT_IF_FAILED_2(hr, "Could not cast service");
+ ComPtr<IAsyncOperation<GattCharacteristicsResult *>> characteristicsOp;
+ hr = service3->GetCharacteristicsAsync(&characteristicsOp);
+ EMIT_WORKER_ERROR_AND_QUIT_IF_FAILED_2(hr, "Could not obtain characteristic");
+ ComPtr<IGattCharacteristicsResult> characteristicsResult;
+ hr = QWinRTFunctions::await(characteristicsOp, characteristicsResult.GetAddressOf(),
+ QWinRTFunctions::ProcessThreadEvents, 5000, earlyExit);
+ EMIT_WORKER_ERROR_AND_QUIT_IF_FAILED_2(hr, "Could not await characteristic operation");
+ GattCommunicationStatus commStatus;
+ hr = characteristicsResult->get_Status(&commStatus);
+ if (FAILED(hr) || commStatus != GattCommunicationStatus_Success) {
+ qCWarning(QT_BT_WINDOWS) << "Characteristic operation failed";
+ break;
+ }
+ ComPtr<IVectorView<GattCharacteristic *>> characteristics;
+ hr = characteristicsResult->get_Characteristics(&characteristics);
+ if (hr == E_ACCESSDENIED) {
+ // Everything will work as expected up until this point if the
+ // manifest capabilties for bluetooth LE are not set.
+ emitErrorAndQuitThread("Could not obtain characteristic list. "
+ "Please check your manifest capabilities");
return;
}
- ComPtr<ABI::Windows::Storage::Streams::IBuffer> buffer;
- hr = result->get_Value(&buffer);
- Q_ASSERT_SUCCEEDED(hr);
- if (!buffer) {
- qCDebug(QT_BT_WINRT) << "Problem reading value";
- setError(QLowEnergyController::ConnectionError);
- setState(QLowEnergyController::UnconnectedState);
+ EMIT_WORKER_ERROR_AND_QUIT_IF_FAILED_2(hr, "Could not obtain characteristic list");
+ uint characteristicsCount;
+ hr = characteristics->get_Size(&characteristicsCount);
+ EMIT_WORKER_ERROR_AND_QUIT_IF_FAILED_2(hr,
+ "Could not obtain characteristic list's size");
+ for (uint j = 0; j < characteristicsCount; ++j) {
+ ComPtr<IGattCharacteristic> characteristic;
+ hr = characteristics->GetAt(j, &characteristic);
+ EMIT_WORKER_ERROR_AND_QUIT_IF_FAILED_2(hr, "Could not obtain characteristic");
+ ComPtr<IAsyncOperation<GattReadResult *>> op;
+ GattCharacteristicProperties props;
+ hr = characteristic->get_CharacteristicProperties(&props);
+ EMIT_WORKER_ERROR_AND_QUIT_IF_FAILED_2(
+ hr, "Could not obtain characteristic's properties");
+ if (!(props & GattCharacteristicProperties_Read))
+ continue;
+ hr = characteristic->ReadValueWithCacheModeAsync(
+ BluetoothCacheMode::BluetoothCacheMode_Uncached, &op);
+ EMIT_WORKER_ERROR_AND_QUIT_IF_FAILED_2(hr, "Could not read characteristic value");
+ ComPtr<IGattReadResult> result;
+ // Reading characteristics can take surprisingly long at the
+ // first time, so we need to have a large the timeout here.
+ hr = QWinRTFunctions::await(op, result.GetAddressOf(),
+ QWinRTFunctions::ProcessThreadEvents, 5000, earlyExit);
+ // E_ILLEGAL_METHOD_CALL will be the result for a device, that is not reachable at
+ // the moment. In this case we should jump back into the outer loop and keep trying.
+ if (hr == E_ILLEGAL_METHOD_CALL)
+ break;
+ EMIT_WORKER_ERROR_AND_QUIT_IF_FAILED_2(hr, "Could not await characteristic read");
+ ComPtr<ABI::Windows::Storage::Streams::IBuffer> buffer;
+ hr = result->get_Value(&buffer);
+ EMIT_WORKER_ERROR_AND_QUIT_IF_FAILED_2(hr, "Could not obtain characteristic value");
+ if (!buffer) {
+ qCDebug(QT_BT_WINDOWS) << "Problem reading value";
+ break;
+ }
+
+ emitConnectedAndQuitThread();
+ return;
}
+ }
+ }
+ // If we got here because of mAbortConnection == true, the error message
+ // will not be delivered, so it does not matter. But we need to terminate
+ // the thread anyway!
+ emitErrorAndQuitThread("Connect to device failed due to timeout!");
+}
+
+void QWinRTLowEnergyConnectionHandler::connectToUnpairedDevice()
+{
+ qCDebug(QT_BT_WINDOWS) << __FUNCTION__;
+ ComPtr<IBluetoothLEDevice3> device3;
+ HRESULT hr = mDevice.As(&device3);
+ EMIT_WORKER_ERROR_AND_QUIT_IF_FAILED_2(hr, "Could not cast device");
+ ComPtr<IGattDeviceServicesResult> deviceServicesResult;
+ auto earlyExit = [this]() { return mAbortConnection; };
+ QDeadlineTimer deadline(kMaxConnectTimeout);
+ while (!mAbortConnection && !deadline.hasExpired()) {
+ ComPtr<IAsyncOperation<GattDeviceServicesResult *>> deviceServicesOp;
+ hr = device3->GetGattServicesAsync(&deviceServicesOp);
+ EMIT_WORKER_ERROR_AND_QUIT_IF_FAILED_2(hr, "Could not obtain services");
+ hr = QWinRTFunctions::await(deviceServicesOp, deviceServicesResult.GetAddressOf(),
+ QWinRTFunctions::ProcessMainThreadEvents, 0, earlyExit);
+ EMIT_WORKER_ERROR_AND_QUIT_IF_FAILED_2(hr, "Could not await services operation");
+
+ GattCommunicationStatus commStatus;
+ hr = deviceServicesResult->get_Status(&commStatus);
+ if (commStatus == GattCommunicationStatus_Unreachable)
+ continue;
+
+ if (FAILED(hr) || commStatus != GattCommunicationStatus_Success) {
+ emitErrorAndQuitThread("Service operation failed");
return;
}
+
+ emitConnectedAndQuitThread();
+ return;
}
+ // If we got here because of mAbortConnection == true, the error message
+ // will not be delivered, so it does not matter. But we need to terminate
+ // the thread anyway!
+ emitErrorAndQuitThread("Connect to device failed due to timeout!");
+}
+
+void QWinRTLowEnergyConnectionHandler::emitErrorAndQuitThread(const QString &error)
+{
+ emit errorOccurred(error);
+ QThread::currentThread()->quit();
+}
+
+void QWinRTLowEnergyConnectionHandler::emitErrorAndQuitThread(const char *error)
+{
+ emitErrorAndQuitThread(QString::fromUtf8(error));
+}
+
+void QWinRTLowEnergyConnectionHandler::emitConnectedAndQuitThread()
+{
+ emit deviceConnected(mDevice, mGattSession);
+ QThread::currentThread()->quit();
+}
+
+QLowEnergyControllerPrivateWinRT::QLowEnergyControllerPrivateWinRT()
+ : QLowEnergyControllerPrivate()
+{
+ registerQLowEnergyControllerMetaType();
+ connect(this, &QLowEnergyControllerPrivateWinRT::characteristicChanged,
+ this, &QLowEnergyControllerPrivateWinRT::handleCharacteristicChanged,
+ Qt::QueuedConnection);
+}
+
+QLowEnergyControllerPrivateWinRT::~QLowEnergyControllerPrivateWinRT()
+{
+ unregisterFromStatusChanges();
+ unregisterFromValueChanges();
+}
+
+void QLowEnergyControllerPrivateWinRT::init()
+{
+}
+
+void QLowEnergyControllerPrivateWinRT::connectToDevice()
+{
+ qCDebug(QT_BT_WINDOWS) << __FUNCTION__;
+ if (remoteDevice.isNull()) {
+ qCWarning(QT_BT_WINDOWS) << "Invalid/null remote device address";
+ setError(QLowEnergyController::UnknownRemoteDeviceError);
+ return;
+ }
+ setState(QLowEnergyController::ConnectingState);
+
+ QWinRTLowEnergyConnectionHandler *worker = new QWinRTLowEnergyConnectionHandler(remoteDevice);
+ QThread *thread = new QThread;
+ worker->moveToThread(thread);
+ connect(this, &QLowEnergyControllerPrivateWinRT::abortConnection, worker,
+ &QWinRTLowEnergyConnectionHandler::handleDeviceDisconnectRequest);
+ connect(thread, &QThread::started, worker, &QWinRTLowEnergyConnectionHandler::connectToDevice);
+ connect(thread, &QThread::finished, worker, &QObject::deleteLater);
+ connect(worker, &QObject::destroyed, thread, &QObject::deleteLater);
+ connect(worker, &QWinRTLowEnergyConnectionHandler::errorOccurred, this,
+ [this](const QString &msg) { handleConnectionError(msg.toUtf8().constData()); });
+ connect(worker, &QWinRTLowEnergyConnectionHandler::deviceConnected, this,
+ [this](ComPtr<IBluetoothLEDevice> device, ComPtr<IGattSession> session) {
+ if (!device || !session) {
+ handleConnectionError("Failed to get device or gatt service");
+ return;
+ }
+ mDevice = device;
+ mGattSession = session;
+
+ if (!registerForStatusChanges() || !registerForMtuChanges()) {
+ handleConnectionError("Failed to register for changes");
+ return;
+ }
+
+ Q_Q(QLowEnergyController);
+ setState(QLowEnergyController::ConnectedState);
+ emit q->connected();
+ });
+ thread->start();
}
void QLowEnergyControllerPrivateWinRT::disconnectFromDevice()
{
- qCDebug(QT_BT_WINRT) << __FUNCTION__;
+ qCDebug(QT_BT_WINDOWS) << __FUNCTION__;
Q_Q(QLowEnergyController);
setState(QLowEnergyController::ClosingState);
+ emit abortConnection();
unregisterFromValueChanges();
- if (mDevice) {
- if (mStatusChangedToken.value) {
- mDevice->remove_ConnectionStatusChanged(mStatusChangedToken);
- mStatusChangedToken.value = 0;
- }
- mDevice = nullptr;
- }
+ unregisterFromStatusChanges();
+ unregisterFromMtuChanges();
+ clearAllServices();
+ mGattSession = nullptr;
+ mDevice = nullptr;
setState(QLowEnergyController::UnconnectedState);
emit q->disconnected();
}
-ComPtr<IGattDeviceService> QLowEnergyControllerPrivateWinRT::getNativeService(const QBluetoothUuid &serviceUuid)
+HRESULT QLowEnergyControllerPrivateWinRT::getNativeService(const QBluetoothUuid &serviceUuid,
+ NativeServiceCallback callback)
{
- ComPtr<IGattDeviceService> deviceService;
- HRESULT hr;
- hr = mDevice->GetGattService(serviceUuid, &deviceService);
- if (FAILED(hr))
- qCDebug(QT_BT_WINRT) << "Could not obtain native service for Uuid" << serviceUuid;
- return deviceService;
+ if (m_openedServices.contains(serviceUuid)) {
+ callback(m_openedServices.value(serviceUuid));
+ return S_OK;
+ }
+
+ ComPtr<IBluetoothLEDevice3> device3;
+ HRESULT hr = mDevice.As(&device3);
+ RETURN_IF_FAILED("Could not convert to IBluetoothDevice3", return hr);
+
+ ComPtr<IAsyncOperation<GattDeviceServicesResult *>> servicesResultOperation;
+ hr = device3->GetGattServicesForUuidAsync(serviceUuid, &servicesResultOperation);
+ RETURN_IF_FAILED("Could not start async services request", return hr);
+
+ QPointer<QLowEnergyControllerPrivateWinRT> thisPtr(this);
+ hr = servicesResultOperation->put_Completed(
+ Callback<IAsyncOperationCompletedHandler<
+ GenericAttributeProfile::GattDeviceServicesResult *>>(
+ [thisPtr, callback, &serviceUuid](
+ IAsyncOperation<GattDeviceServicesResult *> *op, AsyncStatus status)
+ {
+ if (thisPtr) {
+ if (status != AsyncStatus::Completed) {
+ qCDebug(QT_BT_WINDOWS) << "Failed to get result of async service request";
+ return S_OK;
+ }
+ ComPtr<IGattDeviceServicesResult> result;
+ ComPtr<IVectorView<GattDeviceService *>> deviceServices;
+ HRESULT hr = op->GetResults(&result);
+ RETURN_IF_FAILED("Failed to get result of async service request", return hr);
+
+ ComPtr<IVectorView<GattDeviceService *>> services;
+ hr = result->get_Services(&services);
+ RETURN_IF_FAILED("Failed to extract services from the result", return hr);
+
+ uint servicesCount = 0;
+ hr = services->get_Size(&servicesCount);
+ RETURN_IF_FAILED("Failed to extract services count", return hr);
+
+ if (servicesCount > 0) {
+ if (servicesCount > 1) {
+ qWarning() << "getNativeService: more than one service detected for UUID"
+ << serviceUuid << "The first service will be used.";
+ }
+ ComPtr<IGattDeviceService> service;
+ hr = services->GetAt(0, &service);
+ if (FAILED(hr)) {
+ qCDebug(QT_BT_WINDOWS) << "Could not obtain native service for Uuid"
+ << serviceUuid;
+ }
+ if (service) {
+ thisPtr->m_openedServices[serviceUuid] = service;
+ callback(service); // Use the service in a custom callback
+ }
+ } else {
+ qCWarning(QT_BT_WINDOWS) << "No services found for Uuid" << serviceUuid;
+ }
+ } else {
+ qCWarning(QT_BT_WINDOWS) << "LE controller was removed while getting native service";
+ }
+ return S_OK;
+ }).Get());
+
+ return hr;
}
-ComPtr<IGattCharacteristic> QLowEnergyControllerPrivateWinRT::getNativeCharacteristic(const QBluetoothUuid &serviceUuid, const QBluetoothUuid &charUuid)
+HRESULT QLowEnergyControllerPrivateWinRT::getNativeCharacteristic(
+ const QBluetoothUuid &serviceUuid, const QBluetoothUuid &charUuid,
+ NativeCharacteristicCallback callback)
{
- ComPtr<IGattDeviceService> service = getNativeService(serviceUuid);
- if (!service)
- return nullptr;
-
- ComPtr<IVectorView<GattCharacteristic *>> characteristics;
- HRESULT hr = service->GetCharacteristics(charUuid, &characteristics);
- RETURN_IF_FAILED("Could not obtain native characteristics for service", return nullptr);
- ComPtr<IGattCharacteristic> characteristic;
- hr = characteristics->GetAt(0, &characteristic);
- RETURN_IF_FAILED("Could not obtain first characteristic for service", return nullptr);
- return characteristic;
+ QPointer<QLowEnergyControllerPrivateWinRT> thisPtr(this);
+ auto serviceCallback = [thisPtr, callback, charUuid](ComPtr<IGattDeviceService> service) {
+ ComPtr<IGattDeviceService3> service3;
+ HRESULT hr = service.As(&service3);
+ RETURN_IF_FAILED("Could not cast service to service3", return);
+
+ ComPtr<IAsyncOperation<GattCharacteristicsResult *>> characteristicRequestOp;
+ hr = service3->GetCharacteristicsForUuidAsync(charUuid, &characteristicRequestOp);
+
+ hr = characteristicRequestOp->put_Completed(
+ Callback<IAsyncOperationCompletedHandler<GattCharacteristicsResult *>>(
+ [thisPtr, callback](
+ IAsyncOperation<GattCharacteristicsResult *> *op, AsyncStatus status)
+ {
+ if (thisPtr) {
+ if (status != AsyncStatus::Completed) {
+ qCDebug(QT_BT_WINDOWS) << "Failed to get result of async characteristic "
+ "operation";
+ return S_OK;
+ }
+ ComPtr<IGattCharacteristicsResult> result;
+ HRESULT hr = op->GetResults(&result);
+ RETURN_IF_FAILED("Failed to get result of async characteristic operation",
+ return hr);
+ GattCommunicationStatus status;
+ hr = result->get_Status(&status);
+ if (FAILED(hr) || status != GattCommunicationStatus_Success) {
+ qErrnoWarning(hr, "Native characteristic operation failed.");
+ return S_OK;
+ }
+ ComPtr<IVectorView<GattCharacteristic *>> characteristics;
+ hr = result->get_Characteristics(&characteristics);
+ RETURN_IF_FAILED("Could not obtain characteristic list.", return S_OK);
+ uint size;
+ hr = characteristics->get_Size(&size);
+ RETURN_IF_FAILED("Could not obtain characteristic list's size.", return S_OK);
+ if (size != 1)
+ qErrnoWarning("More than 1 characteristic found.");
+ ComPtr<IGattCharacteristic> characteristic;
+ hr = characteristics->GetAt(0, &characteristic);
+ RETURN_IF_FAILED("Could not obtain first characteristic for service", return S_OK);
+ if (characteristic)
+ callback(characteristic); // use the characteristic in a custom callback
+ }
+ return S_OK;
+ }).Get());
+ };
+
+ HRESULT hr = getNativeService(serviceUuid, serviceCallback);
+ if (FAILED(hr))
+ qCDebug(QT_BT_WINDOWS) << "Failed to get native service for" << serviceUuid;
+
+ return hr;
}
-void QLowEnergyControllerPrivateWinRT::registerForValueChanges(const QBluetoothUuid &serviceUuid, const QBluetoothUuid &charUuid)
+void QLowEnergyControllerPrivateWinRT::registerForValueChanges(const QBluetoothUuid &serviceUuid,
+ const QBluetoothUuid &charUuid)
{
- qCDebug(QT_BT_WINRT) << "Registering characteristic" << charUuid << "in service"
+ qCDebug(QT_BT_WINDOWS) << "Registering characteristic" << charUuid << "in service"
<< serviceUuid << "for value changes";
- for (const ValueChangedEntry &entry : qAsConst(mValueChangedTokens)) {
+ for (const ValueChangedEntry &entry : std::as_const(mValueChangedTokens)) {
GUID guuid;
HRESULT hr;
hr = entry.characteristic->get_Uuid(&guuid);
- Q_ASSERT_SUCCEEDED(hr);
+ WARN_AND_CONTINUE_IF_FAILED(hr, "Could not obtain characteristic's Uuid")
if (QBluetoothUuid(guuid) == charUuid)
return;
}
- ComPtr<IGattCharacteristic> characteristic = getNativeCharacteristic(serviceUuid, charUuid);
- EventRegistrationToken token;
- HRESULT hr;
- hr = characteristic->add_ValueChanged(Callback<ValueChangedHandler>([this](IGattCharacteristic *characteristic, IGattValueChangedEventArgs *args) {
+ auto callback = [this, charUuid, serviceUuid](ComPtr<IGattCharacteristic> characteristic) {
+ EventRegistrationToken token;
HRESULT hr;
- quint16 handle;
- hr = characteristic->get_AttributeHandle(&handle);
- Q_ASSERT_SUCCEEDED(hr);
- ComPtr<IBuffer> buffer;
- hr = args->get_CharacteristicValue(&buffer);
- Q_ASSERT_SUCCEEDED(hr);
- emit characteristicChanged(handle, byteArrayFromBuffer(buffer));
- return S_OK;
- }).Get(), &token);
- Q_ASSERT_SUCCEEDED(hr);
- mValueChangedTokens.append(ValueChangedEntry(characteristic, token));
- qCDebug(QT_BT_WINRT) << "Characteristic" << charUuid << "in service"
- << serviceUuid << "registered for value changes";
+ hr = characteristic->add_ValueChanged(
+ Callback<ValueChangedHandler>(
+ this, &QLowEnergyControllerPrivateWinRT::onValueChange).Get(),
+ &token);
+ RETURN_IF_FAILED("Could not register characteristic for value changes", return)
+ mValueChangedTokens.append(ValueChangedEntry(characteristic, token));
+ qCDebug(QT_BT_WINDOWS) << "Characteristic" << charUuid << "in service"
+ << serviceUuid << "registered for value changes";
+ };
+
+ HRESULT hr = getNativeCharacteristic(serviceUuid, charUuid, callback);
+ if (FAILED(hr)) {
+ qCDebug(QT_BT_WINDOWS).nospace() << "Could not obtain native characteristic "
+ << charUuid << " from service " << serviceUuid
+ << ". Qt will not be able to signal"
+ << " changes for this characteristic.";
+ }
}
void QLowEnergyControllerPrivateWinRT::unregisterFromValueChanges()
{
- qCDebug(QT_BT_WINRT) << "Unregistering " << mValueChangedTokens.count() << " value change tokens";
+ qCDebug(QT_BT_WINDOWS) << "Unregistering " << mValueChangedTokens.size() << " value change tokens";
HRESULT hr;
- for (const ValueChangedEntry &entry : qAsConst(mValueChangedTokens)) {
+ for (const ValueChangedEntry &entry : std::as_const(mValueChangedTokens)) {
+ if (!entry.characteristic) {
+ qCWarning(QT_BT_WINDOWS) << "Unregistering from value changes for characteristic failed."
+ << "Characteristic has been deleted";
+ continue;
+ }
hr = entry.characteristic->remove_ValueChanged(entry.token);
- Q_ASSERT_SUCCEEDED(hr);
+ if (FAILED(hr))
+ qCWarning(QT_BT_WINDOWS) << "Unregistering from value changes for characteristic failed.";
}
mValueChangedTokens.clear();
}
-void QLowEnergyControllerPrivateWinRT::obtainIncludedServices(QSharedPointer<QLowEnergyServicePrivate> servicePointer,
- ComPtr<IGattDeviceService> service)
+HRESULT QLowEnergyControllerPrivateWinRT::onValueChange(IGattCharacteristic *characteristic, IGattValueChangedEventArgs *args)
+{
+ HRESULT hr;
+ quint16 handle;
+ hr = characteristic->get_AttributeHandle(&handle);
+ RETURN_IF_FAILED("Could not obtain characteristic's handle", return S_OK)
+ ComPtr<IBuffer> buffer;
+ hr = args->get_CharacteristicValue(&buffer);
+ RETURN_IF_FAILED("Could not obtain characteristic's value", return S_OK)
+ emit characteristicChanged(handle, byteArrayFromBuffer(buffer));
+ return S_OK;
+}
+HRESULT QLowEnergyControllerPrivateWinRT::onMtuChange(IGattSession *session, IInspectable *args)
{
+ qCDebug(QT_BT_WINDOWS) << __FUNCTION__;
+ if (session != mGattSession.Get()) {
+ qCWarning(QT_BT_WINDOWS) << "Got MTU changed event for wrong or outdated GattSession.";
+ return S_OK;
+ }
+
Q_Q(QLowEnergyController);
- ComPtr<IGattDeviceService2> service2;
- HRESULT hr = service.As(&service2);
- Q_ASSERT_SUCCEEDED(hr);
- ComPtr<IVectorView<GattDeviceService *>> includedServices;
- hr = service2->GetAllIncludedServices(&includedServices);
+ emit q->mtuChanged(mtu());
+ return S_OK;
+}
+
+bool QLowEnergyControllerPrivateWinRT::registerForStatusChanges()
+{
+ if (!mDevice)
+ return false;
+
+ qCDebug(QT_BT_WINDOWS) << __FUNCTION__;
+
+ HRESULT hr;
+ hr = mDevice->add_ConnectionStatusChanged(
+ Callback<StatusHandler>(this, &QLowEnergyControllerPrivateWinRT::onStatusChange).Get(),
+ &mStatusChangedToken);
+ RETURN_IF_FAILED("Could not add status callback", return false)
+ return true;
+}
+
+void QLowEnergyControllerPrivateWinRT::unregisterFromStatusChanges()
+{
+ qCDebug(QT_BT_WINDOWS) << __FUNCTION__;
+ if (mDevice && mStatusChangedToken.value) {
+ mDevice->remove_ConnectionStatusChanged(mStatusChangedToken);
+ mStatusChangedToken.value = 0;
+ }
+}
+
+bool QLowEnergyControllerPrivateWinRT::registerForMtuChanges()
+{
+ if (!mDevice || !mGattSession)
+ return false;
+
+ qCDebug(QT_BT_WINDOWS) << __FUNCTION__;
+
+ HRESULT hr;
+ hr = mGattSession->add_MaxPduSizeChanged(
+ Callback<MtuHandler>(this, &QLowEnergyControllerPrivateWinRT::onMtuChange).Get(),
+ &mMtuChangedToken);
+ RETURN_IF_FAILED("Could not add MTU callback", return false)
+ return true;
+}
+
+void QLowEnergyControllerPrivateWinRT::unregisterFromMtuChanges()
+{
+ qCDebug(QT_BT_WINDOWS) << __FUNCTION__;
+ if (mDevice && mGattSession && mMtuChangedToken.value) {
+ mGattSession->remove_MaxPduSizeChanged(mMtuChangedToken);
+ mMtuChangedToken.value = 0;
+ }
+}
+
+HRESULT QLowEnergyControllerPrivateWinRT::onStatusChange(IBluetoothLEDevice *dev, IInspectable *)
+{
+ Q_Q(QLowEnergyController);
+ BluetoothConnectionStatus status;
+ HRESULT hr;
+ hr = dev->get_ConnectionStatus(&status);
+ RETURN_IF_FAILED("Could not obtain connection status", return S_OK)
+ if (state == QLowEnergyController::ConnectingState
+ && status == BluetoothConnectionStatus::BluetoothConnectionStatus_Connected) {
+ setState(QLowEnergyController::ConnectedState);
+ emit q->connected();
+ } else if (state != QLowEnergyController::UnconnectedState
+ && status == BluetoothConnectionStatus::BluetoothConnectionStatus_Disconnected) {
+ invalidateServices();
+ unregisterFromValueChanges();
+ unregisterFromStatusChanges();
+ unregisterFromMtuChanges();
+ mGattSession = nullptr;
+ mDevice = nullptr;
+ setError(QLowEnergyController::RemoteHostClosedError);
+ setState(QLowEnergyController::UnconnectedState);
+ emit q->disconnected();
+ }
+ return S_OK;
+}
+
+void QLowEnergyControllerPrivateWinRT::obtainIncludedServices(
+ QSharedPointer<QLowEnergyServicePrivate> servicePointer,
+ ComPtr<IGattDeviceService> service)
+{
+ Q_Q(QLowEnergyController);
+ ComPtr<IGattDeviceService3> service3;
+ HRESULT hr = service.As(&service3);
+ RETURN_IF_FAILED("Could not cast service", return);
+ ComPtr<IAsyncOperation<GattDeviceServicesResult *>> op;
+ hr = service3->GetIncludedServicesAsync(&op);
// Some devices return ERROR_ACCESS_DISABLED_BY_POLICY
- if (FAILED(hr))
+ RETURN_IF_FAILED("Could not obtain included services", return);
+ ComPtr<IGattDeviceServicesResult> result;
+ hr = QWinRTFunctions::await(op, result.GetAddressOf(), QWinRTFunctions::ProcessMainThreadEvents, 5000);
+ RETURN_IF_FAILED("Could not await service operation", return);
+ // The device can be disconnected by the time we return from await()
+ if (state != QLowEnergyController::DiscoveringState)
return;
+ GattCommunicationStatus status;
+ hr = result->get_Status(&status);
+ if (FAILED(hr) || status != GattCommunicationStatus_Success) {
+ qErrnoWarning("Could not obtain list of included services");
+ return;
+ }
+ ComPtr<IVectorView<GattDeviceService *>> includedServices;
+ hr = result->get_Services(&includedServices);
+ RETURN_IF_FAILED("Could not obtain service list", return);
uint count;
hr = includedServices->get_Size(&count);
- Q_ASSERT_SUCCEEDED(hr);
+ RETURN_IF_FAILED("Could not obtain service list's size", return);
for (uint i = 0; i < count; ++i) {
ComPtr<IGattDeviceService> includedService;
hr = includedServices->GetAt(i, &includedService);
- Q_ASSERT_SUCCEEDED(hr);
+ WARN_AND_CONTINUE_IF_FAILED(hr, "Could not obtain service from list");
GUID guuid;
hr = includedService->get_Uuid(&guuid);
- Q_ASSERT_SUCCEEDED(hr);
+ WARN_AND_CONTINUE_IF_FAILED(hr, "Could not obtain included service's Uuid");
const QBluetoothUuid includedUuid(guuid);
QSharedPointer<QLowEnergyServicePrivate> includedPointer;
- qCDebug(QT_BT_WINRT_SERVICE_THREAD) << __FUNCTION__
+ qCDebug(QT_BT_WINDOWS_SERVICE_THREAD) << __FUNCTION__
<< "Changing service pointer from thread"
<< QThread::currentThread();
if (serviceList.contains(includedUuid)) {
@@ -515,9 +1067,6 @@ void QLowEnergyControllerPrivateWinRT::obtainIncludedServices(QSharedPointer<QLo
includedPointer = QSharedPointer<QLowEnergyServicePrivate>(priv);
serviceList.insert(includedUuid, includedPointer);
}
- qCDebug(QT_BT_WINRT_SERVICE_THREAD) << __FUNCTION__
- << "Changing service pointer from thread"
- << QThread::currentThread();
includedPointer->type |= QLowEnergyService::IncludedService;
servicePointer->includedServices.append(includedUuid);
@@ -527,27 +1076,53 @@ void QLowEnergyControllerPrivateWinRT::obtainIncludedServices(QSharedPointer<QLo
}
}
-void QLowEnergyControllerPrivateWinRT::discoverServices()
+HRESULT QLowEnergyControllerPrivateWinRT::onServiceDiscoveryFinished(ABI::Windows::Foundation::IAsyncOperation<GattDeviceServicesResult *> *op, AsyncStatus status)
{
- Q_Q(QLowEnergyController);
+ // Check if the device is in the proper state, because it can already be
+ // disconnected when the callback arrives.
+ // Also the callback can theoretically come when the connection is
+ // reestablisheed again (for example, if the user quickly clicks
+ // "Disconnect" and then "Connect" again in some UI). But we can probably
+ // omit such details, as we are connecting to the same device anyway.
+ if (state != QLowEnergyController::DiscoveringState)
+ return S_OK;
- qCDebug(QT_BT_WINRT) << "Service discovery initiated";
+ Q_Q(QLowEnergyController);
+ if (status != AsyncStatus::Completed) {
+ qCDebug(QT_BT_WINDOWS) << "Could not obtain services";
+ return S_OK;
+ }
+ ComPtr<IGattDeviceServicesResult> result;
ComPtr<IVectorView<GattDeviceService *>> deviceServices;
- HRESULT hr = mDevice->get_GattServices(&deviceServices);
- Q_ASSERT_SUCCEEDED(hr);
+ HRESULT hr = op->GetResults(&result);
+ CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not obtain service discovery result",
+ return S_OK);
+ GattCommunicationStatus commStatus;
+ hr = result->get_Status(&commStatus);
+ CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not obtain service discovery status",
+ return S_OK);
+ if (commStatus != GattCommunicationStatus_Success)
+ return S_OK;
+
+ hr = result->get_Services(&deviceServices);
+ CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not obtain service list",
+ return S_OK);
+
uint serviceCount;
hr = deviceServices->get_Size(&serviceCount);
- Q_ASSERT_SUCCEEDED(hr);
+ CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not obtain service list size",
+ return S_OK);
for (uint i = 0; i < serviceCount; ++i) {
ComPtr<IGattDeviceService> deviceService;
hr = deviceServices->GetAt(i, &deviceService);
- Q_ASSERT_SUCCEEDED(hr);
+ WARN_AND_CONTINUE_IF_FAILED(hr, "Could not obtain service");
GUID guuid;
hr = deviceService->get_Uuid(&guuid);
- Q_ASSERT_SUCCEEDED(hr);
+ WARN_AND_CONTINUE_IF_FAILED(hr, "Could not obtain service's Uuid");
const QBluetoothUuid service(guuid);
+ m_openedServices[service] = deviceService;
- qCDebug(QT_BT_WINRT_SERVICE_THREAD) << __FUNCTION__
+ qCDebug(QT_BT_WINDOWS_SERVICE_THREAD) << __FUNCTION__
<< "Changing service pointer from thread"
<< QThread::currentThread();
QSharedPointer<QLowEnergyServicePrivate> pointer;
@@ -564,61 +1139,161 @@ void QLowEnergyControllerPrivateWinRT::discoverServices()
pointer->type |= QLowEnergyService::PrimaryService;
obtainIncludedServices(pointer, deviceService);
+ // The obtainIncludedServices method calls await(), so the device can be
+ // disconnected by the time we return from it. TODO - rewrite in an
+ // async way!
+ if (state != QLowEnergyController::DiscoveringState) {
+ emit q->discoveryFinished(); // Probably not needed when the device
+ // is already disconnected?
+ return S_OK;
+ }
emit q->serviceDiscovered(service);
}
setState(QLowEnergyController::DiscoveredState);
emit q->discoveryFinished();
+
+ return S_OK;
}
-void QLowEnergyControllerPrivateWinRT::discoverServiceDetails(const QBluetoothUuid &service)
+void QLowEnergyControllerPrivateWinRT::clearAllServices()
{
- qCDebug(QT_BT_WINRT) << __FUNCTION__ << service;
+ // These services will be closed in the respective
+ // QWinRTLowEnergyServiceHandler workers (in background threads).
+ for (auto &uuid : m_requestDetailsServiceUuids)
+ m_openedServices.remove(uuid);
+ m_requestDetailsServiceUuids.clear();
+
+ for (auto service : m_openedServices) {
+ closeDeviceService(service);
+ }
+ m_openedServices.clear();
+}
+
+void QLowEnergyControllerPrivateWinRT::closeAndRemoveService(const QBluetoothUuid &uuid)
+{
+ auto service = m_openedServices.take(uuid);
+ if (service)
+ closeDeviceService(service);
+}
+
+void QLowEnergyControllerPrivateWinRT::discoverServices()
+{
+ qCDebug(QT_BT_WINDOWS) << "Service discovery initiated";
+ // clear the previous services cache, as we request the services again
+ clearAllServices();
+ ComPtr<IBluetoothLEDevice3> device3;
+ HRESULT hr = mDevice.As(&device3);
+ CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not cast device", return);
+ ComPtr<IAsyncOperation<GenericAttributeProfile::GattDeviceServicesResult *>> asyncResult;
+ hr = device3->GetGattServicesAsync(&asyncResult);
+ CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not obtain services", return);
+ hr = asyncResult->put_Completed(
+ Callback<IAsyncOperationCompletedHandler<GenericAttributeProfile::GattDeviceServicesResult *>>(
+ this, &QLowEnergyControllerPrivateWinRT::onServiceDiscoveryFinished).Get());
+ CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not register services discovery callback",
+ return);
+}
+
+void QLowEnergyControllerPrivateWinRT::discoverServiceDetails(
+ const QBluetoothUuid &service, QLowEnergyService::DiscoveryMode mode)
+{
+ qCDebug(QT_BT_WINDOWS) << __FUNCTION__ << service;
if (!serviceList.contains(service)) {
- qCWarning(QT_BT_WINRT) << "Discovery done of unknown service:"
+ qCWarning(QT_BT_WINDOWS) << "Discovery done of unknown service:"
<< service.toString();
return;
}
- ComPtr<IGattDeviceService> deviceService = getNativeService(service);
- if (!deviceService) {
- qCDebug(QT_BT_WINRT) << "Could not obtain native service for uuid " << service;
- return;
- }
+ // clear the cache to rediscover service details
+ closeAndRemoveService(service);
+
+ auto serviceCallback = [service, mode, this](ComPtr<IGattDeviceService> deviceService) {
+ discoverServiceDetailsHelper(service, mode, deviceService);
+ };
+ HRESULT hr = getNativeService(service, serviceCallback);
+ if (FAILED(hr))
+ qCDebug(QT_BT_WINDOWS) << "Could not obtain native service for uuid " << service;
+}
+
+void QLowEnergyControllerPrivateWinRT::discoverServiceDetailsHelper(
+ const QBluetoothUuid &service, QLowEnergyService::DiscoveryMode mode,
+ GattDeviceServiceComPtr deviceService)
+{
+ auto reactOnDiscoveryError = [](QSharedPointer<QLowEnergyServicePrivate> service,
+ const QString &msg)
+ {
+ qCDebug(QT_BT_WINDOWS) << msg;
+ service->setError(QLowEnergyService::UnknownError);
+ service->setState(QLowEnergyService::RemoteService);
+ };
//update service data
QSharedPointer<QLowEnergyServicePrivate> pointer = serviceList.value(service);
- qCDebug(QT_BT_WINRT_SERVICE_THREAD) << __FUNCTION__ << "Changing service pointer from thread"
- << QThread::currentThread();
-
- pointer->setState(QLowEnergyService::DiscoveringServices);
- ComPtr<IGattDeviceService2> deviceService2;
- HRESULT hr = deviceService.As(&deviceService2);
- Q_ASSERT_SUCCEEDED(hr);
+ if (!pointer) {
+ qCDebug(QT_BT_WINDOWS) << "Device was disconnected while doing service discovery";
+ return;
+ }
+ qCDebug(QT_BT_WINDOWS_SERVICE_THREAD) << __FUNCTION__ << "Changing service pointer from thread"
+ << QThread::currentThread();
+ pointer->setState(QLowEnergyService::RemoteServiceDiscovering);
+ ComPtr<IGattDeviceService3> deviceService3;
+ HRESULT hr = deviceService.As(&deviceService3);
+ if (FAILED(hr)) {
+ reactOnDiscoveryError(pointer, QStringLiteral("Could not cast service: %1").arg(hr));
+ return;
+ }
+ ComPtr<IAsyncOperation<GattDeviceServicesResult *>> op;
+ hr = deviceService3->GetIncludedServicesAsync(&op);
+ if (FAILED(hr)) {
+ reactOnDiscoveryError(pointer,
+ QStringLiteral("Could not obtain included service list: %1").arg(hr));
+ return;
+ }
+ ComPtr<IGattDeviceServicesResult> result;
+ hr = QWinRTFunctions::await(op, result.GetAddressOf());
+ if (FAILED(hr)) {
+ reactOnDiscoveryError(pointer,
+ QStringLiteral("Could not await service operation: %1").arg(hr));
+ return;
+ }
+ GattCommunicationStatus status;
+ hr = result->get_Status(&status);
+ if (FAILED(hr) || status != GattCommunicationStatus_Success) {
+ reactOnDiscoveryError(pointer,
+ QStringLiteral("Obtaining list of included services failed: %1").
+ arg(hr));
+ return;
+ }
ComPtr<IVectorView<GattDeviceService *>> deviceServices;
- hr = deviceService2->GetAllIncludedServices(&deviceServices);
- if (FAILED(hr)) { // ERROR_ACCESS_DISABLED_BY_POLICY
- qCDebug(QT_BT_WINRT) << "Could not obtain included services list for" << service;
- pointer->setError(QLowEnergyService::UnknownError);
- pointer->setState(QLowEnergyService::InvalidService);
+ hr = result->get_Services(&deviceServices);
+ if (FAILED(hr)) {
+ reactOnDiscoveryError(pointer,
+ QStringLiteral("Could not obtain service list from result: %1").
+ arg(hr));
return;
}
uint serviceCount;
hr = deviceServices->get_Size(&serviceCount);
- Q_ASSERT_SUCCEEDED(hr);
+ if (FAILED(hr)) {
+ reactOnDiscoveryError(pointer,
+ QStringLiteral("Could not obtain included service list's size: %1").
+ arg(hr));
+ return;
+ }
for (uint i = 0; i < serviceCount; ++i) {
ComPtr<IGattDeviceService> includedService;
hr = deviceServices->GetAt(i, &includedService);
- Q_ASSERT_SUCCEEDED(hr);
+ WARN_AND_CONTINUE_IF_FAILED(hr, "Could not obtain service from list")
GUID guuid;
hr = includedService->get_Uuid(&guuid);
- Q_ASSERT_SUCCEEDED(hr);
+ WARN_AND_CONTINUE_IF_FAILED(hr, "Could not obtain service Uuid")
const QBluetoothUuid service(guuid);
if (service.isNull()) {
- qCDebug(QT_BT_WINRT) << "Could not find service";
- return;
+ qCDebug(QT_BT_WINDOWS) << "Could not find service";
+ continue;
}
pointer->includedServices.append(service);
@@ -629,42 +1304,46 @@ void QLowEnergyControllerPrivateWinRT::discoverServiceDetails(const QBluetoothUu
otherService->type |= QLowEnergyService::IncludedService;
}
- QWinRTLowEnergyServiceHandler *worker = new QWinRTLowEnergyServiceHandler(service, deviceService2);
+ QWinRTLowEnergyServiceHandler *worker =
+ new QWinRTLowEnergyServiceHandler(service, deviceService3, mode);
+ m_requestDetailsServiceUuids.insert(service);
QThread *thread = new QThread;
worker->moveToThread(thread);
connect(thread, &QThread::started, worker, &QWinRTLowEnergyServiceHandler::obtainCharList);
- connect(thread, &QThread::finished, thread, &QObject::deleteLater);
connect(thread, &QThread::finished, worker, &QObject::deleteLater);
- connect(worker, &QWinRTLowEnergyServiceHandler::charListObtained,
- [this, thread](const QBluetoothUuid &service, QHash<QLowEnergyHandle, QLowEnergyServicePrivate::CharData> charList
- , QVector<QBluetoothUuid> indicateChars
- , QLowEnergyHandle startHandle, QLowEnergyHandle endHandle) {
+ connect(worker, &QObject::destroyed, thread, &QObject::deleteLater);
+ connect(this, &QLowEnergyControllerPrivateWinRT::abortConnection,
+ worker, &QWinRTLowEnergyServiceHandler::setAbortRequested);
+ connect(worker, &QWinRTLowEnergyServiceHandler::errorOccured,
+ this, &QLowEnergyControllerPrivateWinRT::handleServiceHandlerError);
+ connect(worker, &QWinRTLowEnergyServiceHandler::charListObtained, this,
+ [this](const QBluetoothUuid &service, QHash<QLowEnergyHandle,
+ QLowEnergyServicePrivate::CharData> charList, QList<QBluetoothUuid> indicateChars,
+ QLowEnergyHandle startHandle, QLowEnergyHandle endHandle) {
if (!serviceList.contains(service)) {
- qCWarning(QT_BT_WINRT) << "Discovery done of unknown service:"
- << service.toString();
+ qCWarning(QT_BT_WINDOWS)
+ << "Discovery complete for unknown service:" << service.toString();
return;
}
+ m_requestDetailsServiceUuids.remove(service);
QSharedPointer<QLowEnergyServicePrivate> pointer = serviceList.value(service);
pointer->startHandle = startHandle;
pointer->endHandle = endHandle;
pointer->characteristicList = charList;
- HRESULT hr;
- hr = QEventDispatcherWinRT::runOnXamlThread([indicateChars, service, this]() {
- for (const QBluetoothUuid &indicateChar : qAsConst(indicateChars))
- registerForValueChanges(service, indicateChar);
- return S_OK;
- });
- Q_ASSERT_SUCCEEDED(hr);
+ for (const QBluetoothUuid &indicateChar : std::as_const(indicateChars))
+ registerForValueChanges(service, indicateChar);
- pointer->setState(QLowEnergyService::ServiceDiscovered);
- thread->exit(0);
+ pointer->setState(QLowEnergyService::RemoteServiceDiscovered);
});
thread->start();
}
-void QLowEnergyControllerPrivateWinRT::startAdvertising(const QLowEnergyAdvertisingParameters &, const QLowEnergyAdvertisingData &, const QLowEnergyAdvertisingData &)
+void QLowEnergyControllerPrivateWinRT::startAdvertising(
+ const QLowEnergyAdvertisingParameters &,
+ const QLowEnergyAdvertisingData &,
+ const QLowEnergyAdvertisingData &)
{
setError(QLowEnergyController::AdvertisingError);
Q_UNIMPLEMENTED();
@@ -680,11 +1359,12 @@ void QLowEnergyControllerPrivateWinRT::requestConnectionUpdate(const QLowEnergyC
Q_UNIMPLEMENTED();
}
-void QLowEnergyControllerPrivateWinRT::readCharacteristic(const QSharedPointer<QLowEnergyServicePrivate> service,
- const QLowEnergyHandle charHandle)
+void QLowEnergyControllerPrivateWinRT::readCharacteristic(
+ const QSharedPointer<QLowEnergyServicePrivate> service,
+ const QLowEnergyHandle charHandle)
{
- qCDebug(QT_BT_WINRT) << __FUNCTION__ << service << charHandle;
- qCDebug(QT_BT_WINRT_SERVICE_THREAD) << __FUNCTION__ << "Changing service pointer from thread"
+ qCDebug(QT_BT_WINDOWS) << __FUNCTION__ << service << charHandle;
+ qCDebug(QT_BT_WINDOWS_SERVICE_THREAD) << __FUNCTION__ << "Changing service pointer from thread"
<< QThread::currentThread();
Q_ASSERT(!service.isNull());
if (role == QLowEnergyController::PeripheralRole) {
@@ -694,64 +1374,71 @@ void QLowEnergyControllerPrivateWinRT::readCharacteristic(const QSharedPointer<Q
}
if (!service->characteristicList.contains(charHandle)) {
- qCDebug(QT_BT_WINRT) << charHandle << "could not be found in service" << service->uuid;
+ qCDebug(QT_BT_WINDOWS) << charHandle << "could not be found in service" << service->uuid;
service->setError(QLowEnergyService::CharacteristicReadError);
return;
}
- HRESULT hr;
- hr = QEventDispatcherWinRT::runOnXamlThread([charHandle, service, this]() {
- const QLowEnergyServicePrivate::CharData charData = service->characteristicList.value(charHandle);
- if (!(charData.properties & QLowEnergyCharacteristic::Read))
- qCDebug(QT_BT_WINRT) << "Read flag is not set for characteristic" << charData.uuid;
-
- ComPtr<IGattCharacteristic> characteristic = getNativeCharacteristic(service->uuid, charData.uuid);
- if (!characteristic) {
- qCDebug(QT_BT_WINRT) << "Could not obtain native characteristic" << charData.uuid
- << "from service" << service->uuid;
+ const auto charData = service->characteristicList.value(charHandle);
+ if (!(charData.properties & QLowEnergyCharacteristic::Read))
+ qCDebug(QT_BT_WINDOWS) << "Read flag is not set for characteristic" << charData.uuid;
+
+ auto characteristicCallback = [charHandle, service, this](
+ ComPtr<IGattCharacteristic> characteristic) {
+ readCharacteristicHelper(service, charHandle, characteristic);
+ };
+
+ HRESULT hr = getNativeCharacteristic(service->uuid, charData.uuid, characteristicCallback);
+ if (FAILED(hr)) {
+ qCDebug(QT_BT_WINDOWS) << "Could not obtain native characteristic" << charData.uuid
+ << "from service" << service->uuid;
+ service->setError(QLowEnergyService::CharacteristicReadError);
+ }
+}
+
+void QLowEnergyControllerPrivateWinRT::readCharacteristicHelper(
+ const QSharedPointer<QLowEnergyServicePrivate> service,
+ const QLowEnergyHandle charHandle,
+ GattCharacteristicComPtr characteristic)
+{
+ ComPtr<IAsyncOperation<GattReadResult *>> readOp;
+ HRESULT hr = characteristic->ReadValueWithCacheModeAsync(BluetoothCacheMode_Uncached, &readOp);
+ CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not read characteristic",
+ service, QLowEnergyService::CharacteristicReadError, return)
+ auto readCompletedLambda = [charHandle, service]
+ (IAsyncOperation<GattReadResult*> *op, AsyncStatus status)
+ {
+ if (status == AsyncStatus::Canceled || status == AsyncStatus::Error) {
+ qCDebug(QT_BT_WINDOWS) << "Characteristic" << charHandle << "read operation failed.";
service->setError(QLowEnergyService::CharacteristicReadError);
return S_OK;
}
- ComPtr<IAsyncOperation<GattReadResult*>> readOp;
- HRESULT hr = characteristic->ReadValueWithCacheModeAsync(BluetoothCacheMode_Uncached, &readOp);
- Q_ASSERT_SUCCEEDED(hr);
- auto readCompletedLambda = [charData, charHandle, service]
- (IAsyncOperation<GattReadResult*> *op, AsyncStatus status)
- {
- if (status == AsyncStatus::Canceled || status == AsyncStatus::Error) {
- qCDebug(QT_BT_WINRT) << "Characteristic" << charHandle << "read operation failed.";
- service->setError(QLowEnergyService::CharacteristicReadError);
- return S_OK;
- }
- ComPtr<IGattReadResult> characteristicValue;
- HRESULT hr;
- hr = op->GetResults(&characteristicValue);
- if (FAILED(hr)) {
- qCDebug(QT_BT_WINRT) << "Could not obtain result for characteristic" << charHandle;
- service->setError(QLowEnergyService::CharacteristicReadError);
- return S_OK;
- }
-
- const QByteArray value = byteArrayFromGattResult(characteristicValue);
- QLowEnergyServicePrivate::CharData charData = service->characteristicList.value(charHandle);
- charData.value = value;
- service->characteristicList.insert(charHandle, charData);
- emit service->characteristicRead(QLowEnergyCharacteristic(service, charHandle), value);
- return S_OK;
- };
- hr = readOp->put_Completed(Callback<IAsyncOperationCompletedHandler<GattReadResult *>>(readCompletedLambda).Get());
- Q_ASSERT_SUCCEEDED(hr);
+ ComPtr<IGattReadResult> characteristicValue;
+ HRESULT hr;
+ hr = op->GetResults(&characteristicValue);
+ CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not obtain result for characteristic", service,
+ QLowEnergyService::CharacteristicReadError, return S_OK)
+
+ const QByteArray value = byteArrayFromGattResult(characteristicValue);
+ auto charData = service->characteristicList.value(charHandle);
+ charData.value = value;
+ service->characteristicList.insert(charHandle, charData);
+ emit service->characteristicRead(QLowEnergyCharacteristic(service, charHandle), value);
return S_OK;
- });
- Q_ASSERT_SUCCEEDED(hr);
+ };
+ hr = readOp->put_Completed(Callback<IAsyncOperationCompletedHandler<GattReadResult *>>(
+ readCompletedLambda).Get());
+ CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not register characteristic read callback",
+ service, QLowEnergyService::CharacteristicReadError, return)
}
-void QLowEnergyControllerPrivateWinRT::readDescriptor(const QSharedPointer<QLowEnergyServicePrivate> service,
- const QLowEnergyHandle charHandle,
- const QLowEnergyHandle descHandle)
+void QLowEnergyControllerPrivateWinRT::readDescriptor(
+ const QSharedPointer<QLowEnergyServicePrivate> service,
+ const QLowEnergyHandle charHandle,
+ const QLowEnergyHandle descHandle)
{
- qCDebug(QT_BT_WINRT) << __FUNCTION__ << service << charHandle << descHandle;
- qCDebug(QT_BT_WINRT_SERVICE_THREAD) << __FUNCTION__ << "Changing service pointer from thread"
+ qCDebug(QT_BT_WINDOWS) << __FUNCTION__ << service << charHandle << descHandle;
+ qCDebug(QT_BT_WINDOWS_SERVICE_THREAD) << __FUNCTION__ << "Changing service pointer from thread"
<< QThread::currentThread();
Q_ASSERT(!service.isNull());
if (role == QLowEnergyController::PeripheralRole) {
@@ -761,135 +1448,186 @@ void QLowEnergyControllerPrivateWinRT::readDescriptor(const QSharedPointer<QLowE
}
if (!service->characteristicList.contains(charHandle)) {
- qCDebug(QT_BT_WINRT) << "Descriptor" << descHandle << "in characteristic" << charHandle
+ qCDebug(QT_BT_WINDOWS) << "Descriptor" << descHandle << "in characteristic" << charHandle
<< "cannot be found in service" << service->uuid;
service->setError(QLowEnergyService::DescriptorReadError);
return;
}
- HRESULT hr;
- hr = QEventDispatcherWinRT::runOnXamlThread([charHandle, descHandle, service, this]() {
- const QLowEnergyServicePrivate::CharData charData = service->characteristicList.value(charHandle);
- ComPtr<IGattCharacteristic> characteristic = getNativeCharacteristic(service->uuid, charData.uuid);
- if (!characteristic) {
- qCDebug(QT_BT_WINRT) << "Could not obtain native characteristic" << charData.uuid
- << "from service" << service->uuid;
- service->setError(QLowEnergyService::DescriptorReadError);
- return S_OK;
- }
+ const auto charData = service->characteristicList.value(charHandle);
- // Get native descriptor
- if (!charData.descriptorList.contains(descHandle))
- qCDebug(QT_BT_WINRT) << "Descriptor" << descHandle << "cannot be found in characteristic" << charHandle;
- const QLowEnergyServicePrivate::DescData descData = charData.descriptorList.value(descHandle);
- const QBluetoothUuid descUuid = descData.uuid;
- if (descUuid == QBluetoothUuid(QBluetoothUuid::ClientCharacteristicConfiguration)) {
- ComPtr<IAsyncOperation<ClientCharConfigDescriptorResult *>> readOp;
- HRESULT hr = characteristic->ReadClientCharacteristicConfigurationDescriptorAsync(&readOp);
- Q_ASSERT_SUCCEEDED(hr);
- auto readCompletedLambda = [charHandle, descHandle, service]
- (IAsyncOperation<ClientCharConfigDescriptorResult *> *op, AsyncStatus status)
- {
- if (status == AsyncStatus::Canceled || status == AsyncStatus::Error) {
- qCDebug(QT_BT_WINRT) << "Descriptor" << descHandle << "read operation failed";
- service->setError(QLowEnergyService::DescriptorReadError);
- return S_OK;
- }
- ComPtr<IClientCharConfigDescriptorResult> iValue;
- HRESULT hr;
- hr = op->GetResults(&iValue);
- if (FAILED(hr)) {
- qCDebug(QT_BT_WINRT) << "Could not obtain result for descriptor" << descHandle;
- service->setError(QLowEnergyService::DescriptorReadError);
- return S_OK;
- }
- GattClientCharacteristicConfigurationDescriptorValue value;
- hr = iValue->get_ClientCharacteristicConfigurationDescriptor(&value);
- if (FAILED(hr)) {
- qCDebug(QT_BT_WINRT) << "Could not obtain value for descriptor" << descHandle;
- service->setError(QLowEnergyService::DescriptorReadError);
- return S_OK;
- }
- quint16 result = 0;
- bool correct = false;
- if (value & GattClientCharacteristicConfigurationDescriptorValue_Indicate) {
- result |= QLowEnergyCharacteristic::Indicate;
- correct = true;
- }
- if (value & GattClientCharacteristicConfigurationDescriptorValue_Notify) {
- result |= QLowEnergyCharacteristic::Notify;
- correct = true;
- }
- if (value == GattClientCharacteristicConfigurationDescriptorValue_None)
- correct = true;
- if (!correct) {
- qCDebug(QT_BT_WINRT) << "Descriptor" << descHandle
- << "read operation failed. Obtained unexpected value.";
- service->setError(QLowEnergyService::DescriptorReadError);
- return S_OK;
- }
- QLowEnergyServicePrivate::DescData descData;
- descData.uuid = QBluetoothUuid::ClientCharacteristicConfiguration;
- descData.value = QByteArray(2, Qt::Uninitialized);
- qToLittleEndian(result, descData.value.data());
- service->characteristicList[charHandle].descriptorList[descHandle] = descData;
- emit service->descriptorRead(QLowEnergyDescriptor(service, charHandle, descHandle),
- descData.value);
+ auto characteristicCallback = [charHandle, descHandle, service, this](
+ ComPtr<IGattCharacteristic> characteristic) {
+ readDescriptorHelper(service, charHandle, descHandle, characteristic);
+ };
+
+ HRESULT hr = getNativeCharacteristic(service->uuid, charData.uuid, characteristicCallback);
+ if (FAILED(hr)) {
+ qCDebug(QT_BT_WINDOWS) << "Could not obtain native characteristic" << charData.uuid
+ << "from service" << service->uuid;
+ service->setError(QLowEnergyService::DescriptorReadError);
+ }
+}
+
+void QLowEnergyControllerPrivateWinRT::readDescriptorHelper(
+ const QSharedPointer<QLowEnergyServicePrivate> service,
+ const QLowEnergyHandle charHandle,
+ const QLowEnergyHandle descHandle,
+ GattCharacteristicComPtr characteristic)
+{
+ // Get native descriptor
+ const auto charData = service->characteristicList.value(charHandle);
+ if (!charData.descriptorList.contains(descHandle)) {
+ qCDebug(QT_BT_WINDOWS) << "Descriptor" << descHandle << "cannot be found in characteristic"
+ << charHandle;
+ }
+ const auto descData = charData.descriptorList.value(descHandle);
+ const QBluetoothUuid descUuid = descData.uuid;
+ if (descUuid ==
+ QBluetoothUuid(QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration)) {
+ ComPtr<IAsyncOperation<ClientCharConfigDescriptorResult *>> readOp;
+ HRESULT hr = characteristic->ReadClientCharacteristicConfigurationDescriptorAsync(&readOp);
+ CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not read client characteristic configuration",
+ service, QLowEnergyService::DescriptorReadError, return)
+ auto readCompletedLambda = [charHandle, descHandle, service]
+ (IAsyncOperation<ClientCharConfigDescriptorResult *> *op, AsyncStatus status)
+ {
+ if (status == AsyncStatus::Canceled || status == AsyncStatus::Error) {
+ qCDebug(QT_BT_WINDOWS) << "Descriptor" << descHandle << "read operation failed";
+ service->setError(QLowEnergyService::DescriptorReadError);
return S_OK;
- };
- hr = readOp->put_Completed(Callback<IAsyncOperationCompletedHandler<ClientCharConfigDescriptorResult *>>(readCompletedLambda).Get());
- Q_ASSERT_SUCCEEDED(hr);
- return S_OK;
- } else {
- ComPtr<IVectorView<GattDescriptor *>> descriptors;
- HRESULT hr = characteristic->GetDescriptors(descData.uuid, &descriptors);
- Q_ASSERT_SUCCEEDED(hr);
- ComPtr<IGattDescriptor> descriptor;
- hr = descriptors->GetAt(0, &descriptor);
- Q_ASSERT_SUCCEEDED(hr);
- ComPtr<IAsyncOperation<GattReadResult*>> readOp;
- hr = descriptor->ReadValueWithCacheModeAsync(BluetoothCacheMode_Uncached, &readOp);
- Q_ASSERT_SUCCEEDED(hr);
- auto readCompletedLambda = [charHandle, descHandle, descUuid, service]
- (IAsyncOperation<GattReadResult*> *op, AsyncStatus status)
- {
- if (status == AsyncStatus::Canceled || status == AsyncStatus::Error) {
- qCDebug(QT_BT_WINRT) << "Descriptor" << descHandle << "read operation failed";
- service->setError(QLowEnergyService::DescriptorReadError);
- return S_OK;
- }
- ComPtr<IGattReadResult> descriptorValue;
- HRESULT hr;
- hr = op->GetResults(&descriptorValue);
- if (FAILED(hr)) {
- qCDebug(QT_BT_WINRT) << "Could not obtain result for descriptor" << descHandle;
- service->setError(QLowEnergyService::DescriptorReadError);
- return S_OK;
- }
- QLowEnergyServicePrivate::DescData descData;
- if (descUuid == QBluetoothUuid::CharacteristicUserDescription)
- descData.value = byteArrayFromGattResult(descriptorValue, true);
- else
- descData.value = byteArrayFromGattResult(descriptorValue);
- service->characteristicList[charHandle].descriptorList[descHandle] = descData;
- emit service->descriptorRead(QLowEnergyDescriptor(service, charHandle, descHandle),
- descData.value);
+ }
+ ComPtr<IClientCharConfigDescriptorResult> iValue;
+ HRESULT hr;
+ hr = op->GetResults(&iValue);
+ CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not obtain result for descriptor", service,
+ QLowEnergyService::DescriptorReadError, return S_OK)
+ GattClientCharacteristicConfigurationDescriptorValue value;
+ hr = iValue->get_ClientCharacteristicConfigurationDescriptor(&value);
+ CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not obtain value for descriptor", service,
+ QLowEnergyService::DescriptorReadError, return S_OK)
+ quint16 result = 0;
+ bool correct = false;
+ if (value & GattClientCharacteristicConfigurationDescriptorValue_Indicate) {
+ result |= QLowEnergyCharacteristic::Indicate;
+ correct = true;
+ }
+ if (value & GattClientCharacteristicConfigurationDescriptorValue_Notify) {
+ result |= QLowEnergyCharacteristic::Notify;
+ correct = true;
+ }
+ if (value == GattClientCharacteristicConfigurationDescriptorValue_None)
+ correct = true;
+ if (!correct) {
+ qCDebug(QT_BT_WINDOWS) << "Descriptor" << descHandle
+ << "read operation failed. Obtained unexpected value.";
+ service->setError(QLowEnergyService::DescriptorReadError);
return S_OK;
- };
- hr = readOp->put_Completed(Callback<IAsyncOperationCompletedHandler<GattReadResult *>>(readCompletedLambda).Get());
+ }
+ QLowEnergyServicePrivate::DescData descData;
+ descData.uuid = QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration;
+ descData.value = QByteArray(2, Qt::Uninitialized);
+ qToLittleEndian(result, descData.value.data());
+ service->characteristicList[charHandle].descriptorList[descHandle] = descData;
+ emit service->descriptorRead(QLowEnergyDescriptor(service, charHandle, descHandle),
+ descData.value);
+ return S_OK;
+ };
+ hr = readOp->put_Completed(
+ Callback<IAsyncOperationCompletedHandler<ClientCharConfigDescriptorResult *>>(
+ readCompletedLambda).Get());
+ CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not register descriptor read callback",
+ service, QLowEnergyService::DescriptorReadError, return)
+ return;
+ }
+
+ ComPtr<IGattCharacteristic3> characteristic3;
+ HRESULT hr = characteristic.As(&characteristic3);
+ CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not cast characteristic",
+ service, QLowEnergyService::DescriptorReadError, return)
+ ComPtr<IAsyncOperation<GattDescriptorsResult *>> op;
+ hr = characteristic3->GetDescriptorsForUuidAsync(descData.uuid, &op);
+ CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not obtain descriptor for uuid",
+ service, QLowEnergyService::DescriptorReadError, return)
+ ComPtr<IGattDescriptorsResult> result;
+ hr = QWinRTFunctions::await(op, result.GetAddressOf(),
+ QWinRTFunctions::ProcessMainThreadEvents, 5000);
+ CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not await descritpor read result",
+ service, QLowEnergyService::DescriptorReadError, return)
+
+ GattCommunicationStatus commStatus;
+ hr = result->get_Status(&commStatus);
+ if (FAILED(hr) || commStatus != GattCommunicationStatus_Success) {
+ qErrnoWarning("Could not obtain list of descriptors");
+ service->setError(QLowEnergyService::DescriptorReadError);
+ return;
+ }
+
+ ComPtr<IVectorView<GattDescriptor *>> descriptors;
+ hr = result->get_Descriptors(&descriptors);
+ CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not obtain descriptor list",
+ service, QLowEnergyService::DescriptorReadError, return)
+ uint size;
+ hr = descriptors->get_Size(&size);
+ CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not await descritpor list's size",
+ service, QLowEnergyService::DescriptorReadError, return)
+ if (size == 0) {
+ qCWarning(QT_BT_WINDOWS) << "No descriptor with uuid" << descData.uuid << "was found.";
+ service->setError(QLowEnergyService::DescriptorReadError);
+ return;
+ } else if (size > 1) {
+ qCWarning(QT_BT_WINDOWS) << "There is more than 1 descriptor with uuid" << descData.uuid;
+ }
+
+ ComPtr<IGattDescriptor> descriptor;
+ hr = descriptors->GetAt(0, &descriptor);
+ CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not obtain descritpor from list",
+ service, QLowEnergyService::DescriptorReadError, return)
+ ComPtr<IAsyncOperation<GattReadResult*>> readOp;
+ hr = descriptor->ReadValueWithCacheModeAsync(BluetoothCacheMode_Uncached, &readOp);
+ CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not read descriptor value",
+ service, QLowEnergyService::DescriptorReadError, return)
+ auto readCompletedLambda = [charHandle, descHandle, descUuid, service]
+ (IAsyncOperation<GattReadResult*> *op, AsyncStatus status)
+ {
+ if (status == AsyncStatus::Canceled || status == AsyncStatus::Error) {
+ qCDebug(QT_BT_WINDOWS) << "Descriptor" << descHandle << "read operation failed";
+ service->setError(QLowEnergyService::DescriptorReadError);
return S_OK;
}
- });
- Q_ASSERT_SUCCEEDED(hr);
+ ComPtr<IGattReadResult> descriptorValue;
+ HRESULT hr;
+ hr = op->GetResults(&descriptorValue);
+ if (FAILED(hr)) {
+ qCDebug(QT_BT_WINDOWS) << "Could not obtain result for descriptor" << descHandle;
+ service->setError(QLowEnergyService::DescriptorReadError);
+ return S_OK;
+ }
+ QLowEnergyServicePrivate::DescData descData;
+ descData.uuid = descUuid;
+ if (descData.uuid == QBluetoothUuid::DescriptorType::CharacteristicUserDescription)
+ descData.value = byteArrayFromGattResult(descriptorValue, true);
+ else
+ descData.value = byteArrayFromGattResult(descriptorValue);
+ service->characteristicList[charHandle].descriptorList[descHandle] = descData;
+ emit service->descriptorRead(QLowEnergyDescriptor(service, charHandle, descHandle),
+ descData.value);
+ return S_OK;
+ };
+ hr = readOp->put_Completed(Callback<IAsyncOperationCompletedHandler<GattReadResult *>>(
+ readCompletedLambda).Get());
+ CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not register descriptor read callback",
+ service, QLowEnergyService::DescriptorReadError, return)
}
-void QLowEnergyControllerPrivateWinRT::writeCharacteristic(const QSharedPointer<QLowEnergyServicePrivate> service,
+void QLowEnergyControllerPrivateWinRT::writeCharacteristic(
+ const QSharedPointer<QLowEnergyServicePrivate> service,
const QLowEnergyHandle charHandle,
const QByteArray &newValue,
QLowEnergyService::WriteMode mode)
{
- qCDebug(QT_BT_WINRT) << __FUNCTION__ << service << charHandle << newValue << mode;
- qCDebug(QT_BT_WINRT_SERVICE_THREAD) << __FUNCTION__ << "Changing service pointer from thread"
+ qCDebug(QT_BT_WINDOWS) << __FUNCTION__ << service << charHandle << newValue << mode;
+ qCDebug(QT_BT_WINDOWS_SERVICE_THREAD) << __FUNCTION__ << "Changing service pointer from thread"
<< QThread::currentThread();
Q_ASSERT(!service.isNull());
if (role == QLowEnergyController::PeripheralRole) {
@@ -898,80 +1636,108 @@ void QLowEnergyControllerPrivateWinRT::writeCharacteristic(const QSharedPointer<
return;
}
if (!service->characteristicList.contains(charHandle)) {
- qCDebug(QT_BT_WINRT) << "Characteristic" << charHandle << "cannot be found in service" << service->uuid;
+ qCDebug(QT_BT_WINDOWS) << "Characteristic" << charHandle << "cannot be found in service"
+ << service->uuid;
service->setError(QLowEnergyService::CharacteristicWriteError);
return;
}
QLowEnergyServicePrivate::CharData charData = service->characteristicList.value(charHandle);
const bool writeWithResponse = mode == QLowEnergyService::WriteWithResponse;
- if (!(charData.properties & (writeWithResponse ? QLowEnergyCharacteristic::Write : QLowEnergyCharacteristic::WriteNoResponse)))
- qCDebug(QT_BT_WINRT) << "Write flag is not set for characteristic" << charHandle;
+ if (!(charData.properties & (writeWithResponse ? QLowEnergyCharacteristic::Write
+ : QLowEnergyCharacteristic::WriteNoResponse)))
+ qCDebug(QT_BT_WINDOWS) << "Write flag is not set for characteristic" << charHandle;
+
+ auto characteristicCallback = [charHandle, service, newValue, writeWithResponse, this](
+ ComPtr<IGattCharacteristic> characteristic) {
+ writeCharacteristicHelper(service, charHandle, newValue, writeWithResponse,
+ characteristic);
+ };
+
+ HRESULT hr = getNativeCharacteristic(service->uuid, charData.uuid, characteristicCallback);
+ if (FAILED(hr)) {
+ qCDebug(QT_BT_WINDOWS) << "Could not obtain native characteristic" << charData.uuid
+ << "from service" << service->uuid;
+ service->setError(QLowEnergyService::CharacteristicWriteError);
+ }
+}
- HRESULT hr;
- hr = QEventDispatcherWinRT::runOnXamlThread([charData, charHandle, this, service, newValue, writeWithResponse]() {
- ComPtr<IGattCharacteristic> characteristic = getNativeCharacteristic(service->uuid, charData.uuid);
- if (!characteristic) {
- qCDebug(QT_BT_WINRT) << "Could not obtain native characteristic" << charData.uuid
- << "from service" << service->uuid;
+void QLowEnergyControllerPrivateWinRT::writeCharacteristicHelper(
+ const QSharedPointer<QLowEnergyServicePrivate> service,
+ const QLowEnergyHandle charHandle, const QByteArray &newValue,
+ bool writeWithResponse, GattCharacteristicComPtr characteristic)
+{
+ ComPtr<ABI::Windows::Storage::Streams::IBufferFactory> bufferFactory;
+ HRESULT hr = GetActivationFactory(
+ HStringReference(RuntimeClass_Windows_Storage_Streams_Buffer).Get(),
+ &bufferFactory);
+ CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not obtain buffer factory",
+ service, QLowEnergyService::CharacteristicWriteError, return)
+ ComPtr<ABI::Windows::Storage::Streams::IBuffer> buffer;
+ const quint32 length = quint32(newValue.length());
+ hr = bufferFactory->Create(length, &buffer);
+ CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not create buffer",
+ service, QLowEnergyService::CharacteristicWriteError, return)
+ hr = buffer->put_Length(length);
+ CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not set buffer length",
+ service, QLowEnergyService::CharacteristicWriteError, return)
+ ComPtr<Windows::Storage::Streams::IBufferByteAccess> byteAccess;
+ hr = buffer.As(&byteAccess);
+ CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not cast buffer",
+ service, QLowEnergyService::CharacteristicWriteError, return)
+ byte *bytes;
+ hr = byteAccess->Buffer(&bytes);
+ CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not set buffer",
+ service, QLowEnergyService::CharacteristicWriteError, return)
+ memcpy(bytes, newValue, length);
+ ComPtr<IAsyncOperation<GattCommunicationStatus>> writeOp;
+ GattWriteOption option = writeWithResponse ? GattWriteOption_WriteWithResponse
+ : GattWriteOption_WriteWithoutResponse;
+ hr = characteristic->WriteValueWithOptionAsync(buffer.Get(), option, &writeOp);
+ CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could write characteristic",
+ service, QLowEnergyService::CharacteristicWriteError, return)
+ const auto charData = service->characteristicList.value(charHandle);
+ QPointer<QLowEnergyControllerPrivateWinRT> thisPtr(this);
+ auto writeCompletedLambda =
+ [charData, charHandle, newValue, service, writeWithResponse, thisPtr]
+ (IAsyncOperation<GattCommunicationStatus> *op, AsyncStatus status)
+ {
+ if (status == AsyncStatus::Canceled || status == AsyncStatus::Error) {
+ qCDebug(QT_BT_WINDOWS) << "Characteristic" << charHandle << "write operation failed";
service->setError(QLowEnergyService::CharacteristicWriteError);
return S_OK;
}
- ComPtr<ABI::Windows::Storage::Streams::IBufferFactory> bufferFactory;
- HRESULT hr = GetActivationFactory(HStringReference(RuntimeClass_Windows_Storage_Streams_Buffer).Get(), &bufferFactory);
- Q_ASSERT_SUCCEEDED(hr);
- ComPtr<ABI::Windows::Storage::Streams::IBuffer> buffer;
- const int length = newValue.length();
- hr = bufferFactory->Create(length, &buffer);
- Q_ASSERT_SUCCEEDED(hr);
- hr = buffer->put_Length(length);
- Q_ASSERT_SUCCEEDED(hr);
- ComPtr<Windows::Storage::Streams::IBufferByteAccess> byteAccess;
- hr = buffer.As(&byteAccess);
- Q_ASSERT_SUCCEEDED(hr);
- byte *bytes;
- hr = byteAccess->Buffer(&bytes);
- Q_ASSERT_SUCCEEDED(hr);
- memcpy(bytes, newValue, length);
- ComPtr<IAsyncOperation<GattCommunicationStatus>> writeOp;
- GattWriteOption option = writeWithResponse ? GattWriteOption_WriteWithResponse : GattWriteOption_WriteWithoutResponse;
- hr = characteristic->WriteValueWithOptionAsync(buffer.Get(), option, &writeOp);
- Q_ASSERT_SUCCEEDED(hr);
- auto writeCompletedLambda =[charData, charHandle, newValue, service, writeWithResponse, this]
- (IAsyncOperation<GattCommunicationStatus> *op, AsyncStatus status)
- {
- if (status == AsyncStatus::Canceled || status == AsyncStatus::Error) {
- qCDebug(QT_BT_WINRT) << "Characteristic" << charHandle << "write operation failed";
- service->setError(QLowEnergyService::CharacteristicWriteError);
- return S_OK;
- }
- GattCommunicationStatus result;
- HRESULT hr;
- hr = op->GetResults(&result);
- if (hr == E_BLUETOOTH_ATT_INVALID_ATTRIBUTE_VALUE_LENGTH) {
- qCDebug(QT_BT_WINRT) << "Characteristic" << charHandle << "write operation was tried with invalid value length";
- service->setError(QLowEnergyService::CharacteristicWriteError);
- return S_OK;
- }
- Q_ASSERT_SUCCEEDED(hr);
- if (result != GattCommunicationStatus_Success) {
- qCDebug(QT_BT_WINRT) << "Characteristic" << charHandle << "write operation failed";
- service->setError(QLowEnergyService::CharacteristicWriteError);
- return S_OK;
- }
- // only update cache when property is readable. Otherwise it remains
- // empty.
- if (charData.properties & QLowEnergyCharacteristic::Read)
- updateValueOfCharacteristic(charHandle, newValue, false);
- if (writeWithResponse)
- emit service->characteristicWritten(QLowEnergyCharacteristic(service, charHandle), newValue);
+ GattCommunicationStatus result;
+ HRESULT hr;
+ hr = op->GetResults(&result);
+ if (hr == E_BLUETOOTH_ATT_INVALID_ATTRIBUTE_VALUE_LENGTH) {
+ qCDebug(QT_BT_WINDOWS) << "Characteristic" << charHandle
+ << "write operation was tried with invalid value length";
+ service->setError(QLowEnergyService::CharacteristicWriteError);
return S_OK;
- };
- hr = writeOp->put_Completed(Callback<IAsyncOperationCompletedHandler<GattCommunicationStatus>>(writeCompletedLambda).Get());
- Q_ASSERT_SUCCEEDED(hr);
+ }
+ CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not obtain characteristic write result", service,
+ QLowEnergyService::CharacteristicWriteError, return S_OK)
+ if (result != GattCommunicationStatus_Success) {
+ qCDebug(QT_BT_WINDOWS) << "Characteristic" << charHandle << "write operation failed";
+ service->setError(QLowEnergyService::CharacteristicWriteError);
+ return S_OK;
+ }
+ // only update cache when property is readable. Otherwise it remains
+ // empty.
+ if (thisPtr && charData.properties & QLowEnergyCharacteristic::Read)
+ thisPtr->updateValueOfCharacteristic(charHandle, newValue, false);
+ if (writeWithResponse) {
+ emit service->characteristicWritten(QLowEnergyCharacteristic(service, charHandle),
+ newValue);
+ }
return S_OK;
- });
- Q_ASSERT_SUCCEEDED(hr);
+ };
+ hr = writeOp->put_Completed(
+ Callback<IAsyncOperationCompletedHandler<GattCommunicationStatus>>(
+ writeCompletedLambda).Get());
+ CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not register characteristic write callback",
+ service, QLowEnergyService::CharacteristicWriteError, return)
}
void QLowEnergyControllerPrivateWinRT::writeDescriptor(
@@ -980,8 +1746,8 @@ void QLowEnergyControllerPrivateWinRT::writeDescriptor(
const QLowEnergyHandle descHandle,
const QByteArray &newValue)
{
- qCDebug(QT_BT_WINRT) << __FUNCTION__ << service << charHandle << descHandle << newValue;
- qCDebug(QT_BT_WINRT_SERVICE_THREAD) << __FUNCTION__ << "Changing service pointer from thread"
+ qCDebug(QT_BT_WINDOWS) << __FUNCTION__ << service << charHandle << descHandle << newValue;
+ qCDebug(QT_BT_WINDOWS_SERVICE_THREAD) << __FUNCTION__ << "Changing service pointer from thread"
<< QThread::currentThread();
Q_ASSERT(!service.isNull());
if (role == QLowEnergyController::PeripheralRole) {
@@ -991,158 +1757,237 @@ void QLowEnergyControllerPrivateWinRT::writeDescriptor(
}
if (!service->characteristicList.contains(charHandle)) {
- qCDebug(QT_BT_WINRT) << "Descriptor" << descHandle << "in characteristic" << charHandle
+ qCDebug(QT_BT_WINDOWS) << "Descriptor" << descHandle << "in characteristic" << charHandle
<< "could not be found in service" << service->uuid;
service->setError(QLowEnergyService::DescriptorWriteError);
return;
}
- HRESULT hr;
- hr = QEventDispatcherWinRT::runOnXamlThread([charHandle, descHandle, this, service, newValue]() {
- const QLowEnergyServicePrivate::CharData charData = service->characteristicList.value(charHandle);
- ComPtr<IGattCharacteristic> characteristic = getNativeCharacteristic(service->uuid, charData.uuid);
- if (!characteristic) {
- qCDebug(QT_BT_WINRT) << "Could not obtain native characteristic" << charData.uuid
- << "from service" << service->uuid;
- service->setError(QLowEnergyService::DescriptorWriteError);
- return S_OK;
- }
+ const auto charData = service->characteristicList.value(charHandle);
- // Get native descriptor
- if (!charData.descriptorList.contains(descHandle))
- qCDebug(QT_BT_WINRT) << "Descriptor" << descHandle << "could not be found in Characteristic" << charHandle;
+ auto characteristicCallback = [descHandle, charHandle, service, newValue, this](
+ ComPtr<IGattCharacteristic> characteristic) {
+ writeDescriptorHelper(service, charHandle, descHandle, newValue, characteristic);
+ };
- QLowEnergyServicePrivate::DescData descData = charData.descriptorList.value(descHandle);
- if (descData.uuid == QBluetoothUuid(QBluetoothUuid::ClientCharacteristicConfiguration)) {
- GattClientCharacteristicConfigurationDescriptorValue value;
- quint16 intValue = qFromLittleEndian<quint16>(newValue);
- if (intValue & GattClientCharacteristicConfigurationDescriptorValue_Indicate && intValue & GattClientCharacteristicConfigurationDescriptorValue_Notify) {
- qCWarning(QT_BT_WINRT) << "Setting both Indicate and Notify is not supported on WinRT";
- value = (GattClientCharacteristicConfigurationDescriptorValue)(GattClientCharacteristicConfigurationDescriptorValue_Indicate | GattClientCharacteristicConfigurationDescriptorValue_Notify);
- } else if (intValue & GattClientCharacteristicConfigurationDescriptorValue_Indicate) {
- value = GattClientCharacteristicConfigurationDescriptorValue_Indicate;
- } else if (intValue & GattClientCharacteristicConfigurationDescriptorValue_Notify) {
- value = GattClientCharacteristicConfigurationDescriptorValue_Notify;
- } else if (intValue == 0) {
- value = GattClientCharacteristicConfigurationDescriptorValue_None;
- } else {
- qCDebug(QT_BT_WINRT) << "Descriptor" << descHandle << "write operation failed: Invalid value";
+ HRESULT hr = getNativeCharacteristic(service->uuid, charData.uuid, characteristicCallback);
+ if (FAILED(hr)) {
+ qCDebug(QT_BT_WINDOWS) << "Could not obtain native characteristic" << charData.uuid
+ << "from service" << service->uuid;
+ service->setError(QLowEnergyService::DescriptorWriteError);
+ }
+}
+
+void QLowEnergyControllerPrivateWinRT::writeDescriptorHelper(
+ const QSharedPointer<QLowEnergyServicePrivate> service,
+ const QLowEnergyHandle charHandle,
+ const QLowEnergyHandle descHandle,
+ const QByteArray &newValue,
+ GattCharacteristicComPtr characteristic)
+{
+ // Get native descriptor
+ const auto charData = service->characteristicList.value(charHandle);
+ if (!charData.descriptorList.contains(descHandle)) {
+ qCDebug(QT_BT_WINDOWS) << "Descriptor" << descHandle
+ << "could not be found in Characteristic" << charHandle;
+ }
+
+ QLowEnergyServicePrivate::DescData descData = charData.descriptorList.value(descHandle);
+ if (descData.uuid ==
+ QBluetoothUuid(QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration)) {
+ GattClientCharacteristicConfigurationDescriptorValue value;
+ quint16 intValue = qFromLittleEndian<quint16>(newValue);
+ if (intValue & GattClientCharacteristicConfigurationDescriptorValue_Indicate
+ && intValue & GattClientCharacteristicConfigurationDescriptorValue_Notify) {
+ qCWarning(QT_BT_WINDOWS) << "Setting both Indicate and Notify "
+ "is not supported on WinRT";
+ value = GattClientCharacteristicConfigurationDescriptorValue(
+ (GattClientCharacteristicConfigurationDescriptorValue_Indicate
+ | GattClientCharacteristicConfigurationDescriptorValue_Notify));
+ } else if (intValue & GattClientCharacteristicConfigurationDescriptorValue_Indicate) {
+ value = GattClientCharacteristicConfigurationDescriptorValue_Indicate;
+ } else if (intValue & GattClientCharacteristicConfigurationDescriptorValue_Notify) {
+ value = GattClientCharacteristicConfigurationDescriptorValue_Notify;
+ } else if (intValue == 0) {
+ value = GattClientCharacteristicConfigurationDescriptorValue_None;
+ } else {
+ qCDebug(QT_BT_WINDOWS) << "Descriptor" << descHandle
+ << "write operation failed: Invalid value";
+ service->setError(QLowEnergyService::DescriptorWriteError);
+ return;
+ }
+ ComPtr<IAsyncOperation<enum GattCommunicationStatus>> writeOp;
+ HRESULT hr =
+ characteristic->WriteClientCharacteristicConfigurationDescriptorAsync(value, &writeOp);
+ CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not write client characteristic configuration",
+ service, QLowEnergyService::DescriptorWriteError, return)
+ QPointer<QLowEnergyControllerPrivateWinRT> thisPtr(this);
+ auto writeCompletedLambda = [charHandle, descHandle, newValue, service, thisPtr]
+ (IAsyncOperation<GattCommunicationStatus> *op, AsyncStatus status)
+ {
+ if (status == AsyncStatus::Canceled || status == AsyncStatus::Error) {
+ qCDebug(QT_BT_WINDOWS) << "Descriptor" << descHandle << "write operation failed";
service->setError(QLowEnergyService::DescriptorWriteError);
return S_OK;
}
- ComPtr<IAsyncOperation<enum GattCommunicationStatus>> writeOp;
- HRESULT hr = characteristic->WriteClientCharacteristicConfigurationDescriptorAsync(value, &writeOp);
- Q_ASSERT_SUCCEEDED(hr);
- auto writeCompletedLambda = [charHandle, descHandle, newValue, service, this]
- (IAsyncOperation<GattCommunicationStatus> *op, AsyncStatus status)
- {
- if (status == AsyncStatus::Canceled || status == AsyncStatus::Error) {
- qCDebug(QT_BT_WINRT) << "Descriptor" << descHandle << "write operation failed";
- service->setError(QLowEnergyService::DescriptorWriteError);
- return S_OK;
- }
- GattCommunicationStatus result;
- HRESULT hr;
- hr = op->GetResults(&result);
- if (FAILED(hr)) {
- qCDebug(QT_BT_WINRT) << "Could not obtain result for descriptor" << descHandle;
- service->setError(QLowEnergyService::DescriptorWriteError);
- return S_OK;
- }
- if (result != GattCommunicationStatus_Success) {
- qCDebug(QT_BT_WINRT) << "Descriptor" << descHandle << "write operation failed";
- service->setError(QLowEnergyService::DescriptorWriteError);
- return S_OK;
- }
- updateValueOfDescriptor(charHandle, descHandle, newValue, false);
- emit service->descriptorWritten(QLowEnergyDescriptor(service, charHandle, descHandle), newValue);
- return S_OK;
- };
- hr = writeOp->put_Completed(Callback<IAsyncOperationCompletedHandler<GattCommunicationStatus >>(writeCompletedLambda).Get());
- Q_ASSERT_SUCCEEDED(hr);
- } else {
- ComPtr<IVectorView<GattDescriptor *>> descriptors;
- HRESULT hr = characteristic->GetDescriptors(descData.uuid, &descriptors);
- Q_ASSERT_SUCCEEDED(hr);
- ComPtr<IGattDescriptor> descriptor;
- hr = descriptors->GetAt(0, &descriptor);
- Q_ASSERT_SUCCEEDED(hr);
- ComPtr<ABI::Windows::Storage::Streams::IBufferFactory> bufferFactory;
- hr = GetActivationFactory(HStringReference(RuntimeClass_Windows_Storage_Streams_Buffer).Get(), &bufferFactory);
- Q_ASSERT_SUCCEEDED(hr);
- ComPtr<ABI::Windows::Storage::Streams::IBuffer> buffer;
- const int length = newValue.length();
- hr = bufferFactory->Create(length, &buffer);
- Q_ASSERT_SUCCEEDED(hr);
- hr = buffer->put_Length(length);
- Q_ASSERT_SUCCEEDED(hr);
- ComPtr<Windows::Storage::Streams::IBufferByteAccess> byteAccess;
- hr = buffer.As(&byteAccess);
- Q_ASSERT_SUCCEEDED(hr);
- byte *bytes;
- hr = byteAccess->Buffer(&bytes);
- Q_ASSERT_SUCCEEDED(hr);
- memcpy(bytes, newValue, length);
- ComPtr<IAsyncOperation<GattCommunicationStatus>> writeOp;
- hr = descriptor->WriteValueAsync(buffer.Get(), &writeOp);
- Q_ASSERT_SUCCEEDED(hr);
- auto writeCompletedLambda = [charHandle, descHandle, newValue, service, this]
- (IAsyncOperation<GattCommunicationStatus> *op, AsyncStatus status)
- {
- if (status == AsyncStatus::Canceled || status == AsyncStatus::Error) {
- qCDebug(QT_BT_WINRT) << "Descriptor" << descHandle << "write operation failed";
- service->setError(QLowEnergyService::DescriptorWriteError);
- return S_OK;
- }
- GattCommunicationStatus result;
- HRESULT hr;
- hr = op->GetResults(&result);
- if (FAILED(hr)) {
- qCDebug(QT_BT_WINRT) << "Could not obtain result for descriptor" << descHandle;
- service->setError(QLowEnergyService::DescriptorWriteError);
- return S_OK;
- }
- if (result != GattCommunicationStatus_Success) {
- qCDebug(QT_BT_WINRT) << "Descriptor" << descHandle << "write operation failed";
- service->setError(QLowEnergyService::DescriptorWriteError);
- return S_OK;
- }
- updateValueOfDescriptor(charHandle, descHandle, newValue, false);
- emit service->descriptorWritten(QLowEnergyDescriptor(service, charHandle, descHandle), newValue);
+ GattCommunicationStatus result;
+ HRESULT hr;
+ hr = op->GetResults(&result);
+ CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not obtain result for descriptor", service,
+ QLowEnergyService::DescriptorWriteError, return S_OK)
+ if (result != GattCommunicationStatus_Success) {
+ qCWarning(QT_BT_WINDOWS) << "Descriptor" << descHandle << "write operation failed";
+ service->setError(QLowEnergyService::DescriptorWriteError);
return S_OK;
- };
- hr = writeOp->put_Completed(Callback<IAsyncOperationCompletedHandler<GattCommunicationStatus>>(writeCompletedLambda).Get());
- Q_ASSERT_SUCCEEDED(hr);
+ }
+ if (thisPtr)
+ thisPtr->updateValueOfDescriptor(charHandle, descHandle, newValue, false);
+ emit service->descriptorWritten(QLowEnergyDescriptor(service, charHandle, descHandle),
+ newValue);
+ return S_OK;
+ };
+ hr = writeOp->put_Completed(
+ Callback<IAsyncOperationCompletedHandler<GattCommunicationStatus >>(
+ writeCompletedLambda).Get());
+ CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not register descriptor write callback",
+ service, QLowEnergyService::DescriptorWriteError, return)
+ return;
+ }
+
+ ComPtr<IGattCharacteristic3> characteristic3;
+ HRESULT hr = characteristic.As(&characteristic3);
+ CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not cast characteristic",
+ service, QLowEnergyService::DescriptorWriteError, return)
+ ComPtr<IAsyncOperation<GattDescriptorsResult *>> op;
+ hr = characteristic3->GetDescriptorsForUuidAsync(descData.uuid, &op);
+ CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not obtain descriptor from Uuid",
+ service, QLowEnergyService::DescriptorWriteError, return)
+ ComPtr<IGattDescriptorsResult> result;
+ hr = QWinRTFunctions::await(op, result.GetAddressOf(),
+ QWinRTFunctions::ProcessMainThreadEvents, 5000);
+ CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not await descriptor operation",
+ service, QLowEnergyService::DescriptorWriteError, return)
+ GattCommunicationStatus commStatus;
+ hr = result->get_Status(&commStatus);
+ if (FAILED(hr) || commStatus != GattCommunicationStatus_Success) {
+ qCWarning(QT_BT_WINDOWS) << "Descriptor operation failed";
+ service->setError(QLowEnergyService::DescriptorWriteError);
+ return;
+ }
+ ComPtr<IVectorView<GattDescriptor *>> descriptors;
+ hr = result->get_Descriptors(&descriptors);
+ CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not obtain list of descriptors",
+ service, QLowEnergyService::DescriptorWriteError, return)
+ uint size;
+ hr = descriptors->get_Size(&size);
+ CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not obtain list of descriptors' size",
+ service, QLowEnergyService::DescriptorWriteError, return)
+ if (size == 0) {
+ qCWarning(QT_BT_WINDOWS) << "No descriptor with uuid" << descData.uuid << "was found.";
+ return;
+ } else if (size > 1) {
+ qCWarning(QT_BT_WINDOWS) << "There is more than 1 descriptor with uuid" << descData.uuid;
+ }
+ ComPtr<IGattDescriptor> descriptor;
+ hr = descriptors->GetAt(0, &descriptor);
+ CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not obtain descriptor",
+ service, QLowEnergyService::DescriptorWriteError, return)
+ ComPtr<ABI::Windows::Storage::Streams::IBufferFactory> bufferFactory;
+ hr = GetActivationFactory(
+ HStringReference(RuntimeClass_Windows_Storage_Streams_Buffer).Get(),
+ &bufferFactory);
+ CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not obtain buffer factory",
+ service, QLowEnergyService::DescriptorWriteError, return)
+ ComPtr<ABI::Windows::Storage::Streams::IBuffer> buffer;
+ const quint32 length = quint32(newValue.length());
+ hr = bufferFactory->Create(length, &buffer);
+ CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not create buffer",
+ service, QLowEnergyService::DescriptorWriteError, return)
+ hr = buffer->put_Length(length);
+ CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not set buffer length",
+ service, QLowEnergyService::DescriptorWriteError, return)
+ ComPtr<Windows::Storage::Streams::IBufferByteAccess> byteAccess;
+ hr = buffer.As(&byteAccess);
+ CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not cast buffer",
+ service, QLowEnergyService::DescriptorWriteError, return)
+ byte *bytes;
+ hr = byteAccess->Buffer(&bytes);
+ CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not set buffer",
+ service, QLowEnergyService::DescriptorWriteError, return)
+ memcpy(bytes, newValue, length);
+ ComPtr<IAsyncOperation<GattCommunicationStatus>> writeOp;
+ hr = descriptor->WriteValueAsync(buffer.Get(), &writeOp);
+ CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not write descriptor value",
+ service, QLowEnergyService::DescriptorWriteError, return)
+ QPointer<QLowEnergyControllerPrivateWinRT> thisPtr(this);
+ auto writeCompletedLambda = [charHandle, descHandle, newValue, service, thisPtr]
+ (IAsyncOperation<GattCommunicationStatus> *op, AsyncStatus status)
+ {
+ if (status == AsyncStatus::Canceled || status == AsyncStatus::Error) {
+ qCDebug(QT_BT_WINDOWS) << "Descriptor" << descHandle << "write operation failed";
+ service->setError(QLowEnergyService::DescriptorWriteError);
+ return S_OK;
+ }
+ GattCommunicationStatus result;
+ HRESULT hr;
+ hr = op->GetResults(&result);
+ CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not obtain result for descriptor", service,
+ QLowEnergyService::DescriptorWriteError, return S_OK)
+ if (result != GattCommunicationStatus_Success) {
+ qCDebug(QT_BT_WINDOWS) << "Descriptor" << descHandle << "write operation failed";
+ service->setError(QLowEnergyService::DescriptorWriteError);
return S_OK;
}
+ if (thisPtr)
+ thisPtr->updateValueOfDescriptor(charHandle, descHandle, newValue, false);
+ emit service->descriptorWritten(QLowEnergyDescriptor(service, charHandle, descHandle),
+ newValue);
return S_OK;
- });
- Q_ASSERT_SUCCEEDED(hr);
+ };
+ hr = writeOp->put_Completed(
+ Callback<IAsyncOperationCompletedHandler<GattCommunicationStatus>>(
+ writeCompletedLambda).Get());
+ CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not register descriptor write callback",
+ service, QLowEnergyService::DescriptorWriteError, return)
}
-
-void QLowEnergyControllerPrivateWinRT::addToGenericAttributeList(const QLowEnergyServiceData &, QLowEnergyHandle)
+void QLowEnergyControllerPrivateWinRT::addToGenericAttributeList(const QLowEnergyServiceData &,
+ QLowEnergyHandle)
{
Q_UNIMPLEMENTED();
}
+int QLowEnergyControllerPrivateWinRT::mtu() const
+{
+ uint16_t mtu = 23;
+ if (!mGattSession) {
+ qCDebug(QT_BT_WINDOWS) << "mtu queried before GattSession available. Using default mtu.";
+ return mtu;
+ }
+
+ HRESULT hr = mGattSession->get_MaxPduSize(&mtu);
+ RETURN_IF_FAILED("could not obtain MTU size", return mtu);
+ qCDebug(QT_BT_WINDOWS) << "mtu determined to be" << mtu;
+ return mtu;
+}
+
void QLowEnergyControllerPrivateWinRT::handleCharacteristicChanged(
quint16 charHandle, const QByteArray &data)
{
- qCDebug(QT_BT_WINRT) << __FUNCTION__ << charHandle << data;
- qCDebug(QT_BT_WINRT_SERVICE_THREAD) << __FUNCTION__ << "Changing service pointer from thread"
+ qCDebug(QT_BT_WINDOWS) << __FUNCTION__ << charHandle << data;
+ qCDebug(QT_BT_WINDOWS_SERVICE_THREAD) << __FUNCTION__ << "Changing service pointer from thread"
<< QThread::currentThread();
QSharedPointer<QLowEnergyServicePrivate> service =
serviceForHandle(charHandle);
if (service.isNull())
return;
- qCDebug(QT_BT_WINRT) << "Characteristic change notification" << service->uuid
+ qCDebug(QT_BT_WINDOWS) << "Characteristic change notification" << service->uuid
<< charHandle << data.toHex();
QLowEnergyCharacteristic characteristic = characteristicForHandle(charHandle);
if (!characteristic.isValid()) {
- qCWarning(QT_BT_WINRT) << "characteristicChanged: Cannot find characteristic";
+ qCWarning(QT_BT_WINDOWS) << "characteristicChanged: Cannot find characteristic";
return;
}
@@ -1154,6 +1999,25 @@ void QLowEnergyControllerPrivateWinRT::handleCharacteristicChanged(
emit service->characteristicChanged(characteristic, data);
}
+void QLowEnergyControllerPrivateWinRT::handleServiceHandlerError(const QString &error)
+{
+ if (state != QLowEnergyController::DiscoveringState)
+ return;
+
+ qCWarning(QT_BT_WINDOWS) << "Error while discovering services:" << error;
+ setState(QLowEnergyController::UnconnectedState);
+ setError(QLowEnergyController::ConnectionError);
+}
+
+void QLowEnergyControllerPrivateWinRT::handleConnectionError(const char *logMessage)
+{
+ qCWarning(QT_BT_WINDOWS) << logMessage;
+ setError(QLowEnergyController::ConnectionError);
+ setState(QLowEnergyController::UnconnectedState);
+ unregisterFromStatusChanges();
+ unregisterFromMtuChanges();
+}
+
QT_END_NAMESPACE
#include "qlowenergycontroller_winrt.moc"
diff --git a/src/bluetooth/qlowenergycontroller_winrt_new.cpp b/src/bluetooth/qlowenergycontroller_winrt_new.cpp
deleted file mode 100644
index a22064fd..00000000
--- a/src/bluetooth/qlowenergycontroller_winrt_new.cpp
+++ /dev/null
@@ -1,1703 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qlowenergycontroller_winrt_new_p.h"
-#include "qlowenergycontroller_winrt_p.h"
-#include "qbluetoothutils_winrt_p.h"
-
-#include <QtBluetooth/qbluetoothlocaldevice.h>
-#include <QtBluetooth/QLowEnergyCharacteristicData>
-#include <QtBluetooth/QLowEnergyDescriptorData>
-#include <QtBluetooth/private/qbluetoothutils_winrt_p.h>
-
-#ifdef CLASSIC_APP_BUILD
-#define Q_OS_WINRT
-#endif
-#include <QtCore/qfunctions_winrt.h>
-#include <QtCore/QtEndian>
-#include <QtCore/QLoggingCategory>
-#include <private/qeventdispatcher_winrt_p.h>
-
-#include <functional>
-#include <robuffer.h>
-#include <windows.devices.enumeration.h>
-#include <windows.devices.bluetooth.h>
-#include <windows.devices.bluetooth.genericattributeprofile.h>
-#include <windows.foundation.collections.h>
-#include <windows.foundation.metadata.h>
-#include <windows.storage.streams.h>
-
-using namespace Microsoft::WRL;
-using namespace Microsoft::WRL::Wrappers;
-using namespace ABI::Windows::Foundation;
-using namespace ABI::Windows::Foundation::Collections;
-using namespace ABI::Windows::Foundation::Metadata;
-using namespace ABI::Windows::Devices;
-using namespace ABI::Windows::Devices::Bluetooth;
-using namespace ABI::Windows::Devices::Bluetooth::GenericAttributeProfile;
-using namespace ABI::Windows::Devices::Enumeration;
-using namespace ABI::Windows::Storage::Streams;
-
-QT_BEGIN_NAMESPACE
-
-typedef ITypedEventHandler<BluetoothLEDevice *, IInspectable *> StatusHandler;
-typedef ITypedEventHandler<GattCharacteristic *, GattValueChangedEventArgs *> ValueChangedHandler;
-typedef GattReadClientCharacteristicConfigurationDescriptorResult ClientCharConfigDescriptorResult;
-typedef IGattReadClientCharacteristicConfigurationDescriptorResult IClientCharConfigDescriptorResult;
-
-#define EMIT_WORKER_ERROR_AND_QUIT_IF_FAILED(hr, ret) \
- if (FAILED(hr)) { \
- emitErrorAndQuitThread(hr); \
- ret; \
- }
-
-#define WARN_AND_CONTINUE_IF_FAILED(hr, msg) \
- if (FAILED(hr)) { \
- qCWarning(QT_BT_WINRT) << msg; \
- continue; \
- }
-
-#define CHECK_FOR_DEVICE_CONNECTION_ERROR_IMPL(this, hr, msg, ret) \
- if (FAILED(hr)) { \
- qCWarning(QT_BT_WINRT) << msg; \
- this->unregisterFromStatusChanges(); \
- this->setError(QLowEnergyController::ConnectionError); \
- this->setState(QLowEnergyController::UnconnectedState); \
- ret; \
- }
-
-#define CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, msg, ret) \
- CHECK_FOR_DEVICE_CONNECTION_ERROR_IMPL(this, hr, msg, ret)
-
-#define CHECK_HR_AND_SET_SERVICE_ERROR(hr, msg, service, error, ret) \
- if (FAILED(hr)) { \
- qCDebug(QT_BT_WINRT) << msg; \
- service->setError(error); \
- ret; \
- }
-
-Q_DECLARE_LOGGING_CATEGORY(QT_BT_WINRT)
-Q_DECLARE_LOGGING_CATEGORY(QT_BT_WINRT_SERVICE_THREAD)
-
-QLowEnergyControllerPrivate *createWinRTLowEnergyController()
-{
- if (supportsNewLEApi()) {
- qCDebug(QT_BT_WINRT) << "Using new low energy controller";
- return new QLowEnergyControllerPrivateWinRTNew();
- }
-
- qCDebug(QT_BT_WINRT) << "Using pre 15063 low energy controller";
- return new QLowEnergyControllerPrivateWinRT();
-}
-
-static QByteArray byteArrayFromGattResult(const ComPtr<IGattReadResult> &gattResult,
- bool isWCharString = false)
-{
- ComPtr<ABI::Windows::Storage::Streams::IBuffer> buffer;
- HRESULT hr;
- hr = gattResult->get_Value(&buffer);
- if (FAILED(hr) || !buffer) {
- qCWarning(QT_BT_WINRT) << "Could not obtain buffer from GattReadResult";
- return QByteArray();
- }
- return byteArrayFromBuffer(buffer, isWCharString);
-}
-
-class QWinRTLowEnergyServiceHandlerNew : public QObject
-{
- Q_OBJECT
-public:
- QWinRTLowEnergyServiceHandlerNew(const QBluetoothUuid &service,
- const ComPtr<IGattDeviceService3> &deviceService)
- : mService(service)
- , mDeviceService(deviceService)
- {
- qCDebug(QT_BT_WINRT) << __FUNCTION__;
- }
-
- ~QWinRTLowEnergyServiceHandlerNew()
- {
- }
-
-public slots:
- void obtainCharList()
- {
- mIndicateChars.clear();
- qCDebug(QT_BT_WINRT) << __FUNCTION__;
- ComPtr<IAsyncOperation<GattCharacteristicsResult *>> characteristicsOp;
- ComPtr<IGattCharacteristicsResult> characteristicsResult;
- HRESULT hr = mDeviceService->GetCharacteristicsAsync(&characteristicsOp);
- EMIT_WORKER_ERROR_AND_QUIT_IF_FAILED(hr, return);
- hr = QWinRTFunctions::await(characteristicsOp, characteristicsResult.GetAddressOf(),
- QWinRTFunctions::ProcessMainThreadEvents, 5000);
- EMIT_WORKER_ERROR_AND_QUIT_IF_FAILED(hr, return);
- GattCommunicationStatus status;
- hr = characteristicsResult->get_Status(&status);
- EMIT_WORKER_ERROR_AND_QUIT_IF_FAILED(hr, return);
- if (status != GattCommunicationStatus_Success) {
- emitErrorAndQuitThread(QLatin1String("Could not obtain char list"));
- return;
- }
- ComPtr<IVectorView<GattCharacteristic *>> characteristics;
- hr = characteristicsResult->get_Characteristics(&characteristics);
- EMIT_WORKER_ERROR_AND_QUIT_IF_FAILED(hr, return);
-
- uint characteristicsCount;
- hr = characteristics->get_Size(&characteristicsCount);
- EMIT_WORKER_ERROR_AND_QUIT_IF_FAILED(hr, return);
-
- mCharacteristicsCountToBeDiscovered = characteristicsCount;
- for (uint i = 0; i < characteristicsCount; ++i) {
- ComPtr<IGattCharacteristic> characteristic;
- hr = characteristics->GetAt(i, &characteristic);
- if (FAILED(hr)) {
- qCWarning(QT_BT_WINRT) << "Could not obtain characteristic at" << i;
- --mCharacteristicsCountToBeDiscovered;
- continue;
- }
-
- ComPtr<IGattCharacteristic3> characteristic3;
- hr = characteristic.As(&characteristic3);
- if (FAILED(hr)) {
- qCWarning(QT_BT_WINRT) << "Could not cast characteristic";
- --mCharacteristicsCountToBeDiscovered;
- continue;
- }
-
- // For some strange reason, Windows doesn't discover descriptors of characteristics (if not paired).
- // Qt API assumes that all characteristics and their descriptors are discovered in one go.
- // So we start 'GetDescriptorsAsync' for each discovered characteristic and finish only
- // when GetDescriptorsAsync for all characteristics return.
- ComPtr<IAsyncOperation<GattDescriptorsResult*>> descAsyncResult;
- hr = characteristic3->GetDescriptorsAsync(&descAsyncResult);
- if (FAILED(hr)) {
- qCWarning(QT_BT_WINRT) << "Could not obtain list of descriptors";
- --mCharacteristicsCountToBeDiscovered;
- continue;
- }
- hr = descAsyncResult->put_Completed(
- Callback<IAsyncOperationCompletedHandler<GattDescriptorsResult*>>(
- [this, characteristic]
- (IAsyncOperation<GattDescriptorsResult *> *op,
- AsyncStatus status) {
- if (status != AsyncStatus::Completed) {
- qCWarning(QT_BT_WINRT) << "Descriptor operation unsuccessful";
- --mCharacteristicsCountToBeDiscovered;
- checkAllCharacteristicsDiscovered();
- return S_OK;
- }
- quint16 handle;
-
- HRESULT hr = characteristic->get_AttributeHandle(&handle);
- if (FAILED(hr)) {
- qCWarning(QT_BT_WINRT) << "Could not obtain characteristic's attribute handle";
- --mCharacteristicsCountToBeDiscovered;
- checkAllCharacteristicsDiscovered();
- return S_OK;
- }
- QLowEnergyServicePrivate::CharData charData;
- charData.valueHandle = handle + 1;
- if (mStartHandle == 0 || mStartHandle > handle)
- mStartHandle = handle;
- if (mEndHandle == 0 || mEndHandle < handle)
- mEndHandle = handle;
- GUID guuid;
- hr = characteristic->get_Uuid(&guuid);
- if (FAILED(hr)) {
- qCWarning(QT_BT_WINRT) << "Could not obtain characteristic's Uuid";
- --mCharacteristicsCountToBeDiscovered;
- checkAllCharacteristicsDiscovered();
- return S_OK;
- }
- charData.uuid = QBluetoothUuid(guuid);
- GattCharacteristicProperties properties;
- hr = characteristic->get_CharacteristicProperties(&properties);
- if (FAILED(hr)) {
- qCWarning(QT_BT_WINRT) << "Could not obtain characteristic's properties";
- --mCharacteristicsCountToBeDiscovered;
- checkAllCharacteristicsDiscovered();
- return S_OK;
- }
- charData.properties = QLowEnergyCharacteristic::PropertyTypes(properties & 0xff);
- if (charData.properties & QLowEnergyCharacteristic::Read) {
- ComPtr<IAsyncOperation<GattReadResult *>> readOp;
- hr = characteristic->ReadValueWithCacheModeAsync(BluetoothCacheMode_Uncached,
- &readOp);
- if (FAILED(hr)) {
- qCWarning(QT_BT_WINRT) << "Could not read characteristic";
- --mCharacteristicsCountToBeDiscovered;
- checkAllCharacteristicsDiscovered();
- return S_OK;
- }
- ComPtr<IGattReadResult> readResult;
- hr = QWinRTFunctions::await(readOp, readResult.GetAddressOf());
- if (FAILED(hr)) {
- qCWarning(QT_BT_WINRT) << "Could not obtain characteristic read result";
- --mCharacteristicsCountToBeDiscovered;
- checkAllCharacteristicsDiscovered();
- return S_OK;
- }
- if (!readResult)
- qCWarning(QT_BT_WINRT) << "Characteristic read result is null";
- else
- charData.value = byteArrayFromGattResult(readResult);
- }
- mCharacteristicList.insert(handle, charData);
-
- ComPtr<IVectorView<GattDescriptor *>> descriptors;
-
- ComPtr<IGattDescriptorsResult> result;
- hr = op->GetResults(&result);
- if (FAILED(hr)) {
- qCWarning(QT_BT_WINRT) << "Could not obtain descriptor read result";
- --mCharacteristicsCountToBeDiscovered;
- checkAllCharacteristicsDiscovered();
- return S_OK;
- }
- GattCommunicationStatus commStatus;
- hr = result->get_Status(&commStatus);
- if (FAILED(hr) || commStatus != GattCommunicationStatus_Success) {
- qCWarning(QT_BT_WINRT) << "Descriptor operation failed";
- --mCharacteristicsCountToBeDiscovered;
- checkAllCharacteristicsDiscovered();
- return S_OK;
- }
-
- hr = result->get_Descriptors(&descriptors);
- if (FAILED(hr)) {
- qCWarning(QT_BT_WINRT) << "Could not obtain list of descriptors";
- --mCharacteristicsCountToBeDiscovered;
- checkAllCharacteristicsDiscovered();
- return S_OK;
- }
-
- uint descriptorCount;
- hr = descriptors->get_Size(&descriptorCount);
- if (FAILED(hr)) {
- qCWarning(QT_BT_WINRT) << "Could not obtain list of descriptors' size";
- --mCharacteristicsCountToBeDiscovered;
- checkAllCharacteristicsDiscovered();
- return S_OK;
- }
- for (uint j = 0; j < descriptorCount; ++j) {
- QLowEnergyServicePrivate::DescData descData;
- ComPtr<IGattDescriptor> descriptor;
- hr = descriptors->GetAt(j, &descriptor);
- WARN_AND_CONTINUE_IF_FAILED(hr, "Could not obtain descriptor")
- quint16 descHandle;
- hr = descriptor->get_AttributeHandle(&descHandle);
- WARN_AND_CONTINUE_IF_FAILED(hr, "Could not obtain descriptor's attribute handle")
- GUID descriptorUuid;
- hr = descriptor->get_Uuid(&descriptorUuid);
- WARN_AND_CONTINUE_IF_FAILED(hr, "Could not obtain descriptor's Uuid")
- descData.uuid = QBluetoothUuid(descriptorUuid);
- charData.descriptorList.insert(descHandle, descData);
- if (descData.uuid == QBluetoothUuid(QBluetoothUuid::ClientCharacteristicConfiguration)) {
- ComPtr<IAsyncOperation<ClientCharConfigDescriptorResult *>> readOp;
- hr = characteristic->ReadClientCharacteristicConfigurationDescriptorAsync(&readOp);
- WARN_AND_CONTINUE_IF_FAILED(hr, "Could not read descriptor value")
- ComPtr<IClientCharConfigDescriptorResult> readResult;
- hr = QWinRTFunctions::await(readOp, readResult.GetAddressOf());
- WARN_AND_CONTINUE_IF_FAILED(hr, "Could not await descriptor read result")
- GattClientCharacteristicConfigurationDescriptorValue value;
- hr = readResult->get_ClientCharacteristicConfigurationDescriptor(&value);
- WARN_AND_CONTINUE_IF_FAILED(hr, "Could not get descriptor value from result")
- quint16 result = 0;
- bool correct = false;
- if (value & GattClientCharacteristicConfigurationDescriptorValue_Indicate) {
- result |= GattClientCharacteristicConfigurationDescriptorValue_Indicate;
- correct = true;
- }
- if (value & GattClientCharacteristicConfigurationDescriptorValue_Notify) {
- result |= GattClientCharacteristicConfigurationDescriptorValue_Notify;
- correct = true;
- }
- if (value == GattClientCharacteristicConfigurationDescriptorValue_None) {
- correct = true;
- }
- if (!correct)
- continue;
-
- descData.value = QByteArray(2, Qt::Uninitialized);
- qToLittleEndian(result, descData.value.data());
- mIndicateChars << charData.uuid;
- } else {
- ComPtr<IAsyncOperation<GattReadResult *>> readOp;
- hr = descriptor->ReadValueWithCacheModeAsync(BluetoothCacheMode_Uncached,
- &readOp);
- WARN_AND_CONTINUE_IF_FAILED(hr, "Could not read descriptor value")
- ComPtr<IGattReadResult> readResult;
- hr = QWinRTFunctions::await(readOp, readResult.GetAddressOf());
- WARN_AND_CONTINUE_IF_FAILED(hr, "Could await descriptor read result")
- if (descData.uuid == QBluetoothUuid::CharacteristicUserDescription)
- descData.value = byteArrayFromGattResult(readResult, true);
- else
- descData.value = byteArrayFromGattResult(readResult);
- }
- charData.descriptorList.insert(descHandle, descData);
- }
-
- mCharacteristicList.insert(handle, charData);
- --mCharacteristicsCountToBeDiscovered;
- checkAllCharacteristicsDiscovered();
- return S_OK;
- }).Get());
- if (FAILED(hr)) {
- qCWarning(QT_BT_WINRT) << "Could not register descriptor callback";
- --mCharacteristicsCountToBeDiscovered;
- continue;
- }
- }
- checkAllCharacteristicsDiscovered();
- }
-
-private:
- bool checkAllCharacteristicsDiscovered();
- void emitErrorAndQuitThread(HRESULT hr);
- void emitErrorAndQuitThread(const QString &error);
-
-public:
- QBluetoothUuid mService;
- ComPtr<IGattDeviceService3> mDeviceService;
- QHash<QLowEnergyHandle, QLowEnergyServicePrivate::CharData> mCharacteristicList;
- uint mCharacteristicsCountToBeDiscovered;
- quint16 mStartHandle = 0;
- quint16 mEndHandle = 0;
- QVector<QBluetoothUuid> mIndicateChars;
-
-signals:
- void charListObtained(const QBluetoothUuid &service, QHash<QLowEnergyHandle,
- QLowEnergyServicePrivate::CharData> charList,
- QVector<QBluetoothUuid> indicateChars,
- QLowEnergyHandle startHandle, QLowEnergyHandle endHandle);
- void errorOccured(const QString &error);
-};
-
-bool QWinRTLowEnergyServiceHandlerNew::checkAllCharacteristicsDiscovered()
-{
- if (mCharacteristicsCountToBeDiscovered == 0) {
- emit charListObtained(mService, mCharacteristicList, mIndicateChars,
- mStartHandle, mEndHandle);
- QThread::currentThread()->quit();
- return true;
- }
-
- return false;
-}
-
-void QWinRTLowEnergyServiceHandlerNew::emitErrorAndQuitThread(HRESULT hr)
-{
- emitErrorAndQuitThread(qt_error_string(hr));
-}
-
-void QWinRTLowEnergyServiceHandlerNew::emitErrorAndQuitThread(const QString &error)
-{
- emit errorOccured(error);
- QThread::currentThread()->quit();
-}
-
-QLowEnergyControllerPrivateWinRTNew::QLowEnergyControllerPrivateWinRTNew()
- : QLowEnergyControllerPrivate()
-{
- registerQLowEnergyControllerMetaType();
- connect(this, &QLowEnergyControllerPrivateWinRTNew::characteristicChanged,
- this, &QLowEnergyControllerPrivateWinRTNew::handleCharacteristicChanged,
- Qt::QueuedConnection);
-}
-
-QLowEnergyControllerPrivateWinRTNew::~QLowEnergyControllerPrivateWinRTNew()
-{
- unregisterFromStatusChanges();
- unregisterFromValueChanges();
- mAbortPending = true;
-}
-
-void QLowEnergyControllerPrivateWinRTNew::init()
-{
-}
-
-void QLowEnergyControllerPrivateWinRTNew::connectToDevice()
-{
- qCDebug(QT_BT_WINRT) << __FUNCTION__;
- mAbortPending = false;
- Q_Q(QLowEnergyController);
- if (remoteDevice.isNull()) {
- qWarning() << "Invalid/null remote device address";
- setError(QLowEnergyController::UnknownRemoteDeviceError);
- return;
- }
-
- setState(QLowEnergyController::ConnectingState);
-
- ComPtr<IBluetoothLEDeviceStatics> deviceStatics;
- HRESULT hr = GetActivationFactory(
- HString::MakeReference(RuntimeClass_Windows_Devices_Bluetooth_BluetoothLEDevice).Get(),
- &deviceStatics);
- CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not obtain device factory", return)
- ComPtr<IAsyncOperation<BluetoothLEDevice *>> deviceFromIdOperation;
- hr = deviceStatics->FromBluetoothAddressAsync(remoteDevice.toUInt64(), &deviceFromIdOperation);
- CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not find LE device from address", return)
- hr = QWinRTFunctions::await(deviceFromIdOperation, mDevice.GetAddressOf(),
- QWinRTFunctions::ProcessMainThreadEvents, 5000);
- if (FAILED(hr) || !mDevice) {
- qCWarning(QT_BT_WINRT) << "Could not find LE device";
- setError(QLowEnergyController::InvalidBluetoothAdapterError);
- setState(QLowEnergyController::UnconnectedState);
- return;
- }
- BluetoothConnectionStatus status;
- hr = mDevice->get_ConnectionStatus(&status);
- CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not obtain device's connection status", return)
- if (status == BluetoothConnectionStatus::BluetoothConnectionStatus_Connected) {
- setState(QLowEnergyController::ConnectedState);
- emit q->connected();
- return;
- }
-
- QBluetoothLocalDevice localDevice;
- QBluetoothLocalDevice::Pairing pairing = localDevice.pairingStatus(remoteDevice);
- if (pairing == QBluetoothLocalDevice::Unpaired)
- connectToUnpairedDevice();
- else
- connectToPairedDevice();
-}
-
-void QLowEnergyControllerPrivateWinRTNew::disconnectFromDevice()
-{
- qCDebug(QT_BT_WINRT) << __FUNCTION__;
- Q_Q(QLowEnergyController);
- setState(QLowEnergyController::ClosingState);
- unregisterFromValueChanges();
- unregisterFromStatusChanges();
- mAbortPending = true;
- mDevice = nullptr;
- setState(QLowEnergyController::UnconnectedState);
- emit q->disconnected();
-}
-
-ComPtr<IGattDeviceService> QLowEnergyControllerPrivateWinRTNew::getNativeService(
- const QBluetoothUuid &serviceUuid)
-{
- ComPtr<IGattDeviceService> deviceService;
- HRESULT hr;
- hr = mDevice->GetGattService(serviceUuid, &deviceService);
- if (FAILED(hr))
- qCDebug(QT_BT_WINRT) << "Could not obtain native service for Uuid" << serviceUuid;
- return deviceService;
-}
-
-ComPtr<IGattCharacteristic> QLowEnergyControllerPrivateWinRTNew::getNativeCharacteristic(
- const QBluetoothUuid &serviceUuid, const QBluetoothUuid &charUuid)
-{
- ComPtr<IGattDeviceService> service = getNativeService(serviceUuid);
- if (!service)
- return nullptr;
-
- ComPtr<IGattDeviceService3> service3;
- HRESULT hr = service.As(&service3);
- RETURN_IF_FAILED("Could not cast service", return nullptr);
-
- ComPtr<IAsyncOperation<GattCharacteristicsResult *>> op;
- ComPtr<IGattCharacteristicsResult> result;
- hr = service3->GetCharacteristicsForUuidAsync(charUuid, &op);
- RETURN_IF_FAILED("Could not obtain native characteristics for service", return nullptr);
- hr = QWinRTFunctions::await(op, result.GetAddressOf(), QWinRTFunctions::ProcessMainThreadEvents, 5000);
- RETURN_IF_FAILED("Could not await completion of characteristic operation", return nullptr);
- GattCommunicationStatus status;
- hr = result->get_Status(&status);
- if (FAILED(hr) || status != GattCommunicationStatus_Success) {
- qErrnoWarning(hr, "Native characteristic operation failed.");
- return nullptr;
- }
- ComPtr<IVectorView<GattCharacteristic *>> characteristics;
- hr = result->get_Characteristics(&characteristics);
- RETURN_IF_FAILED("Could not obtain characteristic list.", return nullptr);
- uint size;
- hr = characteristics->get_Size(&size);
- RETURN_IF_FAILED("Could not obtain characteristic list's size.", return nullptr);
- if (size != 1)
- qErrnoWarning("More than 1 characteristic found.");
- ComPtr<IGattCharacteristic> characteristic;
- hr = characteristics->GetAt(0, &characteristic);
- RETURN_IF_FAILED("Could not obtain first characteristic for service", return nullptr);
- return characteristic;
-}
-
-void QLowEnergyControllerPrivateWinRTNew::registerForValueChanges(const QBluetoothUuid &serviceUuid,
- const QBluetoothUuid &charUuid)
-{
- qCDebug(QT_BT_WINRT) << "Registering characteristic" << charUuid << "in service"
- << serviceUuid << "for value changes";
- for (const ValueChangedEntry &entry : qAsConst(mValueChangedTokens)) {
- GUID guuid;
- HRESULT hr;
- hr = entry.characteristic->get_Uuid(&guuid);
- WARN_AND_CONTINUE_IF_FAILED(hr, "Could not obtain characteristic's Uuid")
- if (QBluetoothUuid(guuid) == charUuid)
- return;
- }
- ComPtr<IGattCharacteristic> characteristic = getNativeCharacteristic(serviceUuid, charUuid);
- if (!characteristic) {
- qCDebug(QT_BT_WINRT).nospace() << "Could not obtain native characteristic " << charUuid
- << " from service " << serviceUuid << ". Qt will not be able to signal"
- << " changes for this characteristic.";
- return;
- }
-
- EventRegistrationToken token;
- HRESULT hr;
- hr = characteristic->add_ValueChanged(
- Callback<ValueChangedHandler>(this, &QLowEnergyControllerPrivateWinRTNew::onValueChange).Get(),
- &token);
- RETURN_IF_FAILED("Could not register characteristic for value changes", return)
- mValueChangedTokens.append(ValueChangedEntry(characteristic, token));
- qCDebug(QT_BT_WINRT) << "Characteristic" << charUuid << "in service"
- << serviceUuid << "registered for value changes";
-}
-
-void QLowEnergyControllerPrivateWinRTNew::unregisterFromValueChanges()
-{
- qCDebug(QT_BT_WINRT) << "Unregistering " << mValueChangedTokens.count() << " value change tokens";
- HRESULT hr;
- for (const ValueChangedEntry &entry : qAsConst(mValueChangedTokens)) {
- if (!entry.characteristic) {
- qCWarning(QT_BT_WINRT) << "Unregistering from value changes for characteristic failed."
- << "Characteristic has been deleted";
- continue;
- }
- hr = entry.characteristic->remove_ValueChanged(entry.token);
- if (FAILED(hr))
- qCWarning(QT_BT_WINRT) << "Unregistering from value changes for characteristic failed.";
- }
- mValueChangedTokens.clear();
-}
-
-HRESULT QLowEnergyControllerPrivateWinRTNew::onValueChange(IGattCharacteristic *characteristic, IGattValueChangedEventArgs *args)
-{
- HRESULT hr;
- quint16 handle;
- hr = characteristic->get_AttributeHandle(&handle);
- RETURN_IF_FAILED("Could not obtain characteristic's handle", return S_OK)
- ComPtr<IBuffer> buffer;
- hr = args->get_CharacteristicValue(&buffer);
- RETURN_IF_FAILED("Could not obtain characteristic's value", return S_OK)
- emit characteristicChanged(handle, byteArrayFromBuffer(buffer));
- return S_OK;
-}
-
-bool QLowEnergyControllerPrivateWinRTNew::registerForStatusChanges()
-{
- if (!mDevice)
- return false;
-
- qCDebug(QT_BT_WINRT) << __FUNCTION__;
-
- HRESULT hr;
- hr = QEventDispatcherWinRT::runOnXamlThread([this]() {
- HRESULT hr;
- hr = mDevice->add_ConnectionStatusChanged(
- Callback<StatusHandler>(this, &QLowEnergyControllerPrivateWinRTNew::onStatusChange).Get(),
- &mStatusChangedToken);
- RETURN_IF_FAILED("Could not register connection status callback", return hr)
- return S_OK;
- });
- RETURN_FALSE_IF_FAILED("Could not add status callback on Xaml thread")
- return true;
-}
-
-void QLowEnergyControllerPrivateWinRTNew::unregisterFromStatusChanges()
-{
- qCDebug(QT_BT_WINRT) << __FUNCTION__;
- if (mDevice && mStatusChangedToken.value) {
- mDevice->remove_ConnectionStatusChanged(mStatusChangedToken);
- mStatusChangedToken.value = 0;
- }
-}
-
-HRESULT QLowEnergyControllerPrivateWinRTNew::onStatusChange(IBluetoothLEDevice *dev, IInspectable *)
-{
- Q_Q(QLowEnergyController);
- BluetoothConnectionStatus status;
- HRESULT hr;
- hr = dev->get_ConnectionStatus(&status);
- RETURN_IF_FAILED("Could not obtain connection status", return S_OK)
- if (state == QLowEnergyController::ConnectingState
- && status == BluetoothConnectionStatus::BluetoothConnectionStatus_Connected) {
- setState(QLowEnergyController::ConnectedState);
- emit q->connected();
- } else if (state != QLowEnergyController::UnconnectedState
- && status == BluetoothConnectionStatus::BluetoothConnectionStatus_Disconnected) {
- invalidateServices();
- unregisterFromValueChanges();
- unregisterFromStatusChanges();
- mDevice = nullptr;
- setError(QLowEnergyController::RemoteHostClosedError);
- setState(QLowEnergyController::UnconnectedState);
- emit q->disconnected();
- }
- return S_OK;
-}
-
-void QLowEnergyControllerPrivateWinRTNew::obtainIncludedServices(
- QSharedPointer<QLowEnergyServicePrivate> servicePointer,
- ComPtr<IGattDeviceService> service)
-{
- Q_Q(QLowEnergyController);
- ComPtr<IGattDeviceService3> service3;
- HRESULT hr = service.As(&service3);
- RETURN_IF_FAILED("Could not cast service", return);
- ComPtr<IAsyncOperation<GattDeviceServicesResult *>> op;
- hr = service3->GetIncludedServicesAsync(&op);
- // Some devices return ERROR_ACCESS_DISABLED_BY_POLICY
- RETURN_IF_FAILED("Could not obtain included services", return);
- ComPtr<IGattDeviceServicesResult> result;
- hr = QWinRTFunctions::await(op, result.GetAddressOf(), QWinRTFunctions::ProcessMainThreadEvents, 5000);
- RETURN_IF_FAILED("Could not await service operation", return);
- GattCommunicationStatus status;
- hr = result->get_Status(&status);
- if (FAILED(hr) || status != GattCommunicationStatus_Success) {
- qErrnoWarning("Could not obtain list of included services");
- return;
- }
- ComPtr<IVectorView<GattDeviceService *>> includedServices;
- hr = result->get_Services(&includedServices);
- RETURN_IF_FAILED("Could not obtain service list", return);
-
- uint count;
- hr = includedServices->get_Size(&count);
- RETURN_IF_FAILED("Could not obtain service list's size", return);
- for (uint i = 0; i < count; ++i) {
- ComPtr<IGattDeviceService> includedService;
- hr = includedServices->GetAt(i, &includedService);
- WARN_AND_CONTINUE_IF_FAILED(hr, "Could not obtain service from list");
- GUID guuid;
- hr = includedService->get_Uuid(&guuid);
- WARN_AND_CONTINUE_IF_FAILED(hr, "Could not obtain included service's Uuid");
- const QBluetoothUuid includedUuid(guuid);
- QSharedPointer<QLowEnergyServicePrivate> includedPointer;
- qCDebug(QT_BT_WINRT_SERVICE_THREAD) << __FUNCTION__
- << "Changing service pointer from thread"
- << QThread::currentThread();
- if (serviceList.contains(includedUuid)) {
- includedPointer = serviceList.value(includedUuid);
- } else {
- QLowEnergyServicePrivate *priv = new QLowEnergyServicePrivate();
- priv->uuid = includedUuid;
- priv->setController(this);
-
- includedPointer = QSharedPointer<QLowEnergyServicePrivate>(priv);
- serviceList.insert(includedUuid, includedPointer);
- }
- includedPointer->type |= QLowEnergyService::IncludedService;
- servicePointer->includedServices.append(includedUuid);
-
- obtainIncludedServices(includedPointer, includedService);
-
- emit q->serviceDiscovered(includedUuid);
- }
-}
-
-HRESULT QLowEnergyControllerPrivateWinRTNew::onServiceDiscoveryFinished(ABI::Windows::Foundation::IAsyncOperation<GattDeviceServicesResult *> *op, AsyncStatus status)
-{
- Q_Q(QLowEnergyController);
- if (status != AsyncStatus::Completed) {
- qCDebug(QT_BT_WINRT) << "Could not obtain services";
- return S_OK;
- }
- ComPtr<IGattDeviceServicesResult> result;
- ComPtr<IVectorView<GattDeviceService *>> deviceServices;
- HRESULT hr = op->GetResults(&result);
- CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not obtain service discovery result",
- return S_OK);
- GattCommunicationStatus commStatus;
- hr = result->get_Status(&commStatus);
- CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not obtain service discovery status",
- return S_OK);
- if (commStatus != GattCommunicationStatus_Success)
- return S_OK;
-
- hr = result->get_Services(&deviceServices);
- CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not obtain service list",
- return S_OK);
-
- uint serviceCount;
- hr = deviceServices->get_Size(&serviceCount);
- CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not obtain service list size",
- return S_OK);
- for (uint i = 0; i < serviceCount; ++i) {
- ComPtr<IGattDeviceService> deviceService;
- hr = deviceServices->GetAt(i, &deviceService);
- WARN_AND_CONTINUE_IF_FAILED(hr, "Could not obtain service");
- GUID guuid;
- hr = deviceService->get_Uuid(&guuid);
- WARN_AND_CONTINUE_IF_FAILED(hr, "Could not obtain service's Uuid");
- const QBluetoothUuid service(guuid);
-
- qCDebug(QT_BT_WINRT_SERVICE_THREAD) << __FUNCTION__
- << "Changing service pointer from thread"
- << QThread::currentThread();
- QSharedPointer<QLowEnergyServicePrivate> pointer;
- if (serviceList.contains(service)) {
- pointer = serviceList.value(service);
- } else {
- QLowEnergyServicePrivate *priv = new QLowEnergyServicePrivate();
- priv->uuid = service;
- priv->setController(this);
-
- pointer = QSharedPointer<QLowEnergyServicePrivate>(priv);
- serviceList.insert(service, pointer);
- }
- pointer->type |= QLowEnergyService::PrimaryService;
-
- obtainIncludedServices(pointer, deviceService);
-
- emit q->serviceDiscovered(service);
- }
-
- setState(QLowEnergyController::DiscoveredState);
- emit q->discoveryFinished();
-
- return S_OK;
-}
-
-void QLowEnergyControllerPrivateWinRTNew::discoverServices()
-{
- qCDebug(QT_BT_WINRT) << "Service discovery initiated";
-
- ComPtr<IBluetoothLEDevice3> device3;
- HRESULT hr = mDevice.As(&device3);
- CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not cast device", return);
- ComPtr<IAsyncOperation<GenericAttributeProfile::GattDeviceServicesResult *>> asyncResult;
- hr = device3->GetGattServicesAsync(&asyncResult);
- CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not obtain services", return);
- hr = QEventDispatcherWinRT::runOnXamlThread( [asyncResult, this] () {
- HRESULT hr = asyncResult->put_Completed(
- Callback<IAsyncOperationCompletedHandler<GenericAttributeProfile::GattDeviceServicesResult *>>(
- this, &QLowEnergyControllerPrivateWinRTNew::onServiceDiscoveryFinished).Get());
- CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not register service discovery callback",
- return S_OK)
- return hr;
- });
- CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not run registration in Xaml thread",
- return)
-}
-
-void QLowEnergyControllerPrivateWinRTNew::discoverServiceDetails(const QBluetoothUuid &service)
-{
- qCDebug(QT_BT_WINRT) << __FUNCTION__ << service;
- if (!serviceList.contains(service)) {
- qCWarning(QT_BT_WINRT) << "Discovery done of unknown service:"
- << service.toString();
- return;
- }
-
- ComPtr<IGattDeviceService> deviceService = getNativeService(service);
- if (!deviceService) {
- qCDebug(QT_BT_WINRT) << "Could not obtain native service for uuid " << service;
- return;
- }
-
- //update service data
- QSharedPointer<QLowEnergyServicePrivate> pointer = serviceList.value(service);
- qCDebug(QT_BT_WINRT_SERVICE_THREAD) << __FUNCTION__ << "Changing service pointer from thread"
- << QThread::currentThread();
- pointer->setState(QLowEnergyService::DiscoveringServices);
- ComPtr<IGattDeviceService3> deviceService3;
- HRESULT hr = deviceService.As(&deviceService3);
- CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not cast service",
- pointer, QLowEnergyService::UnknownError, return)
- ComPtr<IAsyncOperation<GattDeviceServicesResult *>> op;
- hr = deviceService3->GetIncludedServicesAsync(&op);
- CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not obtain included service list",
- pointer, QLowEnergyService::UnknownError, return)
- ComPtr<IGattDeviceServicesResult> result;
- hr = QWinRTFunctions::await(op, result.GetAddressOf());
- CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not await service operation",
- pointer, QLowEnergyService::UnknownError, return)
- GattCommunicationStatus status;
- hr = result->get_Status(&status);
- if (FAILED(hr) || status != GattCommunicationStatus_Success) {
- qCDebug(QT_BT_WINRT) << "Obtaining list of included services failed";
- pointer->setError(QLowEnergyService::UnknownError);
- return;
- }
- ComPtr<IVectorView<GattDeviceService *>> deviceServices;
- hr = result->get_Services(&deviceServices);
- CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not obtain service list from result",
- pointer, QLowEnergyService::UnknownError, return)
- uint serviceCount;
- hr = deviceServices->get_Size(&serviceCount);
- CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not obtain included service list's size",
- pointer, QLowEnergyService::UnknownError, return)
- for (uint i = 0; i < serviceCount; ++i) {
- ComPtr<IGattDeviceService> includedService;
- hr = deviceServices->GetAt(i, &includedService);
- WARN_AND_CONTINUE_IF_FAILED(hr, "Could not obtain service from list")
- GUID guuid;
- hr = includedService->get_Uuid(&guuid);
- WARN_AND_CONTINUE_IF_FAILED(hr, "Could not obtain service Uuid")
-
- const QBluetoothUuid service(guuid);
- if (service.isNull()) {
- qCDebug(QT_BT_WINRT) << "Could not find service";
- continue;
- }
-
- pointer->includedServices.append(service);
-
- // update the type of the included service
- QSharedPointer<QLowEnergyServicePrivate> otherService = serviceList.value(service);
- if (!otherService.isNull())
- otherService->type |= QLowEnergyService::IncludedService;
- }
-
- QWinRTLowEnergyServiceHandlerNew *worker
- = new QWinRTLowEnergyServiceHandlerNew(service, deviceService3);
- QThread *thread = new QThread;
- worker->moveToThread(thread);
- connect(thread, &QThread::started, worker, &QWinRTLowEnergyServiceHandlerNew::obtainCharList);
- connect(thread, &QThread::finished, thread, &QObject::deleteLater);
- connect(thread, &QThread::finished, worker, &QObject::deleteLater);
- connect(worker, &QWinRTLowEnergyServiceHandlerNew::errorOccured,
- this, &QLowEnergyControllerPrivateWinRTNew::handleServiceHandlerError);
- connect(worker, &QWinRTLowEnergyServiceHandlerNew::charListObtained,
- [this, thread](const QBluetoothUuid &service, QHash<QLowEnergyHandle,
- QLowEnergyServicePrivate::CharData> charList, QVector<QBluetoothUuid> indicateChars,
- QLowEnergyHandle startHandle, QLowEnergyHandle endHandle) {
- if (!serviceList.contains(service)) {
- qCWarning(QT_BT_WINRT) << "Discovery done of unknown service:"
- << service.toString();
- return;
- }
-
- QSharedPointer<QLowEnergyServicePrivate> pointer = serviceList.value(service);
- pointer->startHandle = startHandle;
- pointer->endHandle = endHandle;
- pointer->characteristicList = charList;
-
- HRESULT hr;
- hr = QEventDispatcherWinRT::runOnXamlThread([indicateChars, service, this]() {
- for (const QBluetoothUuid &indicateChar : qAsConst(indicateChars))
- registerForValueChanges(service, indicateChar);
- return S_OK;
- });
- CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not register for value changes in Xaml thread",
- pointer, QLowEnergyService::UnknownError, return)
-
- pointer->setState(QLowEnergyService::ServiceDiscovered);
- thread->exit(0);
- });
- thread->start();
-}
-
-void QLowEnergyControllerPrivateWinRTNew::startAdvertising(
- const QLowEnergyAdvertisingParameters &,
- const QLowEnergyAdvertisingData &,
- const QLowEnergyAdvertisingData &)
-{
- setError(QLowEnergyController::AdvertisingError);
- Q_UNIMPLEMENTED();
-}
-
-void QLowEnergyControllerPrivateWinRTNew::stopAdvertising()
-{
- Q_UNIMPLEMENTED();
-}
-
-void QLowEnergyControllerPrivateWinRTNew::requestConnectionUpdate(const QLowEnergyConnectionParameters &)
-{
- Q_UNIMPLEMENTED();
-}
-
-void QLowEnergyControllerPrivateWinRTNew::readCharacteristic(
- const QSharedPointer<QLowEnergyServicePrivate> service,
- const QLowEnergyHandle charHandle)
-{
- qCDebug(QT_BT_WINRT) << __FUNCTION__ << service << charHandle;
- qCDebug(QT_BT_WINRT_SERVICE_THREAD) << __FUNCTION__ << "Changing service pointer from thread"
- << QThread::currentThread();
- Q_ASSERT(!service.isNull());
- if (role == QLowEnergyController::PeripheralRole) {
- service->setError(QLowEnergyService::CharacteristicReadError);
- Q_UNIMPLEMENTED();
- return;
- }
-
- if (!service->characteristicList.contains(charHandle)) {
- qCDebug(QT_BT_WINRT) << charHandle << "could not be found in service" << service->uuid;
- service->setError(QLowEnergyService::CharacteristicReadError);
- return;
- }
-
- HRESULT hr;
- hr = QEventDispatcherWinRT::runOnXamlThread([charHandle, service, this]() {
- const QLowEnergyServicePrivate::CharData charData = service->characteristicList.value(charHandle);
- if (!(charData.properties & QLowEnergyCharacteristic::Read))
- qCDebug(QT_BT_WINRT) << "Read flag is not set for characteristic" << charData.uuid;
-
- ComPtr<IGattCharacteristic> characteristic = getNativeCharacteristic(service->uuid, charData.uuid);
- if (!characteristic) {
- qCDebug(QT_BT_WINRT) << "Could not obtain native characteristic" << charData.uuid
- << "from service" << service->uuid;
- service->setError(QLowEnergyService::CharacteristicReadError);
- return S_OK;
- }
- ComPtr<IAsyncOperation<GattReadResult*>> readOp;
- HRESULT hr = characteristic->ReadValueWithCacheModeAsync(BluetoothCacheMode_Uncached, &readOp);
- CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not read characteristic",
- service, QLowEnergyService::CharacteristicReadError, return S_OK)
- auto readCompletedLambda = [charData, charHandle, service]
- (IAsyncOperation<GattReadResult*> *op, AsyncStatus status)
- {
- if (status == AsyncStatus::Canceled || status == AsyncStatus::Error) {
- qCDebug(QT_BT_WINRT) << "Characteristic" << charHandle << "read operation failed.";
- service->setError(QLowEnergyService::CharacteristicReadError);
- return S_OK;
- }
- ComPtr<IGattReadResult> characteristicValue;
- HRESULT hr;
- hr = op->GetResults(&characteristicValue);
- CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not obtain result for characteristic",
- service, QLowEnergyService::CharacteristicReadError, return S_OK)
-
- const QByteArray value = byteArrayFromGattResult(characteristicValue);
- QLowEnergyServicePrivate::CharData charData = service->characteristicList.value(charHandle);
- charData.value = value;
- service->characteristicList.insert(charHandle, charData);
- emit service->characteristicRead(QLowEnergyCharacteristic(service, charHandle), value);
- return S_OK;
- };
- hr = readOp->put_Completed(Callback<IAsyncOperationCompletedHandler<GattReadResult *>>(
- readCompletedLambda).Get());
- CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not register characteristic read callback",
- service, QLowEnergyService::CharacteristicReadError, return S_OK)
- return S_OK;
- });
- CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not run registration on Xaml thread",
- service, QLowEnergyService::CharacteristicReadError, return)
-}
-
-void QLowEnergyControllerPrivateWinRTNew::readDescriptor(
- const QSharedPointer<QLowEnergyServicePrivate> service,
- const QLowEnergyHandle charHandle,
- const QLowEnergyHandle descHandle)
-{
- qCDebug(QT_BT_WINRT) << __FUNCTION__ << service << charHandle << descHandle;
- qCDebug(QT_BT_WINRT_SERVICE_THREAD) << __FUNCTION__ << "Changing service pointer from thread"
- << QThread::currentThread();
- Q_ASSERT(!service.isNull());
- if (role == QLowEnergyController::PeripheralRole) {
- service->setError(QLowEnergyService::DescriptorReadError);
- Q_UNIMPLEMENTED();
- return;
- }
-
- if (!service->characteristicList.contains(charHandle)) {
- qCDebug(QT_BT_WINRT) << "Descriptor" << descHandle << "in characteristic" << charHandle
- << "cannot be found in service" << service->uuid;
- service->setError(QLowEnergyService::DescriptorReadError);
- return;
- }
-
- HRESULT hr;
- hr = QEventDispatcherWinRT::runOnXamlThread([charHandle, descHandle, service, this]() {
- const QLowEnergyServicePrivate::CharData charData = service->characteristicList.value(charHandle);
- ComPtr<IGattCharacteristic> characteristic = getNativeCharacteristic(service->uuid, charData.uuid);
- if (!characteristic) {
- qCDebug(QT_BT_WINRT) << "Could not obtain native characteristic" << charData.uuid
- << "from service" << service->uuid;
- service->setError(QLowEnergyService::DescriptorReadError);
- return S_OK;
- }
-
- // Get native descriptor
- if (!charData.descriptorList.contains(descHandle))
- qCDebug(QT_BT_WINRT) << "Descriptor" << descHandle << "cannot be found in characteristic" << charHandle;
- const QLowEnergyServicePrivate::DescData descData = charData.descriptorList.value(descHandle);
- const QBluetoothUuid descUuid = descData.uuid;
- if (descUuid == QBluetoothUuid(QBluetoothUuid::ClientCharacteristicConfiguration)) {
- ComPtr<IAsyncOperation<ClientCharConfigDescriptorResult *>> readOp;
- HRESULT hr = characteristic->ReadClientCharacteristicConfigurationDescriptorAsync(&readOp);
- CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not read client characteristic configuration",
- service, QLowEnergyService::DescriptorReadError, return S_OK)
- auto readCompletedLambda = [charHandle, descHandle, service]
- (IAsyncOperation<ClientCharConfigDescriptorResult *> *op, AsyncStatus status)
- {
- if (status == AsyncStatus::Canceled || status == AsyncStatus::Error) {
- qCDebug(QT_BT_WINRT) << "Descriptor" << descHandle << "read operation failed";
- service->setError(QLowEnergyService::DescriptorReadError);
- return S_OK;
- }
- ComPtr<IClientCharConfigDescriptorResult> iValue;
- HRESULT hr;
- hr = op->GetResults(&iValue);
- CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not obtain result for descriptor",
- service, QLowEnergyService::DescriptorReadError, return S_OK)
- GattClientCharacteristicConfigurationDescriptorValue value;
- hr = iValue->get_ClientCharacteristicConfigurationDescriptor(&value);
- CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not obtain value for descriptor",
- service, QLowEnergyService::DescriptorReadError, return S_OK)
- quint16 result = 0;
- bool correct = false;
- if (value & GattClientCharacteristicConfigurationDescriptorValue_Indicate) {
- result |= QLowEnergyCharacteristic::Indicate;
- correct = true;
- }
- if (value & GattClientCharacteristicConfigurationDescriptorValue_Notify) {
- result |= QLowEnergyCharacteristic::Notify;
- correct = true;
- }
- if (value == GattClientCharacteristicConfigurationDescriptorValue_None)
- correct = true;
- if (!correct) {
- qCDebug(QT_BT_WINRT) << "Descriptor" << descHandle
- << "read operation failed. Obtained unexpected value.";
- service->setError(QLowEnergyService::DescriptorReadError);
- return S_OK;
- }
- QLowEnergyServicePrivate::DescData descData;
- descData.uuid = QBluetoothUuid::ClientCharacteristicConfiguration;
- descData.value = QByteArray(2, Qt::Uninitialized);
- qToLittleEndian(result, descData.value.data());
- service->characteristicList[charHandle].descriptorList[descHandle] = descData;
- emit service->descriptorRead(QLowEnergyDescriptor(service, charHandle, descHandle),
- descData.value);
- return S_OK;
- };
- hr = readOp->put_Completed(
- Callback<IAsyncOperationCompletedHandler<ClientCharConfigDescriptorResult *>>(
- readCompletedLambda).Get());
- CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not register descriptor read callback",
- service, QLowEnergyService::DescriptorReadError, return S_OK)
- return S_OK;
- } else {
- ComPtr<IGattCharacteristic3> characteristic3;
- HRESULT hr = characteristic.As(&characteristic3);
- CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not cast characteristic",
- service, QLowEnergyService::DescriptorReadError, return S_OK)
- ComPtr<IAsyncOperation<GattDescriptorsResult *>> op;
- hr = characteristic3->GetDescriptorsForUuidAsync(descData.uuid, &op);
- CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not obtain descriptor for uuid",
- service, QLowEnergyService::DescriptorReadError, return S_OK)
- ComPtr<IGattDescriptorsResult> result;
- hr = QWinRTFunctions::await(op, result.GetAddressOf(), QWinRTFunctions::ProcessMainThreadEvents, 5000);
- CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not await descritpor read result",
- service, QLowEnergyService::DescriptorReadError, return S_OK)
-
- GattCommunicationStatus commStatus;
- hr = result->get_Status(&commStatus);
- if (FAILED(hr) || commStatus != GattCommunicationStatus_Success) {
- qErrnoWarning("Could not obtain list of descriptors");
- service->setError(QLowEnergyService::DescriptorReadError);
- return S_OK;
- }
-
- ComPtr<IVectorView<GattDescriptor *>> descriptors;
- hr = result->get_Descriptors(&descriptors);
- CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not obtain descriptor list",
- service, QLowEnergyService::DescriptorReadError, return S_OK)
- uint size;
- hr = descriptors->get_Size(&size);
- CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not await descritpor list's size",
- service, QLowEnergyService::DescriptorReadError, return S_OK)
- if (size == 0) {
- qCWarning(QT_BT_WINRT) << "No descriptor with uuid" << descData.uuid << "was found.";
- service->setError(QLowEnergyService::DescriptorReadError);
- return S_OK;
- } else if (size > 1) {
- qCWarning(QT_BT_WINRT) << "There is more than 1 descriptor with uuid" << descData.uuid;
- }
-
- ComPtr<IGattDescriptor> descriptor;
- hr = descriptors->GetAt(0, &descriptor);
- CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not obtain descritpor from list",
- service, QLowEnergyService::DescriptorReadError, return S_OK)
- ComPtr<IAsyncOperation<GattReadResult*>> readOp;
- hr = descriptor->ReadValueWithCacheModeAsync(BluetoothCacheMode_Uncached, &readOp);
- CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not read descriptor value",
- service, QLowEnergyService::DescriptorReadError, return S_OK)
- auto readCompletedLambda = [charHandle, descHandle, descUuid, service]
- (IAsyncOperation<GattReadResult*> *op, AsyncStatus status)
- {
- if (status == AsyncStatus::Canceled || status == AsyncStatus::Error) {
- qCDebug(QT_BT_WINRT) << "Descriptor" << descHandle << "read operation failed";
- service->setError(QLowEnergyService::DescriptorReadError);
- return S_OK;
- }
- ComPtr<IGattReadResult> descriptorValue;
- HRESULT hr;
- hr = op->GetResults(&descriptorValue);
- if (FAILED(hr)) {
- qCDebug(QT_BT_WINRT) << "Could not obtain result for descriptor" << descHandle;
- service->setError(QLowEnergyService::DescriptorReadError);
- return S_OK;
- }
- QLowEnergyServicePrivate::DescData descData;
- descData.uuid = descUuid;
- if (descData.uuid == QBluetoothUuid::CharacteristicUserDescription)
- descData.value = byteArrayFromGattResult(descriptorValue, true);
- else
- descData.value = byteArrayFromGattResult(descriptorValue);
- service->characteristicList[charHandle].descriptorList[descHandle] = descData;
- emit service->descriptorRead(QLowEnergyDescriptor(service, charHandle, descHandle),
- descData.value);
- return S_OK;
- };
- hr = readOp->put_Completed(Callback<IAsyncOperationCompletedHandler<GattReadResult *>>(
- readCompletedLambda).Get());
- CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not register descriptor read callback",
- service, QLowEnergyService::DescriptorReadError, return S_OK)
- return S_OK;
- }
- });
- CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not run registration on Xaml thread",
- service, QLowEnergyService::DescriptorReadError, return)
-}
-
-void QLowEnergyControllerPrivateWinRTNew::writeCharacteristic(
- const QSharedPointer<QLowEnergyServicePrivate> service,
- const QLowEnergyHandle charHandle,
- const QByteArray &newValue,
- QLowEnergyService::WriteMode mode)
-{
- qCDebug(QT_BT_WINRT) << __FUNCTION__ << service << charHandle << newValue << mode;
- qCDebug(QT_BT_WINRT_SERVICE_THREAD) << __FUNCTION__ << "Changing service pointer from thread"
- << QThread::currentThread();
- Q_ASSERT(!service.isNull());
- if (role == QLowEnergyController::PeripheralRole) {
- service->setError(QLowEnergyService::CharacteristicWriteError);
- Q_UNIMPLEMENTED();
- return;
- }
- if (!service->characteristicList.contains(charHandle)) {
- qCDebug(QT_BT_WINRT) << "Characteristic" << charHandle << "cannot be found in service"
- << service->uuid;
- service->setError(QLowEnergyService::CharacteristicWriteError);
- return;
- }
-
- QLowEnergyServicePrivate::CharData charData = service->characteristicList.value(charHandle);
- const bool writeWithResponse = mode == QLowEnergyService::WriteWithResponse;
- if (!(charData.properties & (writeWithResponse ? QLowEnergyCharacteristic::Write
- : QLowEnergyCharacteristic::WriteNoResponse)))
- qCDebug(QT_BT_WINRT) << "Write flag is not set for characteristic" << charHandle;
-
- HRESULT hr;
- hr = QEventDispatcherWinRT::runOnXamlThread([charData, charHandle, this, service, newValue,
- writeWithResponse]() {
- ComPtr<IGattCharacteristic> characteristic = getNativeCharacteristic(service->uuid,
- charData.uuid);
- if (!characteristic) {
- qCDebug(QT_BT_WINRT) << "Could not obtain native characteristic" << charData.uuid
- << "from service" << service->uuid;
- service->setError(QLowEnergyService::CharacteristicWriteError);
- return S_OK;
- }
- ComPtr<ABI::Windows::Storage::Streams::IBufferFactory> bufferFactory;
- HRESULT hr = GetActivationFactory(
- HStringReference(RuntimeClass_Windows_Storage_Streams_Buffer).Get(),
- &bufferFactory);
- CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not obtain buffer factory",
- service, QLowEnergyService::CharacteristicWriteError, return S_OK)
- ComPtr<ABI::Windows::Storage::Streams::IBuffer> buffer;
- const quint32 length = quint32(newValue.length());
- hr = bufferFactory->Create(length, &buffer);
- CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not create buffer",
- service, QLowEnergyService::CharacteristicWriteError, return S_OK)
- hr = buffer->put_Length(length);
- CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not set buffer length",
- service, QLowEnergyService::CharacteristicWriteError, return S_OK)
- ComPtr<Windows::Storage::Streams::IBufferByteAccess> byteAccess;
- hr = buffer.As(&byteAccess);
- CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not cast buffer",
- service, QLowEnergyService::CharacteristicWriteError, return S_OK)
- byte *bytes;
- hr = byteAccess->Buffer(&bytes);
- CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not set buffer",
- service, QLowEnergyService::CharacteristicWriteError, return S_OK)
- memcpy(bytes, newValue, length);
- ComPtr<IAsyncOperation<GattCommunicationStatus>> writeOp;
- GattWriteOption option = writeWithResponse ? GattWriteOption_WriteWithResponse
- : GattWriteOption_WriteWithoutResponse;
- hr = characteristic->WriteValueWithOptionAsync(buffer.Get(), option, &writeOp);
- CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could write characteristic",
- service, QLowEnergyService::CharacteristicWriteError, return S_OK)
- QPointer<QLowEnergyControllerPrivateWinRTNew> thisPtr(this);
- auto writeCompletedLambda = [charData, charHandle, newValue, service, writeWithResponse, thisPtr]
- (IAsyncOperation<GattCommunicationStatus> *op, AsyncStatus status)
- {
- if (status == AsyncStatus::Canceled || status == AsyncStatus::Error) {
- qCDebug(QT_BT_WINRT) << "Characteristic" << charHandle << "write operation failed";
- service->setError(QLowEnergyService::CharacteristicWriteError);
- return S_OK;
- }
- GattCommunicationStatus result;
- HRESULT hr;
- hr = op->GetResults(&result);
- if (hr == E_BLUETOOTH_ATT_INVALID_ATTRIBUTE_VALUE_LENGTH) {
- qCDebug(QT_BT_WINRT) << "Characteristic" << charHandle
- << "write operation was tried with invalid value length";
- service->setError(QLowEnergyService::CharacteristicWriteError);
- return S_OK;
- }
- CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not obtain characteristic write result",
- service, QLowEnergyService::CharacteristicWriteError, return S_OK)
- if (result != GattCommunicationStatus_Success) {
- qCDebug(QT_BT_WINRT) << "Characteristic" << charHandle << "write operation failed";
- service->setError(QLowEnergyService::CharacteristicWriteError);
- return S_OK;
- }
- // only update cache when property is readable. Otherwise it remains
- // empty.
- if (charData.properties & QLowEnergyCharacteristic::Read)
- thisPtr->updateValueOfCharacteristic(charHandle, newValue, false);
- if (writeWithResponse)
- emit service->characteristicWritten(QLowEnergyCharacteristic(service, charHandle),
- newValue);
- return S_OK;
- };
- hr = writeOp->put_Completed(
- Callback<IAsyncOperationCompletedHandler<GattCommunicationStatus>>(
- writeCompletedLambda).Get());
- CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not register characteristic write callback",
- service, QLowEnergyService::CharacteristicWriteError, return S_OK)
- return S_OK;
- });
- CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not run registration on Xaml thread",
- service, QLowEnergyService::CharacteristicWriteError, return)
-}
-
-void QLowEnergyControllerPrivateWinRTNew::writeDescriptor(
- const QSharedPointer<QLowEnergyServicePrivate> service,
- const QLowEnergyHandle charHandle,
- const QLowEnergyHandle descHandle,
- const QByteArray &newValue)
-{
- qCDebug(QT_BT_WINRT) << __FUNCTION__ << service << charHandle << descHandle << newValue;
- qCDebug(QT_BT_WINRT_SERVICE_THREAD) << __FUNCTION__ << "Changing service pointer from thread"
- << QThread::currentThread();
- Q_ASSERT(!service.isNull());
- if (role == QLowEnergyController::PeripheralRole) {
- service->setError(QLowEnergyService::DescriptorWriteError);
- Q_UNIMPLEMENTED();
- return;
- }
-
- if (!service->characteristicList.contains(charHandle)) {
- qCDebug(QT_BT_WINRT) << "Descriptor" << descHandle << "in characteristic" << charHandle
- << "could not be found in service" << service->uuid;
- service->setError(QLowEnergyService::DescriptorWriteError);
- return;
- }
-
- HRESULT hr;
- hr = QEventDispatcherWinRT::runOnXamlThread([charHandle, descHandle, this, service, newValue]() {
- const QLowEnergyServicePrivate::CharData charData = service->characteristicList.value(charHandle);
- ComPtr<IGattCharacteristic> characteristic = getNativeCharacteristic(service->uuid, charData.uuid);
- if (!characteristic) {
- qCDebug(QT_BT_WINRT) << "Could not obtain native characteristic" << charData.uuid
- << "from service" << service->uuid;
- service->setError(QLowEnergyService::DescriptorWriteError);
- return S_OK;
- }
-
- // Get native descriptor
- if (!charData.descriptorList.contains(descHandle))
- qCDebug(QT_BT_WINRT) << "Descriptor" << descHandle << "could not be found in Characteristic"
- << charHandle;
-
- QLowEnergyServicePrivate::DescData descData = charData.descriptorList.value(descHandle);
- if (descData.uuid == QBluetoothUuid(QBluetoothUuid::ClientCharacteristicConfiguration)) {
- GattClientCharacteristicConfigurationDescriptorValue value;
- quint16 intValue = qFromLittleEndian<quint16>(newValue);
- if (intValue & GattClientCharacteristicConfigurationDescriptorValue_Indicate
- && intValue & GattClientCharacteristicConfigurationDescriptorValue_Notify) {
- qCWarning(QT_BT_WINRT) << "Setting both Indicate and Notify is not supported on WinRT";
- value = GattClientCharacteristicConfigurationDescriptorValue(
- (GattClientCharacteristicConfigurationDescriptorValue_Indicate
- | GattClientCharacteristicConfigurationDescriptorValue_Notify));
- } else if (intValue & GattClientCharacteristicConfigurationDescriptorValue_Indicate) {
- value = GattClientCharacteristicConfigurationDescriptorValue_Indicate;
- } else if (intValue & GattClientCharacteristicConfigurationDescriptorValue_Notify) {
- value = GattClientCharacteristicConfigurationDescriptorValue_Notify;
- } else if (intValue == 0) {
- value = GattClientCharacteristicConfigurationDescriptorValue_None;
- } else {
- qCDebug(QT_BT_WINRT) << "Descriptor" << descHandle
- << "write operation failed: Invalid value";
- service->setError(QLowEnergyService::DescriptorWriteError);
- return S_OK;
- }
- ComPtr<IAsyncOperation<enum GattCommunicationStatus>> writeOp;
- HRESULT hr = characteristic->WriteClientCharacteristicConfigurationDescriptorAsync(value, &writeOp);
- CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not write client characteristic configuration",
- service, QLowEnergyService::DescriptorWriteError, return S_OK)
- QPointer<QLowEnergyControllerPrivateWinRTNew> thisPtr(this);
- auto writeCompletedLambda = [charHandle, descHandle, newValue, service, thisPtr]
- (IAsyncOperation<GattCommunicationStatus> *op, AsyncStatus status)
- {
- if (status == AsyncStatus::Canceled || status == AsyncStatus::Error) {
- qCDebug(QT_BT_WINRT) << "Descriptor" << descHandle << "write operation failed";
- service->setError(QLowEnergyService::DescriptorWriteError);
- return S_OK;
- }
- GattCommunicationStatus result;
- HRESULT hr;
- hr = op->GetResults(&result);
- CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not obtain result for descriptor",
- service, QLowEnergyService::DescriptorWriteError, return S_OK)
- if (result != GattCommunicationStatus_Success) {
- qCWarning(QT_BT_WINRT) << "Descriptor" << descHandle << "write operation failed";
- service->setError(QLowEnergyService::DescriptorWriteError);
- return S_OK;
- }
- thisPtr->updateValueOfDescriptor(charHandle, descHandle, newValue, false);
- emit service->descriptorWritten(QLowEnergyDescriptor(service, charHandle, descHandle),
- newValue);
- return S_OK;
- };
- hr = writeOp->put_Completed(
- Callback<IAsyncOperationCompletedHandler<GattCommunicationStatus >>(
- writeCompletedLambda).Get());
- CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not register descriptor write callback",
- service, QLowEnergyService::DescriptorWriteError, return S_OK)
- } else {
- ComPtr<IGattCharacteristic3> characteristic3;
- HRESULT hr = characteristic.As(&characteristic3);
- CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not cast characteristic",
- service, QLowEnergyService::DescriptorWriteError, return S_OK)
- ComPtr<IAsyncOperation<GattDescriptorsResult *>> op;
- hr = characteristic3->GetDescriptorsForUuidAsync(descData.uuid, &op);
- CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not obtain descriptor from Uuid",
- service, QLowEnergyService::DescriptorWriteError, return S_OK)
- ComPtr<IGattDescriptorsResult> result;
- hr = QWinRTFunctions::await(op, result.GetAddressOf(), QWinRTFunctions::ProcessMainThreadEvents, 5000);
- CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not await descriptor operation",
- service, QLowEnergyService::DescriptorWriteError, return S_OK)
- GattCommunicationStatus commStatus;
- hr = result->get_Status(&commStatus);
- if (FAILED(hr) || commStatus != GattCommunicationStatus_Success) {
- qCWarning(QT_BT_WINRT) << "Descriptor operation failed";
- service->setError(QLowEnergyService::DescriptorWriteError);
- return S_OK;
- }
- ComPtr<IVectorView<GattDescriptor *>> descriptors;
- hr = result->get_Descriptors(&descriptors);
- CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not obtain list of descriptors",
- service, QLowEnergyService::DescriptorWriteError, return S_OK)
- uint size;
- hr = descriptors->get_Size(&size);
- CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not obtain list of descriptors' size",
- service, QLowEnergyService::DescriptorWriteError, return S_OK)
- if (size == 0) {
- qCWarning(QT_BT_WINRT) << "No descriptor with uuid" << descData.uuid << "was found.";
- return S_OK;
- } else if (size > 1) {
- qCWarning(QT_BT_WINRT) << "There is more than 1 descriptor with uuid" << descData.uuid;
- }
- ComPtr<IGattDescriptor> descriptor;
- hr = descriptors->GetAt(0, &descriptor);
- CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not obtain descriptor",
- service, QLowEnergyService::DescriptorWriteError, return S_OK)
- ComPtr<ABI::Windows::Storage::Streams::IBufferFactory> bufferFactory;
- hr = GetActivationFactory(
- HStringReference(RuntimeClass_Windows_Storage_Streams_Buffer).Get(),
- &bufferFactory);
- CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not obtain buffer factory",
- service, QLowEnergyService::DescriptorWriteError, return S_OK)
- ComPtr<ABI::Windows::Storage::Streams::IBuffer> buffer;
- const quint32 length = quint32(newValue.length());
- hr = bufferFactory->Create(length, &buffer);
- CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not create buffer",
- service, QLowEnergyService::DescriptorWriteError, return S_OK)
- hr = buffer->put_Length(length);
- CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not set buffer length",
- service, QLowEnergyService::DescriptorWriteError, return S_OK)
- ComPtr<Windows::Storage::Streams::IBufferByteAccess> byteAccess;
- hr = buffer.As(&byteAccess);
- CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not cast buffer",
- service, QLowEnergyService::DescriptorWriteError, return S_OK)
- byte *bytes;
- hr = byteAccess->Buffer(&bytes);
- CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not set buffer",
- service, QLowEnergyService::DescriptorWriteError, return S_OK)
- memcpy(bytes, newValue, length);
- ComPtr<IAsyncOperation<GattCommunicationStatus>> writeOp;
- hr = descriptor->WriteValueAsync(buffer.Get(), &writeOp);
- CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not write descriptor value",
- service, QLowEnergyService::DescriptorWriteError, return S_OK)
- QPointer<QLowEnergyControllerPrivateWinRTNew> thisPtr(this);
- auto writeCompletedLambda = [charHandle, descHandle, newValue, service, thisPtr]
- (IAsyncOperation<GattCommunicationStatus> *op, AsyncStatus status)
- {
- if (status == AsyncStatus::Canceled || status == AsyncStatus::Error) {
- qCDebug(QT_BT_WINRT) << "Descriptor" << descHandle << "write operation failed";
- service->setError(QLowEnergyService::DescriptorWriteError);
- return S_OK;
- }
- GattCommunicationStatus result;
- HRESULT hr;
- hr = op->GetResults(&result);
- CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not obtain result for descriptor",
- service, QLowEnergyService::DescriptorWriteError, return S_OK)
- if (result != GattCommunicationStatus_Success) {
- qCDebug(QT_BT_WINRT) << "Descriptor" << descHandle << "write operation failed";
- service->setError(QLowEnergyService::DescriptorWriteError);
- return S_OK;
- }
- thisPtr->updateValueOfDescriptor(charHandle, descHandle, newValue, false);
- emit service->descriptorWritten(QLowEnergyDescriptor(service, charHandle, descHandle),
- newValue);
- return S_OK;
- };
- hr = writeOp->put_Completed(
- Callback<IAsyncOperationCompletedHandler<GattCommunicationStatus>>(
- writeCompletedLambda).Get());
- CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not register descriptor write callback",
- service, QLowEnergyService::DescriptorWriteError, return S_OK)
- return S_OK;
- }
- return S_OK;
- });
- CHECK_HR_AND_SET_SERVICE_ERROR(hr, "Could not run registration on Xaml thread",
- service, QLowEnergyService::DescriptorWriteError, return)
-}
-
-
-void QLowEnergyControllerPrivateWinRTNew::addToGenericAttributeList(const QLowEnergyServiceData &,
- QLowEnergyHandle)
-{
- Q_UNIMPLEMENTED();
-}
-
-void QLowEnergyControllerPrivateWinRTNew::handleCharacteristicChanged(
- quint16 charHandle, const QByteArray &data)
-{
- qCDebug(QT_BT_WINRT) << __FUNCTION__ << charHandle << data;
- qCDebug(QT_BT_WINRT_SERVICE_THREAD) << __FUNCTION__ << "Changing service pointer from thread"
- << QThread::currentThread();
- QSharedPointer<QLowEnergyServicePrivate> service =
- serviceForHandle(charHandle);
- if (service.isNull())
- return;
-
- qCDebug(QT_BT_WINRT) << "Characteristic change notification" << service->uuid
- << charHandle << data.toHex();
-
- QLowEnergyCharacteristic characteristic = characteristicForHandle(charHandle);
- if (!characteristic.isValid()) {
- qCWarning(QT_BT_WINRT) << "characteristicChanged: Cannot find characteristic";
- return;
- }
-
- // only update cache when property is readable. Otherwise it remains
- // empty.
- if (characteristic.properties() & QLowEnergyCharacteristic::Read)
- updateValueOfCharacteristic(characteristic.attributeHandle(),
- data, false);
- emit service->characteristicChanged(characteristic, data);
-}
-
-void QLowEnergyControllerPrivateWinRTNew::handleServiceHandlerError(const QString &error)
-{
- if (state != QLowEnergyController::DiscoveringState)
- return;
-
- qCWarning(QT_BT_WINRT) << "Error while discovering services:" << error;
- setState(QLowEnergyController::UnconnectedState);
- setError(QLowEnergyController::ConnectionError);
-}
-
-void QLowEnergyControllerPrivateWinRTNew::connectToPairedDevice()
-{
- Q_Q(QLowEnergyController);
- ComPtr<IBluetoothLEDevice3> device3;
- HRESULT hr = mDevice.As(&device3);
- CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not cast device", return)
- ComPtr<IAsyncOperation<GattDeviceServicesResult *>> deviceServicesOp;
- while (!mAbortPending) {
- hr = device3->GetGattServicesAsync(&deviceServicesOp);
- CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not obtain services", return)
- ComPtr<IGattDeviceServicesResult> deviceServicesResult;
- hr = QWinRTFunctions::await(deviceServicesOp, deviceServicesResult.GetAddressOf(),
- QWinRTFunctions::ProcessThreadEvents, 5000);
- CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not await services operation", return)
-
- GattCommunicationStatus commStatus;
- hr = deviceServicesResult->get_Status(&commStatus);
- if (FAILED(hr) || commStatus != GattCommunicationStatus_Success) {
- qCWarning(QT_BT_WINRT()) << "Service operation failed";
- setError(QLowEnergyController::ConnectionError);
- setState(QLowEnergyController::UnconnectedState);
- unregisterFromStatusChanges();
- return;
- }
-
- ComPtr<IVectorView <GattDeviceService *>> deviceServices;
- hr = deviceServicesResult->get_Services(&deviceServices);
- CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not obtain list of services", return)
- uint serviceCount;
- hr = deviceServices->get_Size(&serviceCount);
- CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not obtain service count", return)
-
- if (serviceCount == 0) {
- qCWarning(QT_BT_WINRT()) << "Found devices without services";
- setError(QLowEnergyController::ConnectionError);
- setState(QLowEnergyController::UnconnectedState);
- unregisterFromStatusChanges();
- return;
- }
-
- // Windows automatically connects to the device as soon as a service value is read/written.
- // Thus we read one value in order to establish the connection.
- for (uint i = 0; i < serviceCount; ++i) {
- ComPtr<IGattDeviceService> service;
- hr = deviceServices->GetAt(i, &service);
- CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not obtain service", return);
- ComPtr<IGattDeviceService3> service3;
- hr = service.As(&service3);
- CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not cast service", return);
- ComPtr<IAsyncOperation<GattCharacteristicsResult *>> characteristicsOp;
- hr = service3->GetCharacteristicsAsync(&characteristicsOp);
- CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not obtain characteristic", return);
- ComPtr<IGattCharacteristicsResult> characteristicsResult;
- hr = QWinRTFunctions::await(characteristicsOp, characteristicsResult.GetAddressOf(),
- QWinRTFunctions::ProcessThreadEvents, 5000);
- CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not await characteristic operation", return);
- GattCommunicationStatus commStatus;
- hr = characteristicsResult->get_Status(&commStatus);
- if (FAILED(hr) || commStatus != GattCommunicationStatus_Success) {
- qCWarning(QT_BT_WINRT) << "Characteristic operation failed";
- break;
- }
- ComPtr<IVectorView<GattCharacteristic *>> characteristics;
- hr = characteristicsResult->get_Characteristics(&characteristics);
- if (hr == E_ACCESSDENIED) {
- // Everything will work as expected up until this point if the manifest capabilties
- // for bluetooth LE are not set.
- qCWarning(QT_BT_WINRT) << "Could not obtain characteristic list. Please check your "
- "manifest capabilities";
- setState(QLowEnergyController::UnconnectedState);
- setError(QLowEnergyController::ConnectionError);
- unregisterFromStatusChanges();
- return;
- }
- CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not obtain characteristic list", return);
- uint characteristicsCount;
- hr = characteristics->get_Size(&characteristicsCount);
- CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not obtain characteristic list's size", return);
- for (uint j = 0; j < characteristicsCount; ++j) {
- ComPtr<IGattCharacteristic> characteristic;
- hr = characteristics->GetAt(j, &characteristic);
- CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not obtain characteristic", return);
- ComPtr<IAsyncOperation<GattReadResult *>> op;
- GattCharacteristicProperties props;
- hr = characteristic->get_CharacteristicProperties(&props);
- CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not obtain characteristic's properties", return);
- if (!(props & GattCharacteristicProperties_Read))
- continue;
- hr = characteristic->ReadValueWithCacheModeAsync(BluetoothCacheMode::BluetoothCacheMode_Uncached, &op);
- CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not read characteristic value", return);
- ComPtr<IGattReadResult> result;
- hr = QWinRTFunctions::await(op, result.GetAddressOf(), QWinRTFunctions::ProcessThreadEvents, 500);
- // E_ILLEGAL_METHOD_CALL will be the result for a device, that is not reachable at
- // the moment. In this case we should jump back into the outer loop and keep trying.
- if (hr == E_ILLEGAL_METHOD_CALL)
- break;
- CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not await characteristic read", return);
- ComPtr<ABI::Windows::Storage::Streams::IBuffer> buffer;
- hr = result->get_Value(&buffer);
- CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not obtain characteristic value", return);
- if (!buffer) {
- qCDebug(QT_BT_WINRT) << "Problem reading value";
- break;
- }
-
- setState(QLowEnergyController::ConnectedState);
- emit q->connected();
- if (!registerForStatusChanges()) {
- setError(QLowEnergyController::ConnectionError);
- setState(QLowEnergyController::UnconnectedState);
- return;
- }
- return;
- }
- }
- }
-}
-
-void QLowEnergyControllerPrivateWinRTNew::connectToUnpairedDevice()
-{
- if (!registerForStatusChanges()) {
- setError(QLowEnergyController::ConnectionError);
- setState(QLowEnergyController::UnconnectedState);
- return;
- }
- ComPtr<IBluetoothLEDevice3> device3;
- HRESULT hr = mDevice.As(&device3);
- CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not cast device", return)
- ComPtr<IGattDeviceServicesResult> deviceServicesResult;
- while (!mAbortPending) {
- ComPtr<IAsyncOperation<GattDeviceServicesResult *>> deviceServicesOp;
- hr = device3->GetGattServicesAsync(&deviceServicesOp);
- CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not obtain services", return)
- hr = QWinRTFunctions::await(deviceServicesOp, deviceServicesResult.GetAddressOf(),
- QWinRTFunctions::ProcessMainThreadEvents);
- CHECK_FOR_DEVICE_CONNECTION_ERROR(hr, "Could not await services operation", return)
-
- GattCommunicationStatus commStatus;
- hr = deviceServicesResult->get_Status(&commStatus);
- if (commStatus == GattCommunicationStatus_Unreachable)
- continue;
-
- if (FAILED(hr) || commStatus != GattCommunicationStatus_Success) {
- qCWarning(QT_BT_WINRT()) << "Service operation failed";
- setError(QLowEnergyController::ConnectionError);
- setState(QLowEnergyController::UnconnectedState);
- unregisterFromStatusChanges();
- return;
- }
-
- break;
- }
-}
-
-QT_END_NAMESPACE
-
-#include "qlowenergycontroller_winrt_new.moc"
diff --git a/src/bluetooth/qlowenergycontroller_winrt_new_p.h b/src/bluetooth/qlowenergycontroller_winrt_new_p.h
deleted file mode 100644
index c31408be..00000000
--- a/src/bluetooth/qlowenergycontroller_winrt_new_p.h
+++ /dev/null
@@ -1,181 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QLOWENERGYCONTROLLERPRIVATEWINRT_NEW_P_H
-#define QLOWENERGYCONTROLLERPRIVATEWINRT_NEW_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <qglobal.h>
-#include <QtCore/QQueue>
-#include <QtCore/QVector>
-#include <QtBluetooth/qbluetooth.h>
-#include <QtBluetooth/qlowenergycharacteristic.h>
-#include <QtBluetooth/qlowenergyservicedata.h>
-#include "qlowenergycontroller.h"
-#include "qlowenergycontrollerbase_p.h"
-
-namespace ABI {
- namespace Windows {
- namespace Devices {
- namespace Bluetooth {
- struct IBluetoothLEDevice;
- }
- }
- namespace Foundation {
- template <typename T> struct IAsyncOperation;
- enum class AsyncStatus;
- }
- }
-}
-
-#include <wrl.h>
-#include <windows.devices.bluetooth.genericattributeprofile.h>
-
-#include <functional>
-
-QT_BEGIN_NAMESPACE
-
-class QLowEnergyServiceData;
-class QTimer;
-class QWinRTLowEnergyServiceHandler;
-
-extern void registerQLowEnergyControllerMetaType();
-
-QLowEnergyControllerPrivate *createWinRTLowEnergyController();
-
-class QLowEnergyControllerPrivateWinRTNew final : public QLowEnergyControllerPrivate
-{
- Q_OBJECT
-public:
- QLowEnergyControllerPrivateWinRTNew();
- ~QLowEnergyControllerPrivateWinRTNew() override;
-
- void init() override;
-
- void connectToDevice() override;
- void disconnectFromDevice() override;
-
- void discoverServices() override;
- void discoverServiceDetails(const QBluetoothUuid &service) override;
-
- void startAdvertising(const QLowEnergyAdvertisingParameters &params,
- const QLowEnergyAdvertisingData &advertisingData,
- const QLowEnergyAdvertisingData &scanResponseData) override;
- void stopAdvertising() override;
-
- void requestConnectionUpdate(const QLowEnergyConnectionParameters &params) override;
-
- // read data
- void readCharacteristic(const QSharedPointer<QLowEnergyServicePrivate> service,
- const QLowEnergyHandle charHandle) override;
- void readDescriptor(const QSharedPointer<QLowEnergyServicePrivate> service,
- const QLowEnergyHandle charHandle,
- const QLowEnergyHandle descriptorHandle) override;
-
- // write data
- void writeCharacteristic(const QSharedPointer<QLowEnergyServicePrivate> service,
- const QLowEnergyHandle charHandle,
- const QByteArray &newValue, QLowEnergyService::WriteMode mode) override;
- void writeDescriptor(const QSharedPointer<QLowEnergyServicePrivate> service,
- const QLowEnergyHandle charHandle,
- const QLowEnergyHandle descriptorHandle,
- const QByteArray &newValue) override;
-
- void addToGenericAttributeList(const QLowEnergyServiceData &service,
- QLowEnergyHandle startHandle) override;
-
-signals:
- void characteristicChanged(quint16 charHandle, const QByteArray &data);
-
-private slots:
- void handleCharacteristicChanged(quint16 charHandle, const QByteArray &data);
- void handleServiceHandlerError(const QString &error);
-
-private:
- void connectToPairedDevice();
- void connectToUnpairedDevice();
-
- bool mAbortPending = false;
- Microsoft::WRL::ComPtr<ABI::Windows::Devices::Bluetooth::IBluetoothLEDevice> mDevice;
- EventRegistrationToken mStatusChangedToken;
- struct ValueChangedEntry {
- ValueChangedEntry() {}
- ValueChangedEntry(Microsoft::WRL::ComPtr<ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::IGattCharacteristic> c,
- EventRegistrationToken t)
- : characteristic(c)
- , token(t)
- {
- }
-
- Microsoft::WRL::ComPtr<ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::IGattCharacteristic> characteristic;
- EventRegistrationToken token;
- };
- QVector<ValueChangedEntry> mValueChangedTokens;
-
- Microsoft::WRL::ComPtr<ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::IGattDeviceService> getNativeService(const QBluetoothUuid &serviceUuid);
- Microsoft::WRL::ComPtr<ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::IGattCharacteristic> getNativeCharacteristic(const QBluetoothUuid &serviceUuid, const QBluetoothUuid &charUuid);
-
- void registerForValueChanges(const QBluetoothUuid &serviceUuid, const QBluetoothUuid &charUuid);
- void unregisterFromValueChanges();
- HRESULT onValueChange(ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::IGattCharacteristic *characteristic,
- ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::IGattValueChangedEventArgs *args);
-
- bool registerForStatusChanges();
- void unregisterFromStatusChanges();
- HRESULT onStatusChange(ABI::Windows::Devices::Bluetooth::IBluetoothLEDevice *dev, IInspectable *);
-
- void obtainIncludedServices(QSharedPointer<QLowEnergyServicePrivate> servicePointer,
- Microsoft::WRL::ComPtr<ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::IGattDeviceService> nativeService);
- HRESULT onServiceDiscoveryFinished(ABI::Windows::Foundation::IAsyncOperation<ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::GattDeviceServicesResult *> *op,
- ABI::Windows::Foundation::AsyncStatus status);
-};
-
-QT_END_NAMESPACE
-
-#endif // QLOWENERGYCONTROLLERPRIVATEWINRT_NEW_P_H
diff --git a/src/bluetooth/qlowenergycontroller_winrt_p.h b/src/bluetooth/qlowenergycontroller_winrt_p.h
index fedc52d9..dc9c3235 100644
--- a/src/bluetooth/qlowenergycontroller_winrt_p.h
+++ b/src/bluetooth/qlowenergycontroller_winrt_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QLOWENERGYCONTROLLERPRIVATEWINRT_P_H
#define QLOWENERGYCONTROLLERPRIVATEWINRT_P_H
@@ -52,16 +16,30 @@
//
#include <qglobal.h>
+#include <QtCore/QList>
#include <QtCore/QQueue>
-#include <QtCore/QVector>
#include <QtBluetooth/qbluetooth.h>
#include <QtBluetooth/qlowenergycharacteristic.h>
#include <QtBluetooth/qlowenergyservicedata.h>
#include "qlowenergycontroller.h"
#include "qlowenergycontrollerbase_p.h"
+namespace ABI {
+ namespace Windows {
+ namespace Devices {
+ namespace Bluetooth {
+ struct IBluetoothLEDevice;
+ }
+ }
+ namespace Foundation {
+ template <typename T> struct IAsyncOperation;
+ enum class AsyncStatus;
+ }
+ }
+}
+
#include <wrl.h>
-#include <windows.devices.bluetooth.h>
+#include <windows.devices.bluetooth.genericattributeprofile.h>
#include <functional>
@@ -69,7 +47,6 @@ QT_BEGIN_NAMESPACE
class QLowEnergyServiceData;
class QTimer;
-class QWinRTLowEnergyServiceHandler;
extern void registerQLowEnergyControllerMetaType();
@@ -86,7 +63,8 @@ public:
void disconnectFromDevice() override;
void discoverServices() override;
- void discoverServiceDetails(const QBluetoothUuid &service) override;
+ void discoverServiceDetails(const QBluetoothUuid &service,
+ QLowEnergyService::DiscoveryMode mode) override;
void startAdvertising(const QLowEnergyAdvertisingParameters &params,
const QLowEnergyAdvertisingData &advertisingData,
@@ -114,15 +92,24 @@ public:
void addToGenericAttributeList(const QLowEnergyServiceData &service,
QLowEnergyHandle startHandle) override;
+ int mtu() const override;
+
signals:
void characteristicChanged(quint16 charHandle, const QByteArray &data);
+ void abortConnection();
private slots:
void handleCharacteristicChanged(quint16 charHandle, const QByteArray &data);
+ void handleServiceHandlerError(const QString &error);
private:
+ void handleConnectionError(const char *logMessage);
+
Microsoft::WRL::ComPtr<ABI::Windows::Devices::Bluetooth::IBluetoothLEDevice> mDevice;
+ Microsoft::WRL::ComPtr<ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::IGattSession>
+ mGattSession;
EventRegistrationToken mStatusChangedToken;
+ EventRegistrationToken mMtuChangedToken;
struct ValueChangedEntry {
ValueChangedEntry() {}
ValueChangedEntry(Microsoft::WRL::ComPtr<ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::IGattCharacteristic> c,
@@ -135,17 +122,61 @@ private:
Microsoft::WRL::ComPtr<ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::IGattCharacteristic> characteristic;
EventRegistrationToken token;
};
- QVector<ValueChangedEntry> mValueChangedTokens;
+ QList<ValueChangedEntry> mValueChangedTokens;
- Microsoft::WRL::ComPtr<ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::IGattDeviceService> getNativeService(const QBluetoothUuid &serviceUuid);
- Microsoft::WRL::ComPtr<ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::IGattCharacteristic> getNativeCharacteristic(const QBluetoothUuid &serviceUuid, const QBluetoothUuid &charUuid);
+ using GattDeviceServiceComPtr = Microsoft::WRL::ComPtr<ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::IGattDeviceService>;
+ QMap<QBluetoothUuid, GattDeviceServiceComPtr> m_openedServices;
+ QSet<QBluetoothUuid> m_requestDetailsServiceUuids;
+
+ using NativeServiceCallback = std::function<void(GattDeviceServiceComPtr)>;
+ HRESULT getNativeService(const QBluetoothUuid &serviceUuid, NativeServiceCallback callback);
+
+ using GattCharacteristicComPtr = Microsoft::WRL::ComPtr<ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::IGattCharacteristic>;
+ using NativeCharacteristicCallback = std::function<void(GattCharacteristicComPtr)>;
+ HRESULT getNativeCharacteristic(const QBluetoothUuid &serviceUuid,
+ const QBluetoothUuid &charUuid,
+ NativeCharacteristicCallback callback);
void registerForValueChanges(const QBluetoothUuid &serviceUuid, const QBluetoothUuid &charUuid);
void unregisterFromValueChanges();
+ HRESULT onValueChange(ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::IGattCharacteristic *characteristic,
+ ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::IGattValueChangedEventArgs *args);
+ HRESULT onMtuChange(ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::IGattSession *session,
+ IInspectable *args);
+ bool registerForMtuChanges();
+ void unregisterFromMtuChanges();
+
+ bool registerForStatusChanges();
+ void unregisterFromStatusChanges();
+ HRESULT onStatusChange(ABI::Windows::Devices::Bluetooth::IBluetoothLEDevice *dev, IInspectable *);
void obtainIncludedServices(QSharedPointer<QLowEnergyServicePrivate> servicePointer,
Microsoft::WRL::ComPtr<ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::IGattDeviceService> nativeService);
-
+ HRESULT onServiceDiscoveryFinished(ABI::Windows::Foundation::IAsyncOperation<ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::GattDeviceServicesResult *> *op,
+ ABI::Windows::Foundation::AsyncStatus status);
+
+ void readCharacteristicHelper(const QSharedPointer<QLowEnergyServicePrivate> service,
+ const QLowEnergyHandle charHandle,
+ GattCharacteristicComPtr characteristic);
+ void readDescriptorHelper(const QSharedPointer<QLowEnergyServicePrivate> service,
+ const QLowEnergyHandle charHandle,
+ const QLowEnergyHandle descriptorHandle,
+ GattCharacteristicComPtr characteristic);
+ void writeCharacteristicHelper(const QSharedPointer<QLowEnergyServicePrivate> service,
+ const QLowEnergyHandle charHandle, const QByteArray &newValue,
+ bool writeWithResponse,
+ GattCharacteristicComPtr characteristic);
+ void writeDescriptorHelper(const QSharedPointer<QLowEnergyServicePrivate> service,
+ const QLowEnergyHandle charHandle,
+ const QLowEnergyHandle descriptorHandle,
+ const QByteArray &newValue,
+ GattCharacteristicComPtr characteristic);
+ void discoverServiceDetailsHelper(const QBluetoothUuid &service,
+ QLowEnergyService::DiscoveryMode mode,
+ GattDeviceServiceComPtr deviceService);
+
+ void clearAllServices();
+ void closeAndRemoveService(const QBluetoothUuid &uuid);
};
QT_END_NAMESPACE
diff --git a/src/bluetooth/qlowenergycontrollerbase.cpp b/src/bluetooth/qlowenergycontrollerbase.cpp
index 059bd41b..69074037 100644
--- a/src/bluetooth/qlowenergycontrollerbase.cpp
+++ b/src/bluetooth/qlowenergycontrollerbase.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qlowenergycontrollerbase_p.h"
@@ -109,6 +73,12 @@ void QLowEnergyControllerPrivate::setError(
case QLowEnergyController::AuthorizationError:
errorString = QLowEnergyController::tr("Failed to authorize on the remote device");
break;
+ case QLowEnergyController::MissingPermissionsError:
+ errorString = QLowEnergyController::tr("Missing permissions error");
+ break;
+ case QLowEnergyController::RssiReadError:
+ errorString = QLowEnergyController::tr("Error reading RSSI value");
+ break;
case QLowEnergyController::NoError:
return;
default:
@@ -117,12 +87,13 @@ void QLowEnergyControllerPrivate::setError(
break;
}
- emit q->error(newError);
+ emit q->errorOccurred(newError);
}
void QLowEnergyControllerPrivate::setState(
QLowEnergyController::ControllerState newState)
{
+ qCDebug(QT_BT) << "QLowEnergyControllerPrivate setting state to" << newState;
Q_Q(QLowEnergyController);
if (state == newState)
return;
@@ -171,7 +142,7 @@ QLowEnergyCharacteristic QLowEnergyControllerPrivate::characteristicForHandle(
// check whether it is the handle of the characteristic value or its descriptors
QList<QLowEnergyHandle> charHandles = service->characteristicList.keys();
std::sort(charHandles.begin(), charHandles.end());
- for (int i = charHandles.size() - 1; i >= 0; i--) {
+ for (qsizetype i = charHandles.size() - 1; i >= 0; --i) {
if (charHandles.at(i) > handle)
continue;
@@ -291,7 +262,7 @@ QLowEnergyService *QLowEnergyControllerPrivate::addServiceHelper(
// Spec v4.2, Vol 3, Part G, Section 3.
const QLowEnergyHandle oldLastHandle = this->lastLocalHandle;
servicePrivate->startHandle = ++this->lastLocalHandle; // Service declaration.
- this->lastLocalHandle += servicePrivate->includedServices.count(); // Include declarations.
+ this->lastLocalHandle += servicePrivate->includedServices.size(); // Include declarations.
const QList<QLowEnergyCharacteristicData> characteristics = service.characteristics();
for (const QLowEnergyCharacteristicData &cd : characteristics) {
const QLowEnergyHandle declHandle = ++this->lastLocalHandle;
@@ -318,7 +289,7 @@ QLowEnergyService *QLowEnergyControllerPrivate::addServiceHelper(
}
if (localServices.contains(servicePrivate->uuid)) {
- qWarning() << "Overriding existing local service with uuid"
+ qCWarning(QT_BT) << "Overriding existing local service with uuid"
<< servicePrivate->uuid;
}
this->localServices.insert(servicePrivate->uuid, servicePrivate);
@@ -327,4 +298,12 @@ QLowEnergyService *QLowEnergyControllerPrivate::addServiceHelper(
return new QLowEnergyService(servicePrivate);
}
+void QLowEnergyControllerPrivate::readRssi()
+{
+ qCWarning(QT_BT, "This platform does not support reading RSSI");
+ setError(QLowEnergyController::RssiReadError);
+}
+
QT_END_NAMESPACE
+
+#include "moc_qlowenergycontrollerbase_p.cpp"
diff --git a/src/bluetooth/qlowenergycontrollerbase_p.h b/src/bluetooth/qlowenergycontrollerbase_p.h
index 169ba07b..0b18e6e8 100644
--- a/src/bluetooth/qlowenergycontrollerbase_p.h
+++ b/src/bluetooth/qlowenergycontrollerbase_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QLOWENERGYCONTROLLERPRIVATEBASE_P_H
#define QLOWENERGYCONTROLLERPRIVATEBASE_P_H
@@ -80,39 +44,42 @@ public:
virtual void disconnectFromDevice() = 0;
virtual void discoverServices() = 0;
- virtual void discoverServiceDetails(const QBluetoothUuid &/*service*/) = 0;
+ virtual void discoverServiceDetails(const QBluetoothUuid &service,
+ QLowEnergyService::DiscoveryMode mode) = 0;
virtual void readCharacteristic(
- const QSharedPointer<QLowEnergyServicePrivate> /*service*/,
- const QLowEnergyHandle /*charHandle*/) = 0;
+ const QSharedPointer<QLowEnergyServicePrivate> service,
+ const QLowEnergyHandle charHandle) = 0;
virtual void readDescriptor(
- const QSharedPointer<QLowEnergyServicePrivate> /*service*/,
- const QLowEnergyHandle /*charHandle*/,
- const QLowEnergyHandle /*descriptorHandle*/) = 0;
+ const QSharedPointer<QLowEnergyServicePrivate> service,
+ const QLowEnergyHandle charHandle,
+ const QLowEnergyHandle descriptorHandle) = 0;
virtual void writeCharacteristic(
- const QSharedPointer<QLowEnergyServicePrivate> /*service*/,
- const QLowEnergyHandle /*charHandle*/,
- const QByteArray &/*newValue*/,
- QLowEnergyService::WriteMode /*writeMode*/) = 0;
+ const QSharedPointer<QLowEnergyServicePrivate> service,
+ const QLowEnergyHandle charHandle,
+ const QByteArray &newValue,
+ QLowEnergyService::WriteMode writeMode) = 0;
virtual void writeDescriptor(
- const QSharedPointer<QLowEnergyServicePrivate> /*service*/,
- const QLowEnergyHandle /*charHandle*/,
- const QLowEnergyHandle /*descriptorHandle*/,
- const QByteArray &/*newValue*/) = 0;
+ const QSharedPointer<QLowEnergyServicePrivate> service,
+ const QLowEnergyHandle charHandle,
+ const QLowEnergyHandle descriptorHandle,
+ const QByteArray &newValue) = 0;
virtual void startAdvertising(
- const QLowEnergyAdvertisingParameters &/* params */,
- const QLowEnergyAdvertisingData &/* advertisingData */,
- const QLowEnergyAdvertisingData &/* scanResponseData */) = 0;
+ const QLowEnergyAdvertisingParameters &params,
+ const QLowEnergyAdvertisingData &advertisingData,
+ const QLowEnergyAdvertisingData &scanResponseData) = 0;
virtual void stopAdvertising() = 0;
virtual void requestConnectionUpdate(
- const QLowEnergyConnectionParameters & /* params */) = 0;
+ const QLowEnergyConnectionParameters & params) = 0;
virtual void addToGenericAttributeList(
- const QLowEnergyServiceData &/* service */,
- QLowEnergyHandle /* startHandle */) = 0;
+ const QLowEnergyServiceData &service,
+ QLowEnergyHandle startHandle) = 0;
+ virtual int mtu() const = 0;
+ virtual void readRssi();
virtual QLowEnergyService *addServiceHelper(
const QLowEnergyServiceData &service);
diff --git a/src/bluetooth/qlowenergydescriptor.cpp b/src/bluetooth/qlowenergydescriptor.cpp
index 6908a041..04f5117f 100644
--- a/src/bluetooth/qlowenergydescriptor.cpp
+++ b/src/bluetooth/qlowenergydescriptor.cpp
@@ -1,42 +1,6 @@
-/***************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2016 BlackBerry Limited. All rights reserved.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2016 BlackBerry Limited. All rights reserved.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtBluetooth/QLowEnergyService>
#include "qlowenergyserviceprivate_p.h"
@@ -44,6 +8,8 @@
QT_BEGIN_NAMESPACE
+QT_IMPL_METATYPE_EXTERN(QLowEnergyDescriptor)
+
/*!
\class QLowEnergyDescriptor
\inmodule QtBluetooth
@@ -52,16 +18,16 @@ QT_BEGIN_NAMESPACE
\since 5.4
QLowEnergyDescriptor provides information about a Bluetooth Low Energy
- descriptor's \l name(), \l uuid(), \l value() and \l handle(). Descriptors are
+ descriptor's name(), uuid(), and value(). Descriptors are
encapsulated by Bluetooth Low Energy characteristics and provide additional
contextual information about the characteristic (data format, notification activation
and so on).
- The descriptor value may be written via the \l QLowEnergyService instance
+ The descriptor value may be written via the QLowEnergyService instance
that manages the service to which this descriptor belongs. The
\l {QLowEnergyService::writeDescriptor()} function writes the new value.
The \l {QLowEnergyService::descriptorWritten()} signal
- is emitted upon success. The cached \l value() of this object is updated accordingly.
+ is emitted upon success. The cached value() of this object is updated accordingly.
\sa QLowEnergyService, QLowEnergyCharacteristic
*/
@@ -145,25 +111,46 @@ QLowEnergyDescriptor &QLowEnergyDescriptor::operator=(const QLowEnergyDescriptor
}
/*!
- Returns \c true if \a other is equal to this QLowEnergyCharacteristic; otherwise \c false.
+ \fn bool QLowEnergyDescriptor::operator==(const QLowEnergyDescriptor &a,
+ const QLowEnergyDescriptor &b)
+ \brief Returns \c true if \a a is equal to \a b; otherwise \c false.
+
+ Two QLowEnergyDescriptor instances are considered to be equal if they refer to
+ the same descriptor on the same remote Bluetooth Low Energy device or both
+ instances have been default-constructed.
+ */
+
+/*!
+ \fn bool QLowEnergyDescriptor::operator!=(const QLowEnergyDescriptor &a,
+ const QLowEnergyDescriptor &b)
+ \brief Returns \c true if \a a is not equal to \a b; otherwise \c false.
+
+ Two QLowEnergyDescriptor instances are considered to be equal if they refer to
+ the same descriptor on the same remote Bluetooth Low Energy device or both
+ instances have been default-constructed.
+ */
+
+/*!
+ \brief Returns \c true if \a other is equal to this QLowEnergyCharacteristic,
+ otherwise \c false.
+ \internal
Two QLowEnergyDescriptor instances are considered to be equal if they refer to
the same descriptor on the same remote Bluetooth Low Energy device or both
instances have been default-constructed.
*/
-bool QLowEnergyDescriptor::operator==(const QLowEnergyDescriptor &other) const
+bool QLowEnergyDescriptor::equals(const QLowEnergyDescriptor &a, const QLowEnergyDescriptor &b)
{
- if (d_ptr != other.d_ptr)
+ if (a.d_ptr != b.d_ptr)
return false;
- if ((data && !other.data) || (!data && other.data))
+ if ((a.data && !b.data) || (!a.data && b.data))
return false;
- if (!data)
+ if (!a.data)
return true;
- if (data->charHandle != other.data->charHandle
- || data->descHandle != other.data->descHandle) {
+ if (a.data->charHandle != b.data->charHandle || a.data->descHandle != b.data->descHandle) {
return false;
}
@@ -171,18 +158,6 @@ bool QLowEnergyDescriptor::operator==(const QLowEnergyDescriptor &other) const
}
/*!
- Returns \c true if \a other is not equal to this QLowEnergyCharacteristic; otherwise \c false.
-
- Two QLowEnergyDescriptor instances are considered to be equal if they refer to
- the same descriptor on the same remote Bluetooth Low Energy device or both
- instances have been default-constructed.
- */
-bool QLowEnergyDescriptor::operator!=(const QLowEnergyDescriptor &other) const
-{
- return !(*this == other);
-}
-
-/*!
Returns \c true if the QLowEnergyDescriptor object is valid, otherwise returns \c false.
An invalid descriptor instance is not associated with any service (default-constructed)
@@ -223,6 +198,8 @@ QBluetoothUuid QLowEnergyDescriptor::uuid() const
}
/*!
+ \internal
+
Returns the handle of the descriptor or \c 0 if the handle
cannot be accessed on the platform or the descriptor is invalid.
@@ -281,27 +258,27 @@ QBluetoothUuid::DescriptorType QLowEnergyDescriptor::type() const
{
const QBluetoothUuid u = uuid();
bool ok = false;
- quint16 shortUuid = u.toUInt16(&ok);
+ QBluetoothUuid::DescriptorType shortUuid = static_cast<QBluetoothUuid::DescriptorType>(u.toUInt16(&ok));
if (!ok)
- return QBluetoothUuid::UnknownDescriptorType;
+ return QBluetoothUuid::DescriptorType::UnknownDescriptorType;
switch (shortUuid) {
- case QBluetoothUuid::CharacteristicExtendedProperties:
- case QBluetoothUuid::CharacteristicUserDescription:
- case QBluetoothUuid::ClientCharacteristicConfiguration:
- case QBluetoothUuid::ServerCharacteristicConfiguration:
- case QBluetoothUuid::CharacteristicPresentationFormat:
- case QBluetoothUuid::CharacteristicAggregateFormat:
- case QBluetoothUuid::ValidRange:
- case QBluetoothUuid::ExternalReportReference:
- case QBluetoothUuid::ReportReference:
+ case QBluetoothUuid::DescriptorType::CharacteristicExtendedProperties:
+ case QBluetoothUuid::DescriptorType::CharacteristicUserDescription:
+ case QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration:
+ case QBluetoothUuid::DescriptorType::ServerCharacteristicConfiguration:
+ case QBluetoothUuid::DescriptorType::CharacteristicPresentationFormat:
+ case QBluetoothUuid::DescriptorType::CharacteristicAggregateFormat:
+ case QBluetoothUuid::DescriptorType::ValidRange:
+ case QBluetoothUuid::DescriptorType::ExternalReportReference:
+ case QBluetoothUuid::DescriptorType::ReportReference:
return (QBluetoothUuid::DescriptorType) shortUuid;
default:
break;
}
- return QBluetoothUuid::UnknownDescriptorType;
+ return QBluetoothUuid::DescriptorType::UnknownDescriptorType;
}
/*!
diff --git a/src/bluetooth/qlowenergydescriptor.h b/src/bluetooth/qlowenergydescriptor.h
index 18bb53c0..37f2216f 100644
--- a/src/bluetooth/qlowenergydescriptor.h
+++ b/src/bluetooth/qlowenergydescriptor.h
@@ -1,42 +1,6 @@
-/***************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2016 BlackBerry Limited. All rights reserved.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2016 BlackBerry Limited. All rights reserved.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QLOWENERGYDESCRIPTOR_H
#define QLOWENERGYDESCRIPTOR_H
@@ -59,20 +23,26 @@ public:
~QLowEnergyDescriptor();
QLowEnergyDescriptor &operator=(const QLowEnergyDescriptor &other);
- bool operator==(const QLowEnergyDescriptor &other) const;
- bool operator!=(const QLowEnergyDescriptor &other) const;
+ friend bool operator==(const QLowEnergyDescriptor &a, const QLowEnergyDescriptor &b)
+ {
+ return equals(a, b);
+ }
+ friend bool operator!=(const QLowEnergyDescriptor &a, const QLowEnergyDescriptor &b)
+ {
+ return !equals(a, b);
+ }
bool isValid() const;
QByteArray value() const;
QBluetoothUuid uuid() const;
- QLowEnergyHandle handle() const;
QString name() const;
QBluetoothUuid::DescriptorType type() const;
-protected:
+private:
+ QLowEnergyHandle handle() const;
QLowEnergyHandle characteristicHandle() const;
QSharedPointer<QLowEnergyServicePrivate> d_ptr;
@@ -83,19 +53,19 @@ protected:
friend class QLowEnergyControllerPrivateBluez;
friend class QLowEnergyControllerPrivateBluezDBus;
friend class QLowEnergyControllerPrivateCommon;
- friend class QLowEnergyControllerPrivateWin32;
friend class QLowEnergyControllerPrivateDarwin;
friend class QLowEnergyControllerPrivateWinRT;
- friend class QLowEnergyControllerPrivateWinRTNew;
QLowEnergyDescriptorPrivate *data = nullptr;
QLowEnergyDescriptor(QSharedPointer<QLowEnergyServicePrivate> p,
QLowEnergyHandle charHandle,
QLowEnergyHandle descHandle);
+
+ static bool equals(const QLowEnergyDescriptor &a, const QLowEnergyDescriptor &b);
};
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(QLowEnergyDescriptor)
+QT_DECL_METATYPE_EXTERN(QLowEnergyDescriptor, Q_BLUETOOTH_EXPORT)
#endif // QLOWENERGYDESCRIPTOR_H
diff --git a/src/bluetooth/qlowenergydescriptordata.cpp b/src/bluetooth/qlowenergydescriptordata.cpp
index f5836cdc..34e8c85d 100644
--- a/src/bluetooth/qlowenergydescriptordata.cpp
+++ b/src/bluetooth/qlowenergydescriptordata.cpp
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qlowenergydescriptordata.h"
@@ -202,24 +166,36 @@ QBluetooth::AttAccessConstraints QLowEnergyDescriptorData::writeConstraints() co
*/
/*!
- Returns \c true if \a d1 and \a d2 are equal with respect to their public state,
+ \fn bool QLowEnergyDescriptorData::operator==(const QLowEnergyDescriptorData &a,
+ const QLowEnergyDescriptorData &b)
+
+ \brief Returns \c true if \a a and \a b are equal with respect to their public state,
otherwise returns \c false.
*/
-bool operator==(const QLowEnergyDescriptorData &d1, const QLowEnergyDescriptorData &d2)
-{
- return d1.d == d2.d || (
- d1.uuid() == d2.uuid()
- && d1.value() == d2.value()
- && d1.isReadable() == d2.isReadable()
- && d1.isWritable() == d2.isWritable()
- && d1.readConstraints() == d2.readConstraints()
- && d1.writeConstraints() == d2.writeConstraints());
-}
/*!
- \fn bool operator!=(const QLowEnergyDescriptorData &d1, const QLowEnergyDescriptorData &d2)
- Returns \c true if \a d1 and \a d2 are not equal with respect to their public state,
- otherwise returns \c false.
+ \fn bool QLowEnergyDescriptorData::operator!=(const QLowEnergyDescriptorData &a,
+ const QLowEnergyDescriptorData &b)
+
+ \brief Returns \c true if \a a and \a b are unequal with respect to their public state,
+ otherwise returns \c false.
*/
+/*!
+ \brief Returns \c true if \a a and \a b are equal with respect to their public state,
+ otherwise returns \c false.
+ \internal
+ */
+bool QLowEnergyDescriptorData::equals(const QLowEnergyDescriptorData &a,
+ const QLowEnergyDescriptorData &b)
+{
+ return a.d == b.d || (
+ a.uuid() == b.uuid()
+ && a.value() == b.value()
+ && a.isReadable() == b.isReadable()
+ && a.isWritable() == b.isWritable()
+ && a.readConstraints() == b.readConstraints()
+ && a.writeConstraints() == b.writeConstraints());
+}
+
QT_END_NAMESPACE
diff --git a/src/bluetooth/qlowenergydescriptordata.h b/src/bluetooth/qlowenergydescriptordata.h
index 856acf53..7abd01ee 100644
--- a/src/bluetooth/qlowenergydescriptordata.h
+++ b/src/bluetooth/qlowenergydescriptordata.h
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QLOWENERGYDESCRIPTORDATA_H
#define QLOWENERGYDESCRIPTORDATA_H
@@ -51,8 +15,6 @@ struct QLowEnergyDescriptorDataPrivate;
class Q_BLUETOOTH_EXPORT QLowEnergyDescriptorData
{
- friend Q_BLUETOOTH_EXPORT bool operator==(const QLowEnergyDescriptorData &d1,
- const QLowEnergyDescriptorData &d12);
public:
QLowEnergyDescriptorData();
QLowEnergyDescriptorData(const QBluetoothUuid &uuid,
@@ -61,6 +23,15 @@ public:
~QLowEnergyDescriptorData();
QLowEnergyDescriptorData &operator=(const QLowEnergyDescriptorData &other);
+ friend bool operator==(const QLowEnergyDescriptorData &a, const QLowEnergyDescriptorData &b)
+ {
+ return equals(a, b);
+ }
+
+ friend bool operator!=(const QLowEnergyDescriptorData &a, const QLowEnergyDescriptorData &b)
+ {
+ return !equals(a, b);
+ }
QByteArray value() const;
void setValue(const QByteArray &value);
@@ -80,20 +51,13 @@ public:
bool isWritable() const;
QBluetooth::AttAccessConstraints writeConstraints() const;
- void swap(QLowEnergyDescriptorData &other) Q_DECL_NOTHROW { qSwap(d, other.d); }
+ void swap(QLowEnergyDescriptorData &other) noexcept { d.swap(other.d); }
private:
+ static bool equals(const QLowEnergyDescriptorData &a, const QLowEnergyDescriptorData &b);
QSharedDataPointer<QLowEnergyDescriptorDataPrivate> d;
};
-Q_BLUETOOTH_EXPORT bool operator==(const QLowEnergyDescriptorData &d1,
- const QLowEnergyDescriptorData &d2);
-
-inline bool operator!=(const QLowEnergyDescriptorData &d1, const QLowEnergyDescriptorData &d2)
-{
- return !(d1 == d2);
-}
-
Q_DECLARE_SHARED(QLowEnergyDescriptorData)
QT_END_NAMESPACE
diff --git a/src/bluetooth/qlowenergyservice.cpp b/src/bluetooth/qlowenergyservice.cpp
index 2e6d1f9b..eee75bd1 100644
--- a/src/bluetooth/qlowenergyservice.cpp
+++ b/src/bluetooth/qlowenergyservice.cpp
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2016 Javier S. Pedro <maemo@javispedro.com>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2016 Javier S. Pedro <maemo@javispedro.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtCore/QCoreApplication>
#include <QtCore/QPointer>
@@ -53,6 +17,11 @@
QT_BEGIN_NAMESPACE
+QT_IMPL_METATYPE_EXTERN_TAGGED(QLowEnergyService::ServiceError, QLowEnergyService__ServiceError)
+QT_IMPL_METATYPE_EXTERN_TAGGED(QLowEnergyService::ServiceState, QLowEnergyService__ServiceState)
+QT_IMPL_METATYPE_EXTERN_TAGGED(QLowEnergyService::ServiceType, QLowEnergyService__ServiceType)
+QT_IMPL_METATYPE_EXTERN_TAGGED(QLowEnergyService::WriteMode, QLowEnergyService__WriteMode)
+
/*!
\class QLowEnergyService
\inmodule QtBluetooth
@@ -96,7 +65,7 @@ QT_BEGIN_NAMESPACE
The discovery of its included services, characteristics and descriptors
is triggered when calling \l discoverDetails(). During the discovery the
- \l state() transitions from \l DiscoveryRequired via \l DiscoveringServices
+ \l state() transitions from \l DiscoveryRequired via \l DiscoveringService
to its final \l ServiceDiscovered state. This transition is advertised via
the \l stateChanged() signal. Once the details are known, all of the contained
characteristics, descriptors and included services are known and can be read
@@ -144,7 +113,7 @@ QT_BEGIN_NAMESPACE
the central is interested in receiving. In order for a characteristic to support
such notifications it must have the \l QLowEnergyCharacteristic::Notify or
\l QLowEnergyCharacteristic::Indicate property and a descriptor of type
- \l QBluetoothUuid::ClientCharacteristicConfiguration. Provided those conditions
+ \l QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration. Provided those conditions
are fulfilled notifications can be enabled as shown in the following code segment:
\snippet doc_src_qtbluetooth.cpp enable_btle_notifications
@@ -199,20 +168,19 @@ QT_BEGIN_NAMESPACE
the service while it was not yet in the
\l ServiceDiscovered \l state() or the service is invalid
due to a loss of connection to the peripheral device.
- \value CharacteristicReadError An attempt to read a characteristic value failed. For example,
- it might be triggered in response to a call to
- \l readCharacteristic(). This value was introduced by Qt 5.5.
+ \value [since 5.5] CharacteristicReadError An attempt to read a characteristic value failed.
+ For example, it might be triggered in response
+ to a call to \l readCharacteristic().
\value CharacteristicWriteError An attempt to write a new value to a characteristic
failed. For example, it might be triggered when attempting
to write to a read-only characteristic.
- \value DescriptorReadError An attempt to read a descriptor value failed. For example,
- it might be triggered in response to a call to
- \l readDescriptor(). This value was introduced by Qt 5.5.
+ \value [since 5.5] DescriptorReadError An attempt to read a descriptor value failed.
+ For example, it might be triggered in response
+ to a call to \l readDescriptor().
\value DescriptorWriteError An attempt to write a new value to a descriptor
failed. For example, it might be triggered when attempting
to write to a read-only descriptor.
- \value UnknownError An unknown error occurred when interacting with the service.
- This value was introduced by Qt 5.5.
+ \value [since 5.5] UnknownError An unknown error occurred when interacting with the service.
*/
/*!
@@ -220,23 +188,45 @@ QT_BEGIN_NAMESPACE
This enum describes the \l state() of the service object.
- \value InvalidService A service can become invalid when it looses
- the connection to the underlying device. Even though
- the connection may be lost it retains its last information.
- An invalid service cannot become valid anymore even if
- the connection to the device is re-established.
- \value DiscoveryRequired The service details are yet to be discovered by calling \l discoverDetails().
- The only reliable pieces of information are its
- \l serviceUuid() and \l serviceName().
- \value DiscoveringServices The service details are being discovered.
- \value ServiceDiscovered The service details have been discovered.
- \value LocalService The service is associated with a controller object in the
- \l{QLowEnergyController::PeripheralRole}{peripheral role}. Such
- service objects do not change their state.
- This value was introduced by Qt 5.7.
+ \value InvalidService A service can become invalid when it looses
+ the connection to the underlying device. Even though
+ the connection may be lost it retains its last information.
+ An invalid service cannot become valid anymore even if
+ the connection to the device is re-established.
+ \value RemoteService The service details are yet to be discovered
+ by calling \l discoverDetails().
+ The only reliable pieces of information are its
+ \l serviceUuid() and \l serviceName().
+ \value RemoteServiceDiscovering The service details are being discovered.
+ \value RemoteServiceDiscovered The service details have been discovered.
+ \value [since 5.7] LocalService The service is associated with a controller object in the
+ \l{QLowEnergyController::PeripheralRole}{peripheral role}.
+ Such service objects do not change their state.
+ \value DiscoveryRequired Deprecated. Was renamed to RemoteService.
+ \value DiscoveringService Deprecated. Was renamed to RemoteServiceDiscovering.
+ \value ServiceDiscovered Deprecated. Was renamed to RemoteServiceDiscovered.
*/
/*!
+ \enum QLowEnergyService::DiscoveryMode
+
+ This enum lists service discovery modes.
+ All modes discover the characteristics of the service and the descriptors
+ of the characteristics. The modes differ in whether characteristic values
+ and descriptors are read.
+
+ \value FullDiscovery During a full discovery, all characteristics
+ are discovered. All characteristic values and
+ descriptors are read.
+ \value SkipValueDiscovery During a minimal discovery, all characteristics
+ are discovered. Characteristic values and
+ descriptors are not read.
+
+ \sa discoverDetails()
+ \since 6.2
+*/
+
+/*!
\enum QLowEnergyService::WriteMode
This enum describes the mode to be used when writing a characteristic value.
@@ -261,17 +251,16 @@ QT_BEGIN_NAMESPACE
write operation as it may happen in between other
device interactions.
- \value WriteSigned If a characteristic is written using this mode, the remote peripheral
- shall not send a write confirmation. The operation's success
- cannot be determined and the payload must not be longer than 8 bytes.
- A bond must exist between the two devices and the link must not be
- encrypted.
- A characteristic must have set the
- \l QLowEnergyCharacteristic::WriteSigned property to support this
- write mode.
- This value was introduced in Qt 5.7 and is currently only
- supported on Android and on Linux with BlueZ 5 and a kernel version
- 3.7 or newer.
+ \value [since 5.7] WriteSigned If a characteristic is written using this mode, the remote
+ peripheral shall not send a write confirmation. The operation's
+ success cannot be determined and the payload must not be longer
+ than 8 bytes. A bond must exist between the two devices and the
+ link must not be encrypted.
+ A characteristic must have set the
+ \l QLowEnergyCharacteristic::WriteSigned property to support
+ this write mode.
+ This value is currently only supported on Android and on Linux
+ with BlueZ 5 and a kernel version 3.7 or newer.
*/
/*!
@@ -284,10 +273,12 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \fn void QLowEnergyService::error(QLowEnergyService::ServiceError newError)
+ \fn void QLowEnergyService::errorOccurred(QLowEnergyService::ServiceError newError)
This signal is emitted when an error occurrs. The \a newError parameter
describes the error that occurred.
+
+ \since 6.2
*/
/*!
@@ -295,7 +286,7 @@ QT_BEGIN_NAMESPACE
This signal is emitted when the read request for \a characteristic successfully returned
its \a value. The signal might be triggered by calling \l characteristicRead(). If
- the read operation is not successful, the \l error() signal is emitted using the
+ the read operation is not successful, the \l errorOccurred() signal is emitted using the
\l CharacteristicReadError flag.
\note This signal is only emitted for Central Role related use cases.
@@ -310,13 +301,13 @@ QT_BEGIN_NAMESPACE
This signal is emitted when the value of \a characteristic
is successfully changed to \a newValue. The change must have been triggered
by calling \l writeCharacteristic(). If the write operation is not successful,
- the \l error() signal is emitted using the \l CharacteristicWriteError flag.
+ the \l errorOccurred() signal is emitted using the \l CharacteristicWriteError flag.
The reception of the written signal can be considered as a sign that the target device
received the to-be-written value and reports back the status of write request.
\note If \l writeCharacteristic() is called using the \l WriteWithoutResponse mode,
- this signal and the \l error() are never emitted.
+ this signal and the \l errorOccurred() are never emitted.
\note This signal is only emitted for Central Role related use cases.
@@ -324,13 +315,14 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \fn void QLowEnergyService::characteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &newValue)
+ \fn void QLowEnergyService::characteristicChanged(const QLowEnergyCharacteristic
+ &characteristic, const QByteArray &newValue)
If the associated controller object is in the \l {QLowEnergyController::CentralRole}{central}
role, this signal is emitted when the value of \a characteristic is changed by an event on the
peripheral/device side. In that case, the signal emission implies that change notifications must
have been activated via the characteristic's
- \l {QBluetoothUuid::ClientCharacteristicConfiguration}{ClientCharacteristicConfiguration}
+ \l {QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration}{ClientCharacteristicConfiguration}
descriptor prior to the change event on the peripheral. More details on how this might be
done can be found further \l{notifications}{above}.
@@ -347,7 +339,7 @@ QT_BEGIN_NAMESPACE
This signal is emitted when the read request for \a descriptor successfully returned
its \a value. The signal might be triggered by calling \l descriptorRead(). If
- the read operation is not successful, the \l error() signal is emitted using the
+ the read operation is not successful, the \l errorOccurred() signal is emitted using the
\l DescriptorReadError flag.
\note This signal is only emitted for Central Role related use cases.
@@ -385,8 +377,8 @@ QLowEnergyService::QLowEnergyService(QSharedPointer<QLowEnergyServicePrivate> p,
qRegisterMetaType<QLowEnergyService::ServiceType>();
qRegisterMetaType<QLowEnergyService::WriteMode>();
- connect(p.data(), &QLowEnergyServicePrivate::error,
- this, QOverload<QLowEnergyService::ServiceError>::of(&QLowEnergyService::error));
+ connect(p.data(), &QLowEnergyServicePrivate::errorOccurred, this,
+ &QLowEnergyService::errorOccurred);
connect(p.data(), &QLowEnergyServicePrivate::stateChanged,
this, &QLowEnergyService::stateChanged);
connect(p.data(), &QLowEnergyServicePrivate::characteristicChanged,
@@ -514,7 +506,7 @@ QList<QLowEnergyCharacteristic> QLowEnergyService::characteristics() const
QList<QLowEnergyHandle> handles = d_ptr->characteristicList.keys();
std::sort(handles.begin(), handles.end());
- for (const QLowEnergyHandle &handle : qAsConst(handles)) {
+ for (const QLowEnergyHandle &handle : std::as_const(handles)) {
QLowEnergyCharacteristic characteristic(d_ptr, handle);
results.append(characteristic);
}
@@ -553,15 +545,35 @@ QString QLowEnergyService::serviceName() const
QStringLiteral("Unknown Service");
}
-
/*!
- Initiates the discovery of the services, characteristics
- and descriptors contained by the service. The discovery process is indicated
- via the \l stateChanged() signal.
+ Initiates discovery of the service's included services, characteristics,
+ and their associated descriptors.
+
+ The discovery process is indicated via the \l stateChanged() signal.
+ After creation, the service is in \l DiscoveryRequired state.
+ When calling discoverDetails() it transitions to \l DiscoveringService.
+ After completion of detail discovery, it transitions to
+ \l ServiceDiscovered state. On each transition, the \l stateChanged()
+ signal is emitted.
+ Depending on the argument \a mode, a \l FullDiscovery or a
+ \l SkipValueDiscovery is performed. In
+ any case, all services and characteristics are discovered. A
+ \l FullDiscovery proceeds and reads all characteristic values and
+ descriptors. A \l SkipValueDiscovery does not read characteristic values
+ and descriptors. A \l SkipValueDiscovery has two advantages. First, it is
+ faster. Second, it circumvents bugs in some devices which wrongly advertise
+ characteristics or descriptors as readable but nevertheless do not permit
+ reads on them. This can trigger unpredictable behavior.
+ After a \l SkipValueDiscovery, it is necessary to call
+ \l readCharacteristic() / \l readDescriptor() and wait for them to
+ finish successfully before accessing the value of a characteristic or
+ descriptor.
+
+ The argument \a mode was introduced in Qt 6.2.
\sa state()
*/
-void QLowEnergyService::discoverDetails()
+void QLowEnergyService::discoverDetails(DiscoveryMode mode)
{
Q_D(QLowEnergyService);
@@ -570,12 +582,12 @@ void QLowEnergyService::discoverDetails()
return;
}
- if (d->state != QLowEnergyService::DiscoveryRequired)
+ if (d->state != QLowEnergyService::RemoteService)
return;
- d->setState(QLowEnergyService::DiscoveringServices);
+ d->setState(QLowEnergyService::RemoteServiceDiscovering);
- d->controller->discoverServiceDetails(d->uuid);
+ d->controller->discoverServiceDetails(d->uuid, mode);
}
/*!
@@ -634,7 +646,7 @@ void QLowEnergyService::readCharacteristic(
{
Q_D(QLowEnergyService);
- if (d->controller == nullptr || state() != ServiceDiscovered || !contains(characteristic)) {
+ if (d->controller == nullptr || state() != RemoteServiceDiscovered || !contains(characteristic)) {
d->setError(QLowEnergyService::OperationError);
return;
}
@@ -707,7 +719,7 @@ void QLowEnergyService::writeCharacteristic(
if (d->controller == nullptr
|| (d->controller->role == QLowEnergyController::CentralRole
- && state() != ServiceDiscovered)
+ && state() != RemoteServiceDiscovered)
|| !contains(characteristic)) {
d->setError(QLowEnergyService::OperationError);
return;
@@ -764,7 +776,7 @@ void QLowEnergyService::readDescriptor(
{
Q_D(QLowEnergyService);
- if (d->controller == nullptr || state() != ServiceDiscovered || !contains(descriptor)) {
+ if (d->controller == nullptr || state() != RemoteServiceDiscovered || !contains(descriptor)) {
d->setError(QLowEnergyService::OperationError);
return;
}
@@ -808,13 +820,13 @@ void QLowEnergyService::writeDescriptor(const QLowEnergyDescriptor &descriptor,
if (d->controller == nullptr
|| (d->controller->role == QLowEnergyController::CentralRole
- && state() != ServiceDiscovered)
+ && state() != RemoteServiceDiscovered)
|| !contains(descriptor)) {
d->setError(QLowEnergyService::OperationError);
return;
}
#ifdef Q_OS_DARWIN
- if (descriptor.uuid() == QBluetoothUuid::ClientCharacteristicConfiguration) {
+ if (descriptor.uuid() == QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration) {
// We have to identify a special case - ClientCharacteristicConfiguration
// since with CoreBluetooth:
//
@@ -836,3 +848,5 @@ void QLowEnergyService::writeDescriptor(const QLowEnergyDescriptor &descriptor,
}
QT_END_NAMESPACE
+
+#include "moc_qlowenergyservice.cpp"
diff --git a/src/bluetooth/qlowenergyservice.h b/src/bluetooth/qlowenergyservice.h
index a2715471..2fc94008 100644
--- a/src/bluetooth/qlowenergyservice.h
+++ b/src/bluetooth/qlowenergyservice.h
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2016 Javier S. Pedro <maemo@javispedro.com>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2016 Javier S. Pedro <maemo@javispedro.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QLOWENERGYSERVICE_H
#define QLOWENERGYSERVICE_H
@@ -71,14 +35,35 @@ public:
enum ServiceState {
InvalidService = 0,
- DiscoveryRequired, // we know start/end handle but nothing more
- //TODO Rename DiscoveringServices -> DiscoveringDetails or DiscoveringService
- DiscoveringServices,// discoverDetails() called and running
- ServiceDiscovered, // all details have been synchronized
+ RemoteService,
+ RemoteServiceDiscovering, // discoverDetails() called and running
+ RemoteServiceDiscovered, // all details have been synchronized
LocalService,
+
+#if QT_DEPRECATED_SINCE(6, 2)
+// for source compatibility:
+ DiscoveryRequired
+ Q_DECL_ENUMERATOR_DEPRECATED_X(
+ "DiscoveryRequired was renamed to RemoteService.")
+ = RemoteService,
+ DiscoveringService
+ Q_DECL_ENUMERATOR_DEPRECATED_X(
+ "DiscoveringService was renamed to RemoteServiceDiscovering.")
+ = RemoteServiceDiscovering,
+ ServiceDiscovered
+ Q_DECL_ENUMERATOR_DEPRECATED_X(
+ "ServiceDiscovered was renamed to RemoteServiceDiscovered.")
+ = RemoteServiceDiscovered,
+#endif
};
Q_ENUM(ServiceState)
+ enum DiscoveryMode {
+ FullDiscovery, // standard, reads all attributes
+ SkipValueDiscovery // does not read characteristic values and descriptors
+ };
+ Q_ENUM(DiscoveryMode)
+
enum WriteMode {
WriteWithResponse = 0,
WriteWithoutResponse,
@@ -98,7 +83,7 @@ public:
QBluetoothUuid serviceUuid() const;
QString serviceName() const;
- void discoverDetails();
+ void discoverDetails(DiscoveryMode mode = FullDiscovery);
ServiceError error() const;
@@ -125,7 +110,7 @@ Q_SIGNALS:
const QByteArray &value);
void descriptorWritten(const QLowEnergyDescriptor &info,
const QByteArray &value);
- void error(QLowEnergyService::ServiceError error);
+ void errorOccurred(QLowEnergyService::ServiceError error);
private:
Q_DECLARE_PRIVATE(QLowEnergyService)
@@ -145,9 +130,13 @@ Q_DECLARE_OPERATORS_FOR_FLAGS(QLowEnergyService::ServiceTypes)
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(QLowEnergyService::ServiceError)
-Q_DECLARE_METATYPE(QLowEnergyService::ServiceState)
-Q_DECLARE_METATYPE(QLowEnergyService::ServiceType)
-Q_DECLARE_METATYPE(QLowEnergyService::WriteMode)
+QT_DECL_METATYPE_EXTERN_TAGGED(QLowEnergyService::ServiceError, QLowEnergyService__ServiceError,
+ Q_BLUETOOTH_EXPORT)
+QT_DECL_METATYPE_EXTERN_TAGGED(QLowEnergyService::ServiceState, QLowEnergyService__ServiceState,
+ Q_BLUETOOTH_EXPORT)
+QT_DECL_METATYPE_EXTERN_TAGGED(QLowEnergyService::ServiceType, QLowEnergyService__ServiceType,
+ Q_BLUETOOTH_EXPORT)
+QT_DECL_METATYPE_EXTERN_TAGGED(QLowEnergyService::WriteMode, QLowEnergyService__WriteMode,
+ Q_BLUETOOTH_EXPORT)
#endif // QLOWENERGYSERVICE_H
diff --git a/src/bluetooth/qlowenergyservicedata.cpp b/src/bluetooth/qlowenergyservicedata.cpp
index c536da14..76d6b9f1 100644
--- a/src/bluetooth/qlowenergyservicedata.cpp
+++ b/src/bluetooth/qlowenergyservicedata.cpp
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qlowenergyservicedata.h"
@@ -198,21 +162,33 @@ bool QLowEnergyServiceData::isValid() const
*/
/*!
- Returns \c true if \a sd1 and \a sd2 are equal with respect to their public state,
+ \fn bool QLowEnergyServiceData::operator==(const QLowEnergyServiceData &a,
+ const QLowEnergyServiceData &b)
+
+ \brief Returns \c true if \a a and \a b are equal with respect to their public state,
otherwise returns \c false.
*/
-bool operator==(const QLowEnergyServiceData &sd1, const QLowEnergyServiceData &sd2)
-{
- return sd1.d == sd2.d || (sd1.type() == sd2.type() && sd1.uuid() == sd2.uuid()
- && sd1.includedServices() == sd2.includedServices()
- && sd1.characteristics() == sd2.characteristics());
-}
/*!
- \fn bool operator!=(const QLowEnergyServiceData &sd1,
- const QLowEnergyServiceData &sd2)
- Returns \c true if \a sd1 and \a sd2 are not equal with respect to their public state,
- otherwise returns \c false.
+ \fn bool QLowEnergyServiceData::operator!=(const QLowEnergyServiceData &a,
+ const QLowEnergyServiceData &b)
+
+ \brief Returns \c true if \a a and \a b are unequal with respect to their public state,
+ otherwise returns \c false.
*/
+/*!
+ \brief Returns \c true if \a a and \a b are equal with respect to their public state,
+ otherwise returns \c false.
+ \internal
+ */
+bool QLowEnergyServiceData::equals(const QLowEnergyServiceData &a, const QLowEnergyServiceData &b)
+{
+ return a.d == b.d || (
+ a.type() == b.type()
+ && a.uuid() == b.uuid()
+ && a.includedServices() == b.includedServices()
+ && a.characteristics() == b.characteristics());
+}
+
QT_END_NAMESPACE
diff --git a/src/bluetooth/qlowenergyservicedata.h b/src/bluetooth/qlowenergyservicedata.h
index 4d553267..108b7d88 100644
--- a/src/bluetooth/qlowenergyservicedata.h
+++ b/src/bluetooth/qlowenergyservicedata.h
@@ -1,41 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QLOWENERGYSERVICEDATA_H
#define QLOWENERGYSERVICEDATA_H
@@ -52,14 +16,20 @@ struct QLowEnergyServiceDataPrivate;
class Q_BLUETOOTH_EXPORT QLowEnergyServiceData
{
- friend Q_BLUETOOTH_EXPORT bool operator==(const QLowEnergyServiceData &sd1,
- const QLowEnergyServiceData &sd2);
public:
QLowEnergyServiceData();
QLowEnergyServiceData(const QLowEnergyServiceData &other);
~QLowEnergyServiceData();
QLowEnergyServiceData &operator=(const QLowEnergyServiceData &other);
+ friend bool operator==(const QLowEnergyServiceData &a, const QLowEnergyServiceData &b)
+ {
+ return equals(a, b);
+ }
+ friend bool operator!=(const QLowEnergyServiceData &a, const QLowEnergyServiceData &b)
+ {
+ return !equals(a, b);
+ }
enum ServiceType { ServiceTypePrimary = 0x2800, ServiceTypeSecondary = 0x2801 };
ServiceType type() const;
@@ -78,19 +48,13 @@ public:
bool isValid() const;
- void swap(QLowEnergyServiceData &other) Q_DECL_NOTHROW { qSwap(d, other.d); }
+ void swap(QLowEnergyServiceData &other) noexcept { d.swap(other.d); }
private:
+ static bool equals(const QLowEnergyServiceData &a, const QLowEnergyServiceData &b);
QSharedDataPointer<QLowEnergyServiceDataPrivate> d;
};
-Q_BLUETOOTH_EXPORT bool operator==(const QLowEnergyServiceData &sd1,
- const QLowEnergyServiceData &sd2);
-inline bool operator!=(const QLowEnergyServiceData &sd1, const QLowEnergyServiceData &sd2)
-{
- return !(sd1 == sd2);
-}
-
Q_DECLARE_SHARED(QLowEnergyServiceData)
QT_END_NAMESPACE
diff --git a/src/bluetooth/qlowenergyserviceprivate.cpp b/src/bluetooth/qlowenergyserviceprivate.cpp
index 0b8d8be0..c82897cd 100644
--- a/src/bluetooth/qlowenergyserviceprivate.cpp
+++ b/src/bluetooth/qlowenergyserviceprivate.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qlowenergyserviceprivate_p.h"
@@ -43,15 +7,10 @@
QT_BEGIN_NAMESPACE
-QLowEnergyServicePrivate::QLowEnergyServicePrivate(QObject *parent) :
- QObject(parent),
- startHandle(0),
- endHandle(0),
- type(QLowEnergyService::PrimaryService),
- state(QLowEnergyService::InvalidService),
- lastError(QLowEnergyService::NoError)
-{
-}
+QT_IMPL_METATYPE_EXTERN_TAGGED(QSharedPointer<QLowEnergyServicePrivate>,
+ QSharedPointer_QLowEnergyServicePrivate)
+
+QLowEnergyServicePrivate::QLowEnergyServicePrivate(QObject *parent) : QObject(parent) { }
QLowEnergyServicePrivate::~QLowEnergyServicePrivate()
{
@@ -62,7 +21,7 @@ void QLowEnergyServicePrivate::setController(QLowEnergyControllerPrivate *contro
controller = control;
if (control)
- setState(QLowEnergyService::DiscoveryRequired);
+ setState(QLowEnergyService::RemoteService);
else
setState(QLowEnergyService::InvalidService);
}
@@ -70,7 +29,7 @@ void QLowEnergyServicePrivate::setController(QLowEnergyControllerPrivate *contro
void QLowEnergyServicePrivate::setError(QLowEnergyService::ServiceError newError)
{
lastError = newError;
- emit error(newError);
+ emit errorOccurred(newError);
}
void QLowEnergyServicePrivate::setState(QLowEnergyService::ServiceState newState)
@@ -83,3 +42,5 @@ void QLowEnergyServicePrivate::setState(QLowEnergyService::ServiceState newState
}
QT_END_NAMESPACE
+
+#include "moc_qlowenergyserviceprivate_p.cpp"
diff --git a/src/bluetooth/qlowenergyserviceprivate_p.h b/src/bluetooth/qlowenergyserviceprivate_p.h
index 226af145..68d65da5 100644
--- a/src/bluetooth/qlowenergyserviceprivate_p.h
+++ b/src/bluetooth/qlowenergyserviceprivate_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QLOWENERGYSERVICEPRIVATE_P_H
#define QLOWENERGYSERVICEPRIVATE_P_H
@@ -56,12 +20,10 @@
#include <QtBluetooth/qbluetooth.h>
#include <QtBluetooth/QLowEnergyService>
#include <QtBluetooth/QLowEnergyCharacteristic>
+#include <QtCore/private/qglobal_p.h>
#if defined(QT_ANDROID_BLUETOOTH)
-#include <QtAndroidExtras/QAndroidJniObject>
-#endif
-#if defined(QT_WIN_BLUETOOTH)
-#include <qt_windows.h>
+#include <QtCore/QJniObject>
#endif
QT_BEGIN_NAMESPACE
@@ -86,9 +48,6 @@ public:
QLowEnergyCharacteristic::PropertyTypes properties;
QByteArray value;
QHash<QLowEnergyHandle, DescData> descriptorList;
-#ifdef QT_WIN_BLUETOOTH
- Qt::HANDLE hValueChangeEvent;
-#endif
};
enum GattAttributeTypes {
@@ -104,7 +63,7 @@ public:
signals:
void stateChanged(QLowEnergyService::ServiceState newState);
- void error(QLowEnergyService::ServiceError error);
+ void errorOccurred(QLowEnergyService::ServiceError error);
void characteristicChanged(const QLowEnergyCharacteristic &characteristic,
const QByteArray &newValue);
void characteristicRead(const QLowEnergyCharacteristic &info,
@@ -117,14 +76,15 @@ signals:
const QByteArray &newValue);
public:
- QLowEnergyHandle startHandle;
- QLowEnergyHandle endHandle;
+ QLowEnergyHandle startHandle = 0;
+ QLowEnergyHandle endHandle = 0;
QBluetoothUuid uuid;
QList<QBluetoothUuid> includedServices;
- QLowEnergyService::ServiceTypes type;
- QLowEnergyService::ServiceState state;
- QLowEnergyService::ServiceError lastError;
+ QLowEnergyService::ServiceTypes type = QLowEnergyService::PrimaryService;
+ QLowEnergyService::ServiceState state = QLowEnergyService::InvalidService;
+ QLowEnergyService::ServiceError lastError = QLowEnergyService::NoError;
+ QLowEnergyService::DiscoveryMode mode = QLowEnergyService::FullDiscovery;
QHash<QLowEnergyHandle, CharData> characteristicList;
@@ -132,10 +92,7 @@ public:
#if defined(QT_ANDROID_BLUETOOTH)
// reference to the BluetoothGattService object
- QAndroidJniObject androidService;
-#endif
-#if defined(QT_WIN_BLUETOOTH)
- Qt::HANDLE hService = nullptr;
+ QJniObject androidService;
#endif
};
@@ -145,6 +102,8 @@ typedef QHash<QLowEnergyHandle, QLowEnergyServicePrivate::DescData> DescriptorDa
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(QSharedPointer<QLowEnergyServicePrivate>)
+QT_DECL_METATYPE_EXTERN_TAGGED(QSharedPointer<QLowEnergyServicePrivate>,
+ QSharedPointer_QLowEnergyServicePrivate,
+ /* not exported */)
#endif // QLOWENERGYSERVICEPRIVATE_P_H
diff --git a/src/bluetooth/qprivatelinearbuffer_p.h b/src/bluetooth/qprivatelinearbuffer_p.h
index 60854774..e4072c50 100644
--- a/src/bluetooth/qprivatelinearbuffer_p.h
+++ b/src/bluetooth/qprivatelinearbuffer_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QPRIVATELINEARBUFFER_P_H
#define QPRIVATELINEARBUFFER_P_H
@@ -64,13 +28,15 @@ public:
first = buf;
len = 0;
}
- int size() const {
+ qsizetype size() const
+ {
return len;
}
bool isEmpty() const {
return len == 0;
}
- void skip(int n) {
+ void skip(qsizetype n)
+ {
if (n >= len) {
clear();
} else {
@@ -86,20 +52,23 @@ public:
first++;
return ch;
}
- int read(char* target, int size) {
- int r = qMin(size, len);
+ qsizetype read(char* target, qsizetype size)
+ {
+ qsizetype r = (std::min)(size, len);
memcpy(target, first, r);
len -= r;
first += r;
return r;
}
- char* reserve(int size) {
+ char* reserve(qsizetype size)
+ {
makeSpace(size + len, freeSpaceAtEnd);
char* writePtr = first + len;
len += size;
return writePtr;
}
- void chop(int size) {
+ void chop(qsizetype size)
+ {
if (size >= len) {
clear();
} else {
@@ -108,20 +77,21 @@ public:
}
QByteArray readAll() {
char* f = first;
- int l = len;
+ qsizetype l = len;
clear();
return QByteArray(f, l);
}
- int readLine(char* target, int size) {
- int r = qMin(size, len);
+ qsizetype readLine(char* target, qsizetype size)
+ {
+ qsizetype r = (std::min)(size, len);
char* eol = static_cast<char*>(memchr(first, '\n', r));
if (eol)
r = 1+(eol-first);
memcpy(target, first, r);
len -= r;
first += r;
- return int(r);
- }
+ return r;
+ }
bool canReadLine() const {
return memchr(first, '\n', len);
}
@@ -134,7 +104,8 @@ public:
len++;
*first = c;
}
- void ungetBlock(const char* block, int size) {
+ void ungetBlock(const char* block, qsizetype size)
+ {
if ((first - buf) < size) {
// underflow, the existing valid data needs to move to the end of the (potentially bigger) buffer
makeSpace(len + size, freeSpaceAtStart);
@@ -147,10 +118,10 @@ public:
private:
enum FreeSpacePos {freeSpaceAtStart, freeSpaceAtEnd};
void makeSpace(size_t required, FreeSpacePos where) {
- size_t newCapacity = qMax(capacity, size_t(QPRIVATELINEARBUFFER_BUFFERSIZE));
+ size_t newCapacity = (std::max)(capacity, size_t(QPRIVATELINEARBUFFER_BUFFERSIZE));
while (newCapacity < required)
newCapacity *= 2;
- const int moveOffset = (where == freeSpaceAtEnd) ? 0 : int(newCapacity) - len;
+ const qsizetype moveOffset = (where == freeSpaceAtEnd) ? 0 : qsizetype(newCapacity) - len;
if (newCapacity > capacity) {
// allocate more space
char* newBuf = new char[newCapacity];
@@ -167,7 +138,7 @@ private:
private:
// length of the unread data
- int len;
+ qsizetype len;
// start of the unread data
char* first;
// the allocated buffer
diff --git a/src/bluetooth/qtbluetoothglobal.h b/src/bluetooth/qtbluetoothglobal.h
index 40b6d3d2..62d41a4f 100644
--- a/src/bluetooth/qtbluetoothglobal.h
+++ b/src/bluetooth/qtbluetoothglobal.h
@@ -1,59 +1,10 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QTBLUETOOTH_H
#define QTBLUETOOTH_H
#include <QtCore/qglobal.h>
#include <QtBluetooth/qtbluetooth-config.h> // for feature detection
-
-QT_BEGIN_NAMESPACE
-
-#ifndef QT_STATIC
-# if defined(QT_BUILD_BLUETOOTH_LIB)
-# define Q_BLUETOOTH_EXPORT Q_DECL_EXPORT
-# else
-# define Q_BLUETOOTH_EXPORT Q_DECL_IMPORT
-# endif
-#else
-# define Q_BLUETOOTH_EXPORT
-#endif
-
-QT_END_NAMESPACE
+#include <QtBluetooth/qtbluetoothexports.h>
#endif // QTBLUETOOTH_H
diff --git a/src/bluetooth/qtbluetoothglobal_p.h b/src/bluetooth/qtbluetoothglobal_p.h
index 59944593..7dcbdfab 100644
--- a/src/bluetooth/qtbluetoothglobal_p.h
+++ b/src/bluetooth/qtbluetoothglobal_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtWidgets module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QTBLUETOOTHGLOBAL_P_H
#define QTBLUETOOTHGLOBAL_P_H
@@ -55,11 +19,6 @@
#include <QtBluetooth/qtbluetoothglobal.h>
#include <QtBluetooth/private/qtbluetooth-config_p.h>
-
-QT_BEGIN_NAMESPACE
-
-#define Q_BLUETOOTH_PRIVATE_EXPORT Q_BLUETOOTH_EXPORT
-
-QT_END_NAMESPACE
+#include <QtBluetooth/qtbluetoothexports.h>
#endif // QTBLUETOOTHGLOBAL_P_H
diff --git a/src/bluetooth/removed_api.cpp b/src/bluetooth/removed_api.cpp
new file mode 100644
index 00000000..c4f37b68
--- /dev/null
+++ b/src/bluetooth/removed_api.cpp
@@ -0,0 +1,57 @@
+// Copyright (C) 2022 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#define QT_BLUETOOTH_BUILD_REMOVED_API
+
+// Undefine Qt 128-bit int types
+#define QT_NO_INT128
+
+#include "qtbluetoothglobal.h"
+
+QT_USE_NAMESPACE
+
+#if QT_BLUETOOTH_REMOVED_SINCE(6, 6)
+
+#include "qbluetoothaddress.h" // inlined API
+
+#include "qbluetoothuuid.h"
+
+static_assert(std::is_aggregate_v<quint128>);
+static_assert(std::is_trivial_v<quint128>);
+
+// These legacy functions can't just call the new (quint128, Endian) overloads,
+// as the latter may see either QtCore's quint128 (__int128 built-in) _or_ our
+// fake version from qbluetoothuuid.h. This TU must _always_ see the fake ones
+// (as that is what we had in 6.5):
+#ifdef QT_SUPPORTS_INT128
+# error This TU requires QT_NO_INT128 to be defined.
+#endif
+
+QBluetoothUuid::QBluetoothUuid(quint128 uuid)
+ : QUuid(fromBytes(uuid.data))
+{}
+
+quint128 QBluetoothUuid::toUInt128() const
+{
+ quint128 uuid;
+ const auto bytes = toBytes();
+ memcpy(uuid.data, bytes.data, sizeof(uuid.data));
+ return uuid;
+}
+
+// END quint128 functions
+
+QBluetoothUuid::QBluetoothUuid(const QString &uuid)
+ : QUuid(qToAnyStringViewIgnoringNull(uuid))
+{
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug QBluetoothUuid::streamingOperator(QDebug debug, const QBluetoothUuid &uuid)
+{
+ debug << uuid.toString();
+ return debug;
+}
+#endif // QT_NO_DEBUG_STREAM
+
+#endif // QT_BLUETOOTH_REMOVED_SINCE(6, 6)
diff --git a/src/bluetooth/windows/qwinlowenergybluetooth_p.h b/src/bluetooth/windows/qwinlowenergybluetooth_p.h
deleted file mode 100644
index 39b88a5f..00000000
--- a/src/bluetooth/windows/qwinlowenergybluetooth_p.h
+++ /dev/null
@@ -1,231 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Copyright (C) 2014 Denis Shienkov <denis.shienkov@gmail.com>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtBluetooth module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QWINLOWENERGYBLUETOOTH_P_H
-#define QWINLOWENERGYBLUETOOTH_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <QtCore/qlibrary.h>
-
-#include <qt_windows.h>
-
-#define WIN32_FROM_HRESULT(hr) \
- (SUCCEEDED(hr) ? ERROR_SUCCESS : \
- (HRESULT_FACILITY(hr) == FACILITY_WIN32 ? HRESULT_CODE(hr) : (hr)))
-
-#define BLUETOOTH_GATT_FLAG_NONE 0x00000000
-#define BLUETOOTH_GATT_FLAG_CONNECTION_ENCRYPTED 0x00000001
-#define BLUETOOTH_GATT_FLAG_CONNECTION_AUTHENTICATED 0x00000002
-#define BLUETOOTH_GATT_FLAG_FORCE_READ_FROM_DEVICE 0x00000004
-#define BLUETOOTH_GATT_FLAG_FORCE_READ_FROM_CACHE 0x00000008
-#define BLUETOOTH_GATT_FLAG_SIGNED_WRITE 0x00000010
-#define BLUETOOTH_GATT_FLAG_WRITE_WITHOUT_RESPONSE 0x00000020
-#define BLUETOOTH_GATT_FLAG_RETURN_ALL 0x00000040
-
-typedef enum _BTH_LE_GATT_DESCRIPTOR_TYPE {
- CharacteristicExtendedProperties,
- CharacteristicUserDescription,
- ClientCharacteristicConfiguration,
- ServerCharacteristicConfiguration,
- CharacteristicFormat,
- CharacteristicAggregateFormat,
- CustomDescriptor
-} BTH_LE_GATT_DESCRIPTOR_TYPE, *PBTH_LE_GATT_DESCRIPTOR_TYPE;
-
-typedef enum _BTH_LE_GATT_EVENT_TYPE {
- CharacteristicValueChangedEvent
-} BTH_LE_GATT_EVENT_TYPE;
-
-typedef struct _BTH_LE_UUID {
- BOOLEAN IsShortUuid;
- union {
- USHORT ShortUuid;
- GUID LongUuid;
- } Value;
-} BTH_LE_UUID, *PBTH_LE_UUID;
-
-typedef struct _BTH_LE_GATT_SERVICE {
- BTH_LE_UUID ServiceUuid;
- USHORT AttributeHandle;
-} BTH_LE_GATT_SERVICE, *PBTH_LE_GATT_SERVICE;
-
-typedef struct _BTH_LE_GATT_CHARACTERISTIC {
- USHORT ServiceHandle;
- BTH_LE_UUID CharacteristicUuid;
- USHORT AttributeHandle;
- USHORT CharacteristicValueHandle;
- BOOLEAN IsBroadcastable;
- BOOLEAN IsReadable;
- BOOLEAN IsWritable;
- BOOLEAN IsWritableWithoutResponse;
- BOOLEAN IsSignedWritable;
- BOOLEAN IsNotifiable;
- BOOLEAN IsIndicatable;
- BOOLEAN HasExtendedProperties;
-} BTH_LE_GATT_CHARACTERISTIC, *PBTH_LE_GATT_CHARACTERISTIC;
-
-typedef struct _BTH_LE_GATT_CHARACTERISTIC_VALUE {
- ULONG DataSize;
- UCHAR Data[1];
-} BTH_LE_GATT_CHARACTERISTIC_VALUE, *PBTH_LE_GATT_CHARACTERISTIC_VALUE;
-
-typedef struct _BTH_LE_GATT_DESCRIPTOR {
- USHORT ServiceHandle;
- USHORT CharacteristicHandle;
- BTH_LE_GATT_DESCRIPTOR_TYPE DescriptorType;
- BTH_LE_UUID DescriptorUuid;
- USHORT AttributeHandle;
-} BTH_LE_GATT_DESCRIPTOR, *PBTH_LE_GATT_DESCRIPTOR;
-
-typedef struct _BTH_LE_GATT_DESCRIPTOR_VALUE {
- BTH_LE_GATT_DESCRIPTOR_TYPE DescriptorType;
- BTH_LE_UUID DescriptorUuid;
- union {
- struct {
- BOOLEAN IsReliableWriteEnabled;
- BOOLEAN IsAuxiliariesWritable;
- } CharacteristicExtendedProperties;
- struct {
- BOOLEAN IsSubscribeToNotification;
- BOOLEAN IsSubscribeToIndication;
- } ClientCharacteristicConfiguration;
- struct {
- BOOLEAN IsBroadcast;
- } ServerCharacteristicConfiguration;
- struct {
- UCHAR Format;
- UCHAR Exponent;
- BTH_LE_UUID Unit;
- UCHAR NameSpace;
- BTH_LE_UUID Description;
- } CharacteristicFormat;
- };
- ULONG DataSize;
- UCHAR Data[1];
-} BTH_LE_GATT_DESCRIPTOR_VALUE, *PBTH_LE_GATT_DESCRIPTOR_VALUE;
-
-typedef struct _BLUETOOTH_GATT_VALUE_CHANGED_EVENT {
- USHORT ChangedAttributeHandle;
- size_t CharacteristicValueDataSize;
- PBTH_LE_GATT_CHARACTERISTIC_VALUE CharacteristicValue;
-} BLUETOOTH_GATT_VALUE_CHANGED_EVENT, *PBLUETOOTH_GATT_VALUE_CHANGED_EVENT;
-
-typedef struct _BLUETOOTH_GATT_VALUE_CHANGED_EVENT_REGISTRATION {
- USHORT NumCharacteristics;
- BTH_LE_GATT_CHARACTERISTIC Characteristics[1];
-} BLUETOOTH_GATT_VALUE_CHANGED_EVENT_REGISTRATION, *PBLUETOOTH_GATT_VALUE_CHANGED_EVENT_REGISTRATION;
-
-typedef VOID (CALLBACK *PFNBLUETOOTH_GATT_EVENT_CALLBACK)(
- BTH_LE_GATT_EVENT_TYPE EventType,
- PVOID EventOutParameter,
- PVOID Context
- );
-
-typedef ULONG64 BTH_LE_GATT_RELIABLE_WRITE_CONTEXT, *PBTH_LE_GATT_RELIABLE_WRITE_CONTEXT;
-
-#define DEFINEFUNC(ret, func, ...) \
- typedef ret (WINAPI *fp_##func)(__VA_ARGS__); \
- static fp_##func func;
-
-#define RESOLVEFUNC(func) \
- func = (fp_##func)resolveFunction(library, #func); \
- if (!func) \
- return false;
-
-DEFINEFUNC(HRESULT, BluetoothGATTGetServices, HANDLE, USHORT, PBTH_LE_GATT_SERVICE, PUSHORT, ULONG)
-DEFINEFUNC(HRESULT, BluetoothGATTGetIncludedServices, HANDLE, PBTH_LE_GATT_SERVICE, USHORT, PBTH_LE_GATT_SERVICE, PUSHORT, ULONG)
-DEFINEFUNC(HRESULT, BluetoothGATTGetCharacteristics, HANDLE, PBTH_LE_GATT_SERVICE, USHORT, PBTH_LE_GATT_CHARACTERISTIC, PUSHORT, ULONG)
-DEFINEFUNC(HRESULT, BluetoothGATTGetDescriptors, HANDLE, PBTH_LE_GATT_CHARACTERISTIC, USHORT, PBTH_LE_GATT_DESCRIPTOR, PUSHORT, ULONG)
-DEFINEFUNC(HRESULT, BluetoothGATTGetCharacteristicValue, HANDLE, PBTH_LE_GATT_CHARACTERISTIC, ULONG, PBTH_LE_GATT_CHARACTERISTIC_VALUE, PUSHORT, ULONG)
-DEFINEFUNC(HRESULT, BluetoothGATTGetDescriptorValue, HANDLE, PBTH_LE_GATT_DESCRIPTOR, ULONG, PBTH_LE_GATT_DESCRIPTOR_VALUE, PUSHORT, ULONG)
-DEFINEFUNC(HRESULT, BluetoothGATTBeginReliableWrite, HANDLE, PBTH_LE_GATT_RELIABLE_WRITE_CONTEXT, ULONG)
-DEFINEFUNC(HRESULT, BluetoothGATTEndReliableWrite, HANDLE, BTH_LE_GATT_RELIABLE_WRITE_CONTEXT, ULONG)
-DEFINEFUNC(HRESULT, BluetoothGATTAbortReliableWrite, HANDLE, BTH_LE_GATT_RELIABLE_WRITE_CONTEXT, ULONG)
-DEFINEFUNC(HRESULT, BluetoothGATTSetCharacteristicValue, HANDLE, PBTH_LE_GATT_CHARACTERISTIC, PBTH_LE_GATT_CHARACTERISTIC_VALUE, BTH_LE_GATT_RELIABLE_WRITE_CONTEXT, ULONG)
-DEFINEFUNC(HRESULT, BluetoothGATTSetDescriptorValue, HANDLE, PBTH_LE_GATT_DESCRIPTOR, PBTH_LE_GATT_DESCRIPTOR_VALUE, ULONG)
-DEFINEFUNC(HRESULT, BluetoothGATTRegisterEvent, HANDLE, BTH_LE_GATT_EVENT_TYPE, PVOID, PFNBLUETOOTH_GATT_EVENT_CALLBACK, PVOID, PHANDLE, ULONG)
-DEFINEFUNC(HRESULT, BluetoothGATTUnregisterEvent, HANDLE, ULONG)
-
-static inline QFunctionPointer resolveFunction(QLibrary *library, const char *func)
-{
- QFunctionPointer symbolFunctionPointer = library->resolve(func);
- if (!symbolFunctionPointer)
- qWarning("Cannot resolve '%s' in '%s'.", func, qPrintable(library->fileName()));
- return symbolFunctionPointer;
-}
-
-static inline bool resolveFunctions(QLibrary *library)
-{
- if (!library->isLoaded()) {
- library->setFileName(QStringLiteral("bluetoothapis"));
- if (!library->load()) {
- qWarning("Unable to load '%s' library.", qPrintable(library->fileName()));
- return false;
- }
- }
-
- RESOLVEFUNC(BluetoothGATTGetServices)
- RESOLVEFUNC(BluetoothGATTGetIncludedServices)
- RESOLVEFUNC(BluetoothGATTGetCharacteristics)
- RESOLVEFUNC(BluetoothGATTGetDescriptors)
- RESOLVEFUNC(BluetoothGATTGetCharacteristicValue)
- RESOLVEFUNC(BluetoothGATTGetDescriptorValue)
- RESOLVEFUNC(BluetoothGATTBeginReliableWrite)
- RESOLVEFUNC(BluetoothGATTEndReliableWrite)
- RESOLVEFUNC(BluetoothGATTAbortReliableWrite)
- RESOLVEFUNC(BluetoothGATTSetCharacteristicValue)
- RESOLVEFUNC(BluetoothGATTSetDescriptorValue)
- RESOLVEFUNC(BluetoothGATTRegisterEvent)
- RESOLVEFUNC(BluetoothGATTUnregisterEvent)
-
- return true;
-}
-
-#endif // QWINLOWENERGYBLUETOOTH_P_H
diff --git a/src/bluetooth/windows/windows.pri b/src/bluetooth/windows/windows.pri
deleted file mode 100644
index de3d863c..00000000
--- a/src/bluetooth/windows/windows.pri
+++ /dev/null
@@ -1,2 +0,0 @@
-HEADERS += \
- windows/qwinlowenergybluetooth_p.h